Why do SpinBox and TextField look so bad on Windows?
-
I have this snippet of QML:
import QtQuick import QtQuick.Window import QtQuick.Controls 6.3 ... Item { id: date_boxes height: year_number.height width: day_label.x + day_label.width - year_number.x anchors.horizontalCenter: parent.horizontalCenter SpinBox { id: year_number width: 52 editable: true wheelEnabled: true to: 2023 from: 2019 value: manager.year anchors.left: parent.left activeFocusOnTab: true onValueChanged: manager.year = value textFromValue: function(value) { return value; } } Text { id: year_label color: pal.text text: qsTr("Year (YYYY)") anchors.verticalCenter: year_number.verticalCenter anchors.left: year_number.right font.pixelSize: 12 anchors.leftMargin: 10 } SpinBox { id: month_number width: 37 anchors.verticalCenter: year_label.verticalCenter anchors.left: year_label.right wheelEnabled: true editable: true to: 12 from: 1 value: manager.month activeFocusOnTab: true anchors.leftMargin: 20 onValueChanged: manager.month = value } Text { id: month_label color: pal.text text: qsTr("Month (MM)") anchors.verticalCenter: month_number.verticalCenter anchors.left: month_number.right font.pixelSize: 12 anchors.leftMargin: 10 } SpinBox { id: day_number width: 37 anchors.verticalCenter: month_label.verticalCenter anchors.left: month_label.right wheelEnabled: true editable: true to: (month_number.value === 4 || month_number.value === 6 || month_number.value === 9 || month_number.value === 11) ? 30 : month_number.value === 2 ? (year_number.value % 4 == 0 ? 29 : 28) : 31 from: 1 value: manager.day activeFocusOnTab: true anchors.leftMargin: 20 onValueChanged: manager.day = value } Text { id: day_label color: pal.text text: qsTr("Day (DD)") anchors.verticalCenter: day_number.verticalCenter anchors.left: day_number.right font.pixelSize: 12 anchors.leftMargin: 10 } } Text { id: title_label color: pal.text text: qsTr("Sermon Title") font.pixelSize: 12 } TextField { id: title color: pal.text anchors.left: parent.left anchors.right: parent.right font.pixelSize: 12 placeholderText: "Authority in the Church" activeFocusOnTab: true topPadding: 4 bottomPadding: 4 leftPadding: 10 rightPadding: 10 onTextChanged: manager.updateTitle(title.text) }
Here's how it looks under KDE Plasma:
And here's how it looks under Windows 10:
In Plasma it looks... well normal, but in Windows the text boxes are reduced to corners instead of full rectangles, and those corner pieces even go over the text! (Since my date boxes are rather small.)
Is this just how these particular UI elements work in Windows or is there something here I need to fix?
-
I have this snippet of QML:
import QtQuick import QtQuick.Window import QtQuick.Controls 6.3 ... Item { id: date_boxes height: year_number.height width: day_label.x + day_label.width - year_number.x anchors.horizontalCenter: parent.horizontalCenter SpinBox { id: year_number width: 52 editable: true wheelEnabled: true to: 2023 from: 2019 value: manager.year anchors.left: parent.left activeFocusOnTab: true onValueChanged: manager.year = value textFromValue: function(value) { return value; } } Text { id: year_label color: pal.text text: qsTr("Year (YYYY)") anchors.verticalCenter: year_number.verticalCenter anchors.left: year_number.right font.pixelSize: 12 anchors.leftMargin: 10 } SpinBox { id: month_number width: 37 anchors.verticalCenter: year_label.verticalCenter anchors.left: year_label.right wheelEnabled: true editable: true to: 12 from: 1 value: manager.month activeFocusOnTab: true anchors.leftMargin: 20 onValueChanged: manager.month = value } Text { id: month_label color: pal.text text: qsTr("Month (MM)") anchors.verticalCenter: month_number.verticalCenter anchors.left: month_number.right font.pixelSize: 12 anchors.leftMargin: 10 } SpinBox { id: day_number width: 37 anchors.verticalCenter: month_label.verticalCenter anchors.left: month_label.right wheelEnabled: true editable: true to: (month_number.value === 4 || month_number.value === 6 || month_number.value === 9 || month_number.value === 11) ? 30 : month_number.value === 2 ? (year_number.value % 4 == 0 ? 29 : 28) : 31 from: 1 value: manager.day activeFocusOnTab: true anchors.leftMargin: 20 onValueChanged: manager.day = value } Text { id: day_label color: pal.text text: qsTr("Day (DD)") anchors.verticalCenter: day_number.verticalCenter anchors.left: day_number.right font.pixelSize: 12 anchors.leftMargin: 10 } } Text { id: title_label color: pal.text text: qsTr("Sermon Title") font.pixelSize: 12 } TextField { id: title color: pal.text anchors.left: parent.left anchors.right: parent.right font.pixelSize: 12 placeholderText: "Authority in the Church" activeFocusOnTab: true topPadding: 4 bottomPadding: 4 leftPadding: 10 rightPadding: 10 onTextChanged: manager.updateTitle(title.text) }
Here's how it looks under KDE Plasma:
And here's how it looks under Windows 10:
In Plasma it looks... well normal, but in Windows the text boxes are reduced to corners instead of full rectangles, and those corner pieces even go over the text! (Since my date boxes are rather small.)
Is this just how these particular UI elements work in Windows or is there something here I need to fix?
@Magicrafter13 this won't fix all your problems, but...I recreated your QML code using layouts (I had to remove a few references to objects that you didn't include.) Look this over:
import QtQuick import QtQuick.Controls import QtQuick.Layouts ApplicationWindow { id: mainWindow visible: true width: 640 height: 480 ColumnLayout { height: mainWindow.height width: mainWindow.width RowLayout { id: date_boxes height: year_number.height Layout.fillWidth: true SpinBox { id: year_number editable: true wheelEnabled: true to: 2023 from: 2019 activeFocusOnTab: true textFromValue: function(value) { return value; } } Text { id: year_label text: qsTr("Year (YYYY)") font.pixelSize: 12 anchors.leftMargin: 10 } SpinBox { id: month_number wheelEnabled: true editable: true to: 12 from: 1 activeFocusOnTab: true anchors.leftMargin: 20 } Text { id: month_label text: qsTr("Month (MM)") font.pixelSize: 12 } SpinBox { id: day_number wheelEnabled: true editable: true to: (month_number.value === 4 || month_number.value === 6 || month_number.value === 9 || month_number.value === 11) ? 30 : month_number.value === 2 ? (year_number.value % 4 == 0 ? 29 : 28) : 31 from: 1 activeFocusOnTab: true } Text { id: day_label text: qsTr("Day (DD)") font.pixelSize: 12 } } Text { id: title_label text: qsTr("Sermon Title") font.pixelSize: 12 } TextField { id: title Layout.fillWidth: true Layout.fillHeight: true font.pixelSize: 12 placeholderText: "Authority in the Church" activeFocusOnTab: true topPadding: 4 bottomPadding: 4 leftPadding: 10 rightPadding: 10 } } }
Another part of the problem might be the style you're using. The default Windows style isn't all that great, on a number of fronts. You can change it to plasma if you want, with the QQuickStyle::setStyle() function in your main.cpp.
-
@Magicrafter13 this won't fix all your problems, but...I recreated your QML code using layouts (I had to remove a few references to objects that you didn't include.) Look this over:
import QtQuick import QtQuick.Controls import QtQuick.Layouts ApplicationWindow { id: mainWindow visible: true width: 640 height: 480 ColumnLayout { height: mainWindow.height width: mainWindow.width RowLayout { id: date_boxes height: year_number.height Layout.fillWidth: true SpinBox { id: year_number editable: true wheelEnabled: true to: 2023 from: 2019 activeFocusOnTab: true textFromValue: function(value) { return value; } } Text { id: year_label text: qsTr("Year (YYYY)") font.pixelSize: 12 anchors.leftMargin: 10 } SpinBox { id: month_number wheelEnabled: true editable: true to: 12 from: 1 activeFocusOnTab: true anchors.leftMargin: 20 } Text { id: month_label text: qsTr("Month (MM)") font.pixelSize: 12 } SpinBox { id: day_number wheelEnabled: true editable: true to: (month_number.value === 4 || month_number.value === 6 || month_number.value === 9 || month_number.value === 11) ? 30 : month_number.value === 2 ? (year_number.value % 4 == 0 ? 29 : 28) : 31 from: 1 activeFocusOnTab: true } Text { id: day_label text: qsTr("Day (DD)") font.pixelSize: 12 } } Text { id: title_label text: qsTr("Sermon Title") font.pixelSize: 12 } TextField { id: title Layout.fillWidth: true Layout.fillHeight: true font.pixelSize: 12 placeholderText: "Authority in the Church" activeFocusOnTab: true topPadding: 4 bottomPadding: 4 leftPadding: 10 rightPadding: 10 } } }
Another part of the problem might be the style you're using. The default Windows style isn't all that great, on a number of fronts. You can change it to plasma if you want, with the QQuickStyle::setStyle() function in your main.cpp.
@mzimmers I added 2 (3) lines to main (I'm doing this in Python not C++):
if __name__ == "__main__": # Set the application style to KDE Plasma settings = QSettings("org/kde/desktop", "applications") settings.setValue("style", "org.kde.desktop") app = QApplication(sys.argv) manager = Manager() engine = QQmlApplicationEngine() engine.rootContext().setContextProperty("manager", manager) qml_file = str(Path(__file__).resolve().parent / "main.qml") engine.load(qml_file) if not engine.rootObjects(): sys.exit(-1) # ... # Start program sys.exit(app.exec())
However this did not change the styling at all. I did discover the
-style
command line option, but on Windows there were only 3 style available. Fusion actually looks pretty nice and fixes all my issues, however it doesn't respect the system dark/light mode setting and is always dark (which to be fair looks superior but it would be nice if it matched the system colors).Do I have to install some package to get additional styles?
Actually right before submitting this reply I realized Fusion is KDE Plasma because I tried it on my Linux install.
So now there are only really 3 issues:
- Fusion on Windows and macOS forces dark theme
- Fusion on Windows and macOS makes the radio buttons blue for some reason (looks strange but not a deal breaker, I can live with this)
- How can I make it always use this theme, when creating a package with pyinstaller
I kinda have a solution to my last problem there, I can just hard code the QApplication call to use ["-style", "Fusion"] instead of sys.argv, since there doesn't seem to be a way to build it into the PyInstaller build, even if this solution seems a little cursed haha.
Either way, thanks for pointing me in the direction of the application Styling.
-
@mzimmers I added 2 (3) lines to main (I'm doing this in Python not C++):
if __name__ == "__main__": # Set the application style to KDE Plasma settings = QSettings("org/kde/desktop", "applications") settings.setValue("style", "org.kde.desktop") app = QApplication(sys.argv) manager = Manager() engine = QQmlApplicationEngine() engine.rootContext().setContextProperty("manager", manager) qml_file = str(Path(__file__).resolve().parent / "main.qml") engine.load(qml_file) if not engine.rootObjects(): sys.exit(-1) # ... # Start program sys.exit(app.exec())
However this did not change the styling at all. I did discover the
-style
command line option, but on Windows there were only 3 style available. Fusion actually looks pretty nice and fixes all my issues, however it doesn't respect the system dark/light mode setting and is always dark (which to be fair looks superior but it would be nice if it matched the system colors).Do I have to install some package to get additional styles?
Actually right before submitting this reply I realized Fusion is KDE Plasma because I tried it on my Linux install.
So now there are only really 3 issues:
- Fusion on Windows and macOS forces dark theme
- Fusion on Windows and macOS makes the radio buttons blue for some reason (looks strange but not a deal breaker, I can live with this)
- How can I make it always use this theme, when creating a package with pyinstaller
I kinda have a solution to my last problem there, I can just hard code the QApplication call to use ["-style", "Fusion"] instead of sys.argv, since there doesn't seem to be a way to build it into the PyInstaller build, even if this solution seems a little cursed haha.
Either way, thanks for pointing me in the direction of the application Styling.
@Magicrafter13 said in Why do SpinBox and TextField look so bad on Windows?:
Do I have to install some package to get additional styles?
You shouldn't (I'm fairly sure I didn't), but in your QML you may need to import the controls for the style you selected:
import qtQuick.Controls.Material // or whatever
Also, take a look at this bug report
If you're on a relatively new release of Qt, this should solve your light/dark issue.
-