pythonpyqtqstylesheet

PyQt: How can i set stylesheet contents on scaled mode?


I had an application that contained a lot of widgets with stylesheet on them, However, I did not add any layout to interface, It neither had central widget included, But the application was running without any problems.

However, whenever i tried to resize the application (scaling it down) the widgets would not scale, of course.

I had an little research (Because i could not find anything else related to my problem) and i found this on Qt Documentation, stylesheet reference:

"The actual image that is drawn is determined using the same algorithm as QIcon (i.e) the image is never scaled up but always scaled down if necessary."

How can i make stylesheet scale down with window? (If stylesheet has background image on)


For example i have button with stylesheet:

btn = QtGui.QPushButton(self)
btn.move(0, 0)
btn.setObjectName('btn)
btn.setStyleSheet("#btn {background-image: url(':/images/somepicture.png'); border: none; }")

How can i make this button scale down with window, Can i achieve this without layouts? If not how can i do it with layouts? (without it limiting too much)


Solution

  • If you add the button as the central widget to a QMainWindow it should automatically adjust it's size to fit the available space. However, to get the button image to scale, you need to set the image as a border-image stylesheet property (a little strange). A working example for PyQt4:

    from PyQt4 import QtGui, QtCore
    
    class MainWindow(QtGui.QMainWindow):
    
        def __init__(self, *args, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
    
            btn = QtGui.QPushButton(self)
            btn.setStyleSheet("border-image: url('somepicture.png');")  # Scaled
            #btn.setStyleSheet("background-image: url('somepicture.png');")  # Not scaled
    
            self.setCentralWidget(btn)
    
            self.show()
    
    app = QtGui.QApplication([])
    window = MainWindow()
    
    app.exec_()
    

    Note that you don't need to set an id (objectName) to assign the CSS to a specific widget, you can simply pass in the CSS rule via .setStyleSheet().

    You cannot set a layout on QMainWindow as it already has a complex layout system to accommodate docking widgets and toolbars. Therefore, if you want to use a layout to add more than one widget to the window, you need to use a container widget to hold it. The following working example demonstrates this:

    from PyQt4 import QtGui, QtCore
    
    class MainWindow(QtGui.QMainWindow):
    
        def __init__(self, *args, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
    
            w = QtGui.QWidget() # container widget
            l = QtGui.QVBoxLayout() # your layout
            w.setLayout(l) # set the layout on your container widget
    
            btn = QtGui.QPushButton(self)
            btn.setStyleSheet("border-image: url('somepicture.png');")      
    
            label = QtGui.QLabel('Hello!')
    
            l.addWidget(btn) # add your widget to the layout
            l.addWidget(label) # add the label to the layout
    
            self.setCentralWidget(w) # add the container widget to the QMainWindow        
    
            self.show()
    
    app = QtGui.QApplication([])
    window = MainWindow()
    
    app.exec_()
    

    If you want to be able to position widgets absolutely, rather than adding them to a layout (which will control their size/position) you can pass the parent element (relative to which x,y coords are taken) when creating it:

    from PyQt4 import QtGui, QtCore
    
    class MainWindow(QtGui.QMainWindow):
    
        def __init__(self, *args, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
    
            w = QtGui.QWidget() # container widget
    
            btn = QtGui.QPushButton(w)
            btn.move(100,100)
            btn.setStyleSheet("border-image: url('somepicture.png');")      
    
            self.setCentralWidget(w) # add the container widget to the QMainWindow        
            self.show()
    
    app = QtGui.QApplication([])
    window = MainWindow()
    
    app.exec_()
    

    But positioning a widget absolutely like this loses you the ability to auto-scale it to fit the parent widget. If you just want some padding/spacing around the element in the window, take a look at .setContentsMargins on the QLayouts, e.g. l.setContentsMargins(50,50,50,50) will put a 50px margin around the button.