Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Not able to overload paintEvent() for QMainWindow to display SVG as backround, despite being able to do so for QWidget



  • I'm trying to set an SVG as the background for my QMainWindow based application. Previously I was using QWidget for my application, but I switched over to QMainWindow because I needed a status bar. I was able to set an SVG as a background when I was using QWidget by overloading paintEvent(). However, I'm not able to use the same approach for QMainWindow. What gives? I've created an example for both a QMainWindow and QWidget based application below.

    from PySide2 import QtCore, QtGui, QtWidgets
    
    class Ui_Form(object):
        def setupUi(self, Form):
            Form.setObjectName("Form")
            Form.resize(400, 300)
            contents = b"<svg width='44' height='12' viewBox='0 0 44 12' xmlns='http://www.w3.org/2000/svg'><path d='M20 12v-2L0 0v10l4 2h16zm18 0l4-2V0L22 10v2h16zM20 0v8L4 0h16zm18 0L22 8V0h16z' fill='#2c2c2c' fill-opacity='0.4' fill-rule='evenodd'/></svg>"
            file = QtCore.QTemporaryFile(Form)
            if file.open():
                file.write(contents)
                file.flush()
                Form.setStyleSheet("""CustomWidget#Form{background-color: #000000;
                                      background-image: url(%s);}""" % file.fileName())
            self.retranslateUi(Form)
            QtCore.QMetaObject.connectSlotsByName(Form)
    
        def retranslateUi(self, Form):
            Form.setWindowTitle(QtWidgets.QApplication.translate("Form", "Form", None, -1))
    
    
    class CustomWidget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(CustomWidget, self).__init__(parent)
    
        def paintEvent(self, event):
    
            opt = QtWidgets.QStyleOption()
            opt.init(self)
            painter = QtGui.QPainter(self)
            self.style().drawPrimitive(QtWidgets.QStyle.PE_Widget, opt, painter, self)
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        Form = CustomWidget()
        ui = Ui_Form()
        ui.setupUi(Form)
        Form.show()
        sys.exit(app.exec_())
    
    from PySide2 import QtCore, QtGui, QtWidgets
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(800, 600)
    
            contents = b"<svg width='44' height='12' viewBox='0 0 44 12' xmlns='http://www.w3.org/2000/svg'><path d='M20 12v-2L0 0v10l4 2h16zm18 0l4-2V0L22 10v2h16zM20 0v8L4 0h16zm18 0L22 8V0h16z' fill='#2c2c2c' fill-opacity='0.4' fill-rule='evenodd'/></svg>"
            file = QtCore.QTemporaryFile(MainWindow)
            if file.open():
                file.write(contents)
                file.flush()
                MainWindow.setStyleSheet("""CustomWidget#Form{background-color: #000000;
                                      background-image: url(%s);}""" % file.fileName())
    
            self.menubar = QtWidgets.QMenuBar(MainWindow)
            self.menubar.setObjectName("menubar")
            MainWindow.setMenuBar(self.menubar)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            MainWindow.setCentralWidget(self.centralwidget)
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
    
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "MainWindow", None, -1))
    
    
    class CustomWidget(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(CustomWidget, self).__init__(parent)
    
        def paintEvent(self, event):
    
            opt = QtWidgets.QStyleOption()
            opt.init(self)
            painter = QtGui.QPainter(self)
            self.style().drawPrimitive(QtWidgets.QStyle.PE_Widget, opt, painter, self)
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = CustomWidget()
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())
    

    alt text

    alt text


  • Lifetime Qt Champion

    Hi
    Didn't read the code.
    Just wanted to ask.
    You are aware of centralWidget() for main window.
    Unless you set SVG to that, it will be hidden.



  • I tried overloading paintEvent() for the centralwidget() as well, however the SVG still isn't displayed as the background. Here is the code for that attempt:

    from PySide2 import QtCore, QtGui, QtWidgets
    
    
    class CustomWidget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(CustomWidget, self).__init__(parent)
    
        def paintEvent(self, event):
    
            opt = QtWidgets.QStyleOption()
            opt.init(self)
            painter = QtGui.QPainter(self)
            self.style().drawPrimitive(QtWidgets.QStyle.PE_Widget, opt, painter, self)
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(800, 600)
    
    
    
            self.menubar = QtWidgets.QMenuBar(MainWindow)
            self.menubar.setObjectName("menubar")
            MainWindow.setMenuBar(self.menubar)
         
            self.centralwidget = CustomWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            MainWindow.setCentralWidget(self.centralwidget)
            contents = b"<svg width='44' height='12' viewBox='0 0 44 12' xmlns='http://www.w3.org/2000/svg'><path d='M20 12v-2L0 0v10l4 2h16zm18 0l4-2V0L22 10v2h16zM20 0v8L4 0h16zm18 0L22 8V0h16z' fill='#2c2c2c' fill-opacity='0.4' fill-rule='evenodd'/></svg>"
            file = QtCore.QTemporaryFile(self.centralwidget)
            if file.open():
                file.write(contents)
                file.flush()
                self.centralwidget.setStyleSheet("""CustomWidget#Form{background-color: #000000;
                                      background-image: url(%s);}""" % file.fileName())
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
    
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "MainWindow", None, -1))
    
    
    
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = QtWidgets.QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())
    

  • Lifetime Qt Champion

    Hi,

    Why are you doing a custom paint event if you are going to set a background image by stylesheet ?



  • @SGaist
    Thanks for responding.

    I initially tried the approach of not overriding paintEvent and using a temporary file to store the svg for the backround-image attribute of the stylesheet. However, I still couldn't get the SVG to display. This post on stackoverflow seems to indicate Pyside2(which I'm using) is a special case that requires the overloading of PaintEvent to display the SVG. This solution worked for QWidget(as shown above) but not for QMainWindow which is weirdly inconsistent. Any idea?


  • Lifetime Qt Champion

    QMainWindow does a lot of stuff to handle everything it does, therefore depending on what you want to do with it, you should rather customise its central widget.


Log in to reply