Issue
I am trying to build an app using PyQt, so I decided to first develop the UI using qt Designer. I want to style my elements, so I am using stylesheets to specify the styles I need. After making the UI in qt Designer, I used the preview button to see if everything works, and everything was working as expected. Then, I used pyuic5 to convert the UI file to the python version. Now, almost everything is OK, but SOME stylesheets do not work properly. For example, I used stylesheet for QComboBox, and everything works but QComboBox QAbstractItemView part of the stylesheet. What is happening? Half of the code works and the other half does not. Here is the stylesheet if you need:
QComboBox{
color: #F5F3F4;
border: 2px solid #E5383B;
border-radius: 15px;
background-color: #BA181B;
padding: 2px;
padding-left: 5px;
}
QComboBox::drop-down {
border: 0px;
width: 0px;
}
QComboBox QAbstractItemView {
border: 2px solid #E5383B;
selection-background-color: #A4161A;
color: #F5F3F4;
background-color: #BA181B;
border-radius: 5px;
}
Only the last part does not work in python app, but it works perfectly in the qt Designer preview mode.
Edit:
What I intend to do (and qt Designer also shows)
What Python outputs
What app.setStyle("fusion") does (when the combo box is open)
Contents of the .ui file:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QComboBox" name="comboBox">
<property name="geometry">
<rect>
<x>160</x>
<y>140</y>
<width>69</width>
<height>22</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QComboBox{
color: #F5F3F4;
border: 2px solid #E5383B;
border-radius: 15px;
background-color: #BA181B;
padding: 2px;
padding-left: 5px;
}
QComboBox::drop-down {
border: 0px;
width: 0px;
}
QComboBox QAbstractItemView {
border: 2px solid #E5383B;
selection-background-color: #A4161A;
color: #F5F3F4;
background-color: #BA181B;
border-radius: 5px;
}</string>
</property>
<item>
<property name="text">
<string>New Item</string>
</property>
</item>
<item>
<property name="text">
<string>New Item 2</string>
</property>
</item>
</widget>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
then, I convert the .ui file to its .py version with
pyuic5 ui.py ui.ui
python file:
from ui import UI
from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow, qApp, QDockWidget, QFileDialog
from PyQt5 import QtWidgets, QtGui
import sys
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.ui = UI()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
app.setStyle("fusion")
app.setWindowIcon(QtGui.QIcon('gallery/icon.jpg'))
window = MainWindow()
window.show()
sys.exit(app.exec_())
Solution
There are some issues related to propagation of stylesheets, especially for complex widgets that use scroll areas (or inherit from them).
Unfortunately, due to the complexity of style propagation and stylesheet management, it's really hard to track down the exact source of the problem, and some number of Qt bug reports exist about this matter.
First of all, it's better to have a single and centralized stylesheet: whenever you have to modify a single property that might be shared among lots of widgets, you don't have to modify the stylesheet of every widget. The drawback is that if you have many different styled widgets of the same class type, you need to better use selectors (the #
selector is the best choice, as it uses the object name of the widget to identify it, and object names are usually unique); read more about Qt stylesheet selectors.
If your program has only a single main window (and everything else is a child of it, including dialogs), you can set the stylesheet on that window, otherwise it's better to set the stylesheet on the QApplication instead.
Then, whenever those issues occur, a possible solution is to set again the stylesheet as soon as the widget is shown. For simple cases, you can try the following:
class MainWindow(QMainWindow):
shown = False
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.ui = UI()
self.ui.setupUi(self)
def showEvent(self, event):
super().showEvent(event)
if not self.shown:
self.shown = True
self.ui.setStyleSheet(self.ui.styleSheet())
Unlike other properties for which Qt ignores the new value if it's identical to the current, every call to setStyleSheet()
causes the whole widget (and its children) to repolish them, even if the style sheet is empty.
Finally, it's better to avoid stylesheets that are too generic, as they might cause unexpected behavior (I know it's not your case, but it's an important aspect that should always be kept in mind).
So, the following should be avoided or, at least, used with care:
setStyleSheet('color: somecolor; border: someborder')
setStyleSheet('QWidget { color: somecolor; border: someborder; }')
setStyleSheet('* { color: somecolor; border: someborder; }')
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.