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

How to cater for Windows user text size in PyQt5?



  • In the example code that I've pasted below, I've got a small PyQt5 window with a menu bar, status bar, and a couple of widgets in the centre.

    On a Windows setup with the DPI setting set at 100% and text size (Settings -> Ease of access -> 'Make text bigger') set 100, all is well, and looks like this:

    Sample window at 100%

    And if the user DPI setting gets changed, for example to 150%, then Qt compenates for it and it continues to look absolutely fine:

    Sample window at 100%

    However, if the user keeps their DPI setting at 100% but increases the text size setting under Ease Of Access -> Make text bigger, for example to 200, then things go wrong and it looks like this:

    Sample image at 100%, text size at 200

    For people who need large text because of vision issues, it's correct that the window title, menu bar and status bar have all scaled up. But it's wrong that the QLabel and the QButton text have not scaled up (even after a Windows restart). They should have scaled up.

    What's the correct way, please, to make a Windows PyQt5 application scale everything up if the user has chosen a text size larger than 100?

    Searching online I found a bunch of examples referring to DPI (125%/150%/175%) etc., but this isn't a DPI issue, it's an ease of access text size issue. There were also references to ignoring the DPI setting, but that's not an adequate solution as it doesn't solve the problem for the application users who need large text.

    Is there a proper and accurate way to make a whole application (multi-dialog) scale up correctly just by setting something at the QApplication level maybe?

    Sample code:

    from PyQt5 import QtCore
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtWidgets import QGridLayout, QLabel, QMainWindow, QPushButton, QFrame
    import sys
    
    
    class TestDialog(QMainWindow):
        def __init__(self, parent, windowTitle):
            super().__init__(parent)
            self.setWindowTitle(windowTitle)
            self.setWindowFlags(QtCore.Qt.Window |
                                QtCore.Qt.WindowTitleHint |
                                QtCore.Qt.WindowCloseButtonHint |
                                QtCore.Qt.WindowStaysOnTopHint)
            self.name = windowTitle
            self.parent_window = parent
    
            menu = self.menuBar()
            menu.addAction("One")
            menu.addAction("Two")
            menu.addAction("Three")
    
            screen = QApplication.screens()[0]
            dpiScaling = screen.logicalDotsPerInch()
    
            self.frame = QFrame()
            self.grid = QGridLayout()
            self.frame.setLayout(self.grid)
            self.setCentralWidget(self.frame)
            self.scalingLabel = QLabel("DPI scaling: " + str(dpiScaling))
            self.grid.addWidget(self.scalingLabel, 0, 0)
            self.uselessButton = QPushButton("Button in the main area")
            self.grid.addWidget(self.uselessButton, 1, 0)
    
            self.statusBar().addWidget(QLabel("Text on the status bar"))
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        app.setStyleSheet("Fusion")
        windowTitle = "Scaling test"
        testDialog = TestDialog(None, windowTitle)
        testDialog.show()
        sys.exit(app.exec_())
    
    

  • Lifetime Qt Champion

    Hi,

    Sorry I can't answer that right away but you should give more information about your software stack and OS version so people can try to reproduce your issue.



  • Sure, no problem. Python 3.7, Qt / PyQt 5.14.2, Windows 10 version 1909. What other info would be helpful?


  • Lifetime Qt Champion

    How you installed it can also be useful (conda VS pip VS ?)



  • I'm working in PyCharm 2019.12, which handles the installation of libraries from requirements.txt using (I think) pip.

    I'm using PyInstaller to create executable files of the application to test on other machines, but get the same results when running directly in the PyCharm virtual environment too.


  • Lifetime Qt Champion

    Can you check if you have the same issue with PySide2 ?



  • I can do that, but I've not used PySide2 at all so far so it might take me a little time. I'll get back to you.



  • OK, that didn't take anywhere near as long as I expected.

    PySide2 appears to have the same problem- the text of items in the main window doesn't scale for the environment settings. Strangely, in PySide2 the status bar label at the bottom doesn't scale either, while in PyQt5, the status bar label did scale for text size.

    So my question still remains- how am I meant to get my application to scale all the text to suit the user's accessibility settings, instead of just some of it? Are there changes or additions I can make to my code to make this work as expected on Windows, without affecting Mac users etc.?

    The result I got from PySide2 was:

    Test window screengrab with inconsistent font sizes

    The 'correct' expected result would be that all the text would be large, the same size as the "One Two Three" on the menu bar, as this is what the Windows "make text bigger" settings ought to do- but Qt appears to only partially implement this?

    The source code is exactly the same as before, but with the imports changed from PyQt5 to PySide2:

    from PySide2 import QtCore
    from PySide2.QtWidgets import QApplication
    from PySide2.QtWidgets import QGridLayout, QLabel, QMainWindow, QPushButton, QFrame
    import sys
    
    
    class TestDialog(QMainWindow):
        def __init__(self, parent, windowTitle):
            super().__init__(parent)
            self.setWindowTitle(windowTitle)
            self.setWindowFlags(QtCore.Qt.Window |
                                QtCore.Qt.WindowTitleHint |
                                QtCore.Qt.WindowCloseButtonHint |
                                QtCore.Qt.WindowStaysOnTopHint)
            self.name = windowTitle
            self.parent_window = parent
    
            menu = self.menuBar()
            menu.addAction("One")
            menu.addAction("Two")
            menu.addAction("Three")
    
            screen = QApplication.screens()[0]
            dpiScaling = screen.logicalDotsPerInch()
    
            self.frame = QFrame()
            self.grid = QGridLayout()
            self.frame.setLayout(self.grid)
            self.setCentralWidget(self.frame)
            self.scalingLabel = QLabel("DPI scaling: " + str(dpiScaling))
            self.grid.addWidget(self.scalingLabel, 0, 0)
            self.uselessButton = QPushButton("Button in the main area")
            self.grid.addWidget(self.uselessButton, 1, 0)
    
            self.statusBar().addWidget(QLabel("Text on the status bar"))
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        app.setStyleSheet("Fusion")
        windowTitle = "Scaling test"
        testDialog = TestDialog(None, windowTitle)
        testDialog.show()
        sys.exit(app.exec_())
    
    


  • Just to add, the above test was on PySide2 5.15.0. I've also just tested it with PyQt5 5.15.0 with the same results.


  • Lifetime Qt Champion

    Then I would say you found a bug. You should check the bug report system to see if it's something known. If not please create a new report providing your examples and the results you obtained.



  • Thanks for the response. As you suggested, I have posted this as a potential bug, now visible at https://bugreports.qt.io/browse/QTBUG-85491

    As far as I'm aware there's nothing that I could add to my code to compensate for this in the meantime? I can't see a Qt method or function that makes the Windows text size setting accessible so that it could be compensated for manually.


Log in to reply