如何为Matplotlib小部件(导航栏/画布)设置PyQT4样式表?

3
我有一个QMainWindow应用程序,包括菜单栏、中心小部件中的分割器和状态栏。在分割器的左侧是一个小部件,其中包含一些控件(列表、组合框和按钮),右侧是一个小部件,其中包含Matplotlib画布和NavigationToolBar的布局。
我能够使用QT样式表设置所有内容的各种背景颜色...除了Matplotlib侧。我尝试使用以下代码,但没有效果。我还尝试直接设置NavBar和Canvas样式表...但仍然没有效果:
self.mplFig.setStyleSheet(".QWidget {background-color:   #0ff}")

基本上我正在尝试将NavToolbar的背景颜色以及画布周围的边框与其他所有内容匹配(目前为青色,以便易于显示)...任何帮助都将不胜感激。完整代码和示例图像如下:

import sys
from PyQt4 import QtGui, QtCore
import matplotlib
matplotlib.use("qt4agg")
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure

class testGUI(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(testGUI, self).__init__(parent)
        self.buildLayout()
        self.buildMenus()        
        self.menuBar()
        self.statusBar()

        ## Style Sheets
        self.splitter.setStyleSheet("QSplitter::handle:horizontal {background-color:   #ccc}")            
        self.controlWidget.setStyleSheet(".QWidget {background-color:   #0ff}")  
        menuStyle = """.QMenuBar {background-color:   #0ff}
            QMenuBar::item {background: transparent} 
            QMenuBar::item:selected {background: #8ff}"""
        self.statusBar().setStyleSheet(".QStatusBar {background-color:   #0ff}")
        self.menuBar().setStyleSheet(menuStyle)
        # .....THIS DOESN"T WORK !! .....
        self.mplFig.setStyleSheet(".QWidget {background-color:   #0ff}")


    def buildLayout(self):
        self.controlWidget = QtGui.QWidget(self) 
        self.plotList  = QtGui.QListWidget(self)
        self.combo  = QtGui.QComboBox(self)
        self.button = QtGui.QPushButton('Plot')        
        self.combo.addItems(\['1','2','3','4'\]) 
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.plotList)
        layout.addWidget(self.combo)
        layout.addWidget(self.button)
        self.controlWidget.setLayout(layout)
        self.mplFig  = MplGrapher()
        self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
        self.splitter.addWidget(self.controlWidget) 
        self.splitter.addWidget(self.mplFig) 
        self.setCentralWidget(self.splitter)
        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Plastique'))
    def buildMenus(self):
        openFile = QtGui.QAction('Open', self)
        self.fileMenu = self.menuBar().addMenu('&File')
        self.fileMenu.addAction(openFile)

class MplGrapher(QtGui.QWidget):
    def __init__(self,parent=None):
        super(MplGrapher, self).__init__(parent)
        self.initFigure()

    def initFigure(self):   
        self.figure = Figure()        
        self.canvas = FigureCanvas(self.figure)
        self.navbar = NavigationToolbar(self.canvas, self) 
        self.figure.add_subplot(1,1,1)
        self.layout = QtGui.QVBoxLayout()
        self.layout.addWidget(self.navbar)
        self.layout.addWidget(self.canvas)
        self.setLayout(self.layout)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = testGUI()
    main.show()
    sys.exit(app.exec_())

Sample GUI


很抱歉,我目前没有答案。我之前也在这里发布过一个类似问题的帖子(想在嵌入的mpl图形周围绘制边框),是关于Qt的。我认为问题在于Qt如何解释FigureCanvas对象 - 也就是说,当您定义qss字符串以告诉Qt如何对它们进行样式化时,您需要首先告诉Qt您正在添加样式选项的小部件类型。我猜测Qt没有将FigureCanvas解释为您正在添加样式字符串的相同小部件。 - Maxwell Grady
我目前正在尝试使用一些最小化的GUI,以找到一种方法来查看PyQt如何解释FigureCanvas对象。您可以使用addWidget()将FigureCanvas对象添加到boxLayout中,因此它正确地将FigureCanvas解释为Widget。弄清楚小部件类型可能会有所帮助。另一种选择是FigureCanvas对象没有支持样式表字符串。 - Maxwell Grady
同时 - 我在QSS样式指南中找到了这个链接:样式指南。它明确提到QWidget仅支持一组最小的QSS属性,即“background、background-clip和background-origin” - 因此,如果Qt将FigureCanvas解释为通用的QWidget,则设置background-color将没有任何效果。 - Maxwell Grady
我现在不在电脑旁进行检查。但是我相信在我的某个测试中,我在样式表定义中删除了QWidget前面的点,导致Gui中的每个小部件都被设置了...甚至包括按钮和列表背景等。因此,它至少在某种程度上被识别为QWidget。稍后我会尽可能提供一个示例更新这个问题。 - Aero Engy
1
这是我的GUI的链接图片;我使用QDarkStyle(一个外部库)并通过app.setStyleSheet(qdarkstyle.load_stylesheet(pyside=False))在我的主方法中设置整个应用程序的样式表。因此,主文件中QDarkStyle的一些QSS可能具有使背景变暗的正确属性,从而影响导航栏。我能够通过将画布放入HBoxLayout中,然后将HBox放入GroupBox中,并使用border属性为GroupBox添加样式表来设置Canvas周围的边框。 - Maxwell Grady
我认为这让我走上了正确的道路。我将类MplGrapher从QtGui.QWidget更改为QtGui.QGroupBox。然后我从QWidget前面删除了点,成功了!...我想 - Aero Engy
1个回答

1
我认为我可能有一个解决方案,这要归功于Maxwell Grady的一些提示。
我更改了以下2行:
self.mplFig.setStyleSheet("QWidget {background-color:   #0ff}")

请注意 QWidget 前缺少 "."。
class MplGrapher(QtGui.QGroupBox):

更改后的GUI图片。现在我可以设置一些样式属性了...是时候让它变得不那么丑陋了。

Sample with colored in borders.


我很高兴发现这个解决方法,但我无法避免感觉这似乎是一个愚蠢的解决方案。考虑到Qt是一个C++框架,我们很幸运能够如此紧密地与Matplotlib合作,这或许是一个小代价。很高兴看起来它正在工作。 - Maxwell Grady
再次感谢。这似乎是一个bug。我不知道为什么当我的MplGrapher是QWidget类时它忽略了样式表...但是QGroupBox可以工作,即使它是widget的子类。无论如何,我尝试了你提到的QDarkStyle,我很喜欢它。所以现在我正在寻找不同的Matlplotlib样式来匹配。 - Aero Engy
mpl即将进行大修。mpl 2.0基本上将拥有与当前版本(1.4是吗?)完全相同的 mpl 功能,但他们正在添加一种非常简单的设置新样式的方式 - 并且将会有大量内置的预定义样式可供选择。它将变得非常简单,只需要输入import matplotlib.pyplot as plt; plt.style.use('ggplot'),这会看起来像 R 语言中的 ggplot 包,或者 plt.style.use('fivethirtyeight'),这会使您的图表看起来像著名的538政治博客中的图表......等等 - Maxwell Grady

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接