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

Design of window with PyQt 5



  • Hello dear users iam using PyQt5 and i noticed all my programs looks old. They have old looking design like this

    c83ac3e8-cffb-4fa3-9f52-7568f64df0a5-image.png

    But how to make mine programs looks like this one

    pyqt-download-progress-bar-tutorial.png

    Thank you a lot for your help !


  • Lifetime Qt Champion

    Hi,

    What version of PyQt5 are you using ?
    What version of Windows are you running ?
    How are you starting your application ?
    Can you share a minimal reproducible example that shows this ?



  • class Window(QMainWindow):

    def init(self):
    super().init()

       self.setGeometry(300, 300, 400, 500)
       self.setWindowTitle("Please login")
    

    this is how i start program.
    iam using windows 10 and PyQt5 5.14.12


  • Lifetime Qt Champion

    Hi,

    No this is not. This is just a class declaration.
    It would be best to provide all the code that allows to start you application properly.



  • Like this iam sorry

    from PyQt5 import QtWidgets
    from PyQt5.QtWidgets import QMainWindow
    import sys
    from PyQt5.QtWidgets import QApplication

    class Window(QMainWindow):

    def __init__(self):
        super().__init__()
    
        self.name = ""
        self.password = ""
    
        self.setGeometry(300, 300, 400, 500)
        self.setWindowTitle("Hello")
    
        self.b1 = QtWidgets.QPushButton(self)
        self.b1.setText("Button")
        self.b1.move(120, 155)
        self.b1.resize(170, 32)
        self.show()
    

    if name == "main":
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec())



  • Don`t do these setGeometry!

    class Window(QMainWindow):
        
        def __init__(self, parent=None):
            super(Window, self).__init__(parent)
            self.setWindowTitle("Please login")
    
    if __name__ == "__main__":
        ...
        app_window = Window()
        app_window.show()
        desktop = QtWidgets.QApplication.desktop()
        resolution = desktop.availableGeometry()
        app_window.setFixedWidth(resolution.width() / 2)
        app_window.setFixedHeight(resolution.height() / 2)
        app_window.move(resolution.center() - app_window.rect().center())
        sys.exit(app.exec_())
    


  • Or if want to save stretch:

    class Window(QMainWindow):
    
        def __init__(self, parent=None):
            super(Window, self).__init__(parent)
            self.setWindowTitle("Please login")
            self.setMinimumWidth(resolution.width() / 2)
            self.setMinimumHeight(resolution.height() / 2)
            ...
    
    
    if __name__ == "__main__":
        ...
        app = QtWidgets.QApplication(sys.argv)
        desktop = QtWidgets.QApplication.desktop()
        resolution = desktop.availableGeometry()
        app_window = Window()
        app_window.show()
        app_window.move(resolution.center() - app_window.rect().center())
        sys.exit(app.exec_())
    

    And button to the layout )



  • @Volodymyr14 Thank you for tip !!!



  • @Samuel-Bachorik no problem. The second variant is better because the screens are different and the size will be from minimum signed to a resolution of the screen. Really, in applications, it is not a good idea to use fixed sizes, set geometry, fixed resize and move. No fixed integers with sizes, just relative values. For example, to the fixed size put the size of sceen or widget divided on 2.



  • @Samuel-Bachorik
    All this self.b1.move(120, 155)-type stuff is possible but is usually not the right way to go about things. You would normally create QLayouts on your widgets --- if you are really using a QMainWindow for your app that would be on the QMainWindow::centralWidget() --- and then add your child widgets onto those layouts. Not doing so may lead to unexpected sizing/positioning issues. If you have not read through https://doc.qt.io/qt-5/layout.html, may I suggest you do so and reconsider in that light.



  • Thank you for you help guys ! But iam not sure exatly about these sizes of my window. When i was working GUI in Tkinter whole program was able to scale without doing something extra. But at least how can i stop to scaling my window ? Just permament ressolution and no resizing allowed. You know also when i do not define set geometry from where this program know how big my window should be ?



  • I need to learn and figure it out how to make this in right way. What should i do when i want scale with all widgeds in window when i try to resize it while using.


  • Lifetime Qt Champion

    Hi,

    Use layouts.


  • Banned

    Okay I am not sure what is available to you on your computer but you can use

    for Style in QStyleFactory.keys():
        print(Style)
    

    to get a list of all the styles available then use MainEventThread.setStyle('ChosenStyle') to set the style to the one you are wanting to use -- just note it may not be available on the destination machine if it is not the same OS as the one you created it on -- so perhaps a contingency and/or check to be sure its present before using it could be implemented.

    Also here is a cleaner more python-qt friendly version of a QMainWindow without any unnecessary issues that I share with all my students, it contains full explanations of the various elements and the more common potential issues you may encounter out on the internet. Oh and I also show you how to set the window style once you determine the one you want to use. The checking to see if it exists is a simple if 'Style' in QStyleFactory.keys():

    # All imports should be done at the top for ease of viewing and collectivity
    # Just import the bare minimum of what you need and no more as this helps you
    # and anyone viewing your code to know what you are using and where it came
    # from at an easy glance.
    from PyQt5.QtCore    import Qt
    from PyQt5.QtGui     import QPalette, QColor, QBrush, QFont
    from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
    from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QAction, QStyleFactory
    from PyQt5.QtWidgets import QLabel, QPushButton
    
    # Always import everything else after you import your Python-Qt objects as
    # this prevents potential issues that might occur if you do not
    from sys import exit as sysExit
    
    # This is your Menu and Tool Bar class it does not handle the Tool Bar
    # at this time but it could be expanded to do so fairly easily just 
    # keep in mind everything on a Tool Bar comes from the Menu    
    class MenuToolBar(QDockWidget):
        def __init__(self, MainWin):
          # Note do not use super( ) in Python as it introduces 4 known issues that 
          # must be handled properly. Further there are still actual bugs within
          # the usage of super( ) when used in Python. Now while super( ) does work 
          # fine within C++ it does not work as seamlessly within Python due to the 
          # major differences between these 2 languages. Next the reason it was 
          # created was to handle a rather rare inheritance issue and unless you are 
          # doing some complicated inheritance you will most likely never run into 
          # this extremely rare issue, however the 4 major issues that get included 
          # by using super( ) are much more likely to occur than that rare issue its 
          # meant to solve. Of course using the basic explicit method (as shown), 
          # does not cause these issues and is as just as simple as using `super( )` 
          # further you do not actually gain anything useful by using `super( )` in 
          # Python that could not be done in a much simpler and safer manner.
            QDockWidget.__init__(self)
            self.MainWin = MainWin
            self.MainMenu = MainWin.menuBar()
    
          # This is used to have a handle to the Menu Items
          # should you implement a Tool Bar
            self.MenuActRef = {'HelloAct':0,
                               'ResetAct':0}
    
            # ******* Create the World Menu *******
            self.WorldMenu  = self.MainMenu.addMenu('World')
    
            # ******* Create World Menu Items *******
            self.HelloAct = QAction('&Hello', self)
          # In case you have or want to include an Icon
          #  self.HelloAct = QAction(QIcon('Images/hello.ico'), '&Hello', self)
            self.HelloAct.setShortcut("Ctrl+H")
            self.HelloAct.setStatusTip('Say Hello to the World')
            self.HelloAct.triggered.connect(self.SayHello)
            self.MenuActRef['HelloAct'] = self.HelloAct
    
            self.ResetAct = QAction('&Reset', self)
          #  self.ResetAct = QAction(QIcon('Images/reset.ico'), '&Hello', self)
            self.ResetAct.setShortcut("Ctrl+H")
            self.ResetAct.setStatusTip('Reset the Dialog')
            self.ResetAct.triggered.connect(self.ResetWorld)
            self.MenuActRef['ResetAct'] = self.ResetAct
    
            # ******* Setup the World Menu *******
            self.WorldMenu.addAction(self.HelloAct)
            self.WorldMenu.addSeparator()
            self.WorldMenu.addAction(self.ResetAct)
    
      # These are the Menu/Tool Bar Actions
        def SayHello(self):
          # This is called a call back and you will find many will cry foul with this but that is 
          # because they simply do not understand its purpose compared to the Signal/Slot method
          # either is fine if you are not using QThreads but Signal/Slots come with unnecessary 
          # overhead that makes the program unnecessarily more complex, however on the flip-side
          # if using QThreads then you definitely want to handle things contained within a QThread 
          # using Signal/Slots however no QtWidget object can exist anywhere but within the 
          # MainEventThread most of these kind of calls will never be a concern
            self.MainWin.MenuSubmit()
    
        def ResetWorld(self):
            self.MainWin.MenuReset()
    
    # The Central Panel where everything gets displayed basically the actual Main Gui
    class CenterPanel(QWidget):
        def __init__(self, parent):
            QWidget.__init__(self)
          # Note you only need handles "self." to things you plan to manipulate
    
          # Okay first everything for the Label 
          # Define the Palette and Brush for the Label
            lblPalette = QPalette()
            lblBrush = QBrush(QColor(255, 255, 255))
            lblBrush.setStyle(Qt.SolidPattern)
            lblPalette.setBrush(QPalette.Disabled, QPalette.Window, lblBrush)
          # Define the Font for the Label
            lblFont = QFont()
            lblFont.setPointSize(36)  # 48 was a bit big
          # Create and Set the Label
            self.lblDisplyr = QLabel()
            self.lblDisplyr.setPalette(lblPalette)
            self.lblDisplyr.setFont(lblFont)
            self.lblDisplyr.setAutoFillBackground(True)
            self.lblDisplyr.setText("Here is What I Look Like Before the Click")
    
          # Now everything for the Button
            self.btnSubmit = QPushButton('Submit')
            self.btnSubmit.clicked.connect(self.HandleSubmit)
    
          # Put the Button in a Box on the Left to handle its layout
            HBox = QHBoxLayout()
            HBox.addWidget(self.btnSubmit)
            HBox.addStretch(1)
    
          # Finally put everything in a Vertical Box to finish the layout
            VBox = QVBoxLayout()
            VBox.addLayout(HBox)
            VBox.addWidget(self.lblDisplyr)
            VBox.addStretch(1)
    
          # Assign the Layout to your Center Pane QWidget            
            self.setLayout(VBox)
    
        def HandleSubmit(self):
            self.lblDisplyr.setText('Hello World... can you read me yet?')
    
    class MainWindow(QMainWindow):
        def __init__(self):
            QMainWindow.__init__(self)
          # Basic Main Window Items aka this is your Handler or Controller for M-V-C
            self.setWindowTitle('Main Window')
          # I do this for clarity and to remind myself which occupies what spot
            WinLeft = 150; WinTop = 150; WinWidth = 500; WinHigh = 500
            self.setGeometry(WinLeft, WinTop, WinWidth, WinHigh)
    
          # QMainWindow contains a Central Widget, Menu/Tool Bar, Status Bar, and 
          # dockable window border this covers 3 of the 4 items
            self.CenterPane = CenterPanel(self)
            self.setCentralWidget(self.CenterPane)
    
          # The Menu and Tool Bar for your MainWindow should you want one or both
            self.MenuBar = MenuToolBar(self)
    
          # The Status Bar for your MainWindow should you want one
            self.SetStatusBar(self)
          # Not exactly sure what this does but it does remove oddities from the window
            self.setStyle(QStyleFactory.create('Cleanlooks'))
    
        def SetStatusBar(self, parent):
            StatusMsg = ''
            parent.StatBar = parent.statusBar()
    
            if len(StatusMsg) < 1:
              # This verbiage will disappear when you view menu items
                StatusMsg = 'Ready'
    
            parent.StatBar.showMessage(StatusMsg)
    
        def MenuSubmit(self):
            self.CenterPane.HandleSubmit()
    
        def MenuReset(self):
            self.CenterPane.lblDisplyr.setText('Oh no the World has been Reset')
    
    if __name__ == "__main__":
      # If you are not going to handle Command Line arguments then do not include sys.argv
      # However if you do plan to use Command Line arguments then look into the argparser
      # library as this handles them much more intuitively, concisely, and efficiently no sense
      # reinventing a quality wheel one you can simply employ the one that already exists 
        MainEvntThred = QApplication([])
        MainEvntThred.setStyle('Fusion')
    
        MainApp = MainWindow()
        MainApp.show()
    
        MainEvntThred.exec()
    


  • Thank you guys for your help !



  • @Samuel-Bachorik You don`t need to care about scaling. If you will use a resolution of the desktop you will have the window that will be similar for any device with any screen resolution. To build the elements inside this window you can build these elements (buttons, fields, etc) with layouts without setting sizes explicitly. It is better to use the QGridLayout, or you can use QVBoxLayout or QHBoxLayout if the app is simple in functional elements. Or another way to make sizes relative to the window. For example:

    self.button.setFixedWidth(self.width() / 3)
    

    That will be button width as one-third of the window size, and it will work for any device with any resolution. And do not any these "resize(100, 100)".


Log in to reply