Your first GUI app with Python and PyQt

Introduction

Many people struggle with learning how to build a GUI app. The most common reason is, they don’t even know where to start. Most tutorials are purely text based, and it’s hard to learn GUI development using text, since GUIs are mainly a visual medium.

We will get around that by building a simple GUI app, and show you how easy it is to get started. Once you understand the basics, it’s easy to add advanced stuff.

This is what we will be building:

qt19

A simple GUI app that takes in a price, a tax rate and calculates the final price.

Most tutorials on GUI apps try to layout the GUI blocks using code, but that is very painful to do. We will be using the superb QT Designer tool to layout our app:

qt21

So no struggling laying out the design by hand. Everything will be done graphically.

All the source code is here.

Pre-requisites

If you followed my advice and installed Anaconda, you will already have PyQt4. If not, you will need to get it from here.

You also need Qt Designer.

Update: As Steve points out in the comments, Anaconda comes with qt-designer, so you don’t need to download anything! It is in: …\Anaconda3\Library\bin and is called designer-qt4.exe.

I recommend you download the whole QT suite, as there are some other useful tools in there too.

Getting Started

Note: You can click on any image below to see the full size, in case you want more detail.

Start QT Designer. In the window that comes up, choose Main Window, as it will give is a blank canvas:

qt01

 

The next thing to do is to select the Text Edit box on the left:

qt2

 

Drag Text Edit to the main window, to get a box like:

qt4

 

See the right side, where I have clumsily red circled a box? That is where the name of the object is. The name is the way this object will be called from our Python code, so call it something sensible.

qt5

 

I’m calling it price_box, as we will enter the price into this box. The next thing we will do is attach a label to the box, to make it clear to the user what this box is for.

qt6

Above, I have circled the label. Drag it across to the main window.

qt7

 

It gets the default text of TextLabel. Double click it and change it to Price. You can also make the text large and bold, as seen here:

qt8

For the tax box, we are going to use something different. See the spin box:

qt9

 

The circle on the left is a spin box. This limits the values you can enter. We don’t need a spinbox, it’s just good to see how you can use different widgets that QT Creator provides. Drag the spin box to the window. The first thing we do is change the objectName to something sensible, tax_rate in our case. Remember, this is how this object will be called from Python.

qt10

We can choose a default value for our spinbox. I’m choosing 20:

qt011

If you look at the image above, you can also set the minimum and maximum limits. We will keep them to what they are.

We will also add another label called Tax Rate, same as we did before. Also look at the circled Push Button we will be using next:

qt012

 

Now, select the Push Button box and drag it to our window.

qt13

The button just says PushButton, which isn’t very helpful. By now, you should know how to change this. But before that, we change the name of the button (and not the text) to calc_tax_button.

qt14

Next,  we change the actual text:

qt15

Drag another Text Edit box on to the window. You don’t need to label it, as we will print the output in here. Do change it’s name to results_window (not shown below, but you should know how to do it by now).

qt16

If you want, you can add a header. This is a simple label box with the font increased:

qt18

And save your work:

qt017This file will be used in the next part when we write the code, so store it somewhere you can access it.

This file that we  created is just a XML file. Open it in a text editor, if you want, and you will find something like this:

qt22
Writing the code

Qt’s code is object oriented, and in  a manner that is easy to follow. Each of the widgets we added is an object, with it’s own functions like toPlainText() (to read the value in a box). This makes it quite easy to use.

I’m sure the official documentation mentions this somewhere, but you have to do some setup before you can use the code. I couldn’t find this setup anywhere, so I worked back from the official examples (as well as other online tutorials) to find the smallest program you need to initialize the class. I have checked this function in as pyqt_skeleton.py.

This is useful, as everytime you start a new PyQt project, use this skeleton to start off, and add your code.

The code is:

The main thing to note is line 3:

This is where you add the file you created earlier. It is loaded using the inbuilt function:

 

Let’s take a quick look at the code:

The main code creates a new Qt Gui application. Passing in sys.argv is required, as QT can be configured from the command line. We won’t be doing that.
Finally, we create a class called MyApp, which inherits from Qt libraries and initializes the parent classes:

You don’t need to know the details of this code. Just use the skeleton and work on that.

Take this file, pyqt_skeleton.py, and rename it to pyqt_first.py. That’s because we don’t want to edit the original file.
The first thing to do is add our XML file, the one that contains our GUI, to the code. Replace this line:

with

This will load our GUI file into memory. Now, the key widget in our GUI was the button. Once you press the button, something happens. What? We need to tell our code what to do when the user presses the Calculate Tax button. In the __init__ function, add this line:

What does this do? Remember we called our button calc_tax_button? (This was the name of the object, not the text that was displayed on it.) clicked is an internal function that is called when (surprise) someone clicks on the button. All QT widgets have specific functions, which you can find our by Googling. The last part of the code says connect(self.CalculateTax). This says that connect this button to a function called self.CalculateTax, so that everytime the user presses this button, that function is called.

We haven’t written that function yet. Let’s do it now.

In the MyApp Class, add another function. We will look at the whole function first, and then go into details:

Okay, let’s look at the code above line by line.

We have to do two things: Read the price box, read the tax box, and calculate the final price. Let’s do that now. Remember, we will call the objects by the names we gave them (which is why I asked you not to use the default generic names like box1, as that would have been confusing pretty soon).

We read our price_box. toPlainText() is an internal function that reads the value stored in that box. You don’t have to remember all these functions, by the way. I just Google something like “Qt Textbox read data” to find out what the name of the function is, though you will start to remember the names after some time, as they are very logically named.

The read value is a string, so we convert it to an integer and store it in a variable called price.

Next, we read the tax box:

Again, value() is the function for reading from a spinbox. Thanks, Google.

Now that we have both these values, we can calculate the final price using very high tech maths:

We create a string with our final price. This is because we will output this string directly to our app:

In our results_window, we call the function setText(), which outputs the string we created.

Just run the file using:

qt19

qt20

And there you go. A simple introduction to PyQt.

If you want more fun, trying playing with the different widgets, though be warned, you can add too many widgets and make your app confusing to use.

Are you interested in seeing more on this? If so, please leave a comment, or contact me.

PS: Interested in leveling up your Python and getting a great job? Check out the Python Apprenticeship Program.

63 thoughts on “Your first GUI app with Python and PyQt”

  1. Hi
    Very interesting tool as Python always lacked a good GUI. Wonder whether this will work on a Raspberry Pi platform?

    Regards

    Andre

    1. QT5 is the shinier newer version. Unfortunately, it breaks backward compatibility.

      I chose PYQy4 merely because it came with my install of Anaconda.

  2. Hi Shantnu,

    Awesome guide, really helped me out. Thanks for posting!

    I’m a Mechanical Engineer using Qt Designer alongside PySide to develop engineering analysis applications. I would love for some more tutorials on using Qt Designer and its implementation through PySide (or Qt). Specifically, I’m trying to implement plots from matplotlib into a GUI designed using Qt designer.

    Any more tutorials/help on this subject matter would be greatly appreciated!

    Thanks so much!

    -Lemay

    1. Thanks Lemay.

      When I last tried PySide, I found it poorly documented & hard to use, but maybe it has improved now.

      Let’s see.

  3. As a complete beginner I struggled getting this to work with PyQt5, however i think i’m finally there (it works at least!). This may be of help to someone else:

    ###############

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

    Ui_MainWindow, QtBaseClass = uic.loadUiType(“tax_calc.ui”)

    class MyApp(QMainWindow):
    def __init__(self):
    super(MyApp, self).__init__()
    self.ui = Ui_MainWindow()
    self.ui.setupUi(self)
    self.ui.calc_tax_button.clicked.connect(self.CalculateTax)

    def CalculateTax(self):
    price = int(self.ui.price_box.toPlainText())
    tax = (self.ui.tax_rate.value())
    total_price = price + ((tax / 100) * price)
    total_price_string = “The total price with tax is: ” + str(total_price)
    self.ui.results_window.setText(total_price_string)

    if __name__ == “__main__”:
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

    1. Hello Sam,
      I tried to use your code for QT5, but I get every time this error message:

      RESTART: H:/Programmierung Python/Projekte/test UI/PyQt_first-master/pyqt_first_qt5.py
      Traceback (most recent call last):
      File “H:/Programmierung Python/Projekte/test UI/PyQt_first-master/pyqt_first_qt5.py”, line 7, in
      class MyApp(QMainWindow):
      File “H:/Programmierung Python/Projekte/test UI/PyQt_first-master/pyqt_first_qt5.py”, line 23, in MyApp
      window = MyApp()
      NameError: name ‘MyApp’ is not defined
      >>>

      I used original your source and WinPython 3.4.4.1QT5

      Sorry, I am new in Python AND QT5.
      Can you help me?
      Thanks
      Guenter

      1. Hi Guenter. Looks like you are inheriting the wrong stuff in “class MyApp(QMainWindow):”. That line should be “class MyApp(QtGui.QMainWindow, Ui_MainWindow):”.

    2. I am Using the same code but still getting error

      //////////////////////////////////////////////////////////////////////////////
      Traceback (most recent call last):
      File “C:\Users\saksh\Desktop\Python3Learn\prjtax.py”, line 8, in
      class MyApp(QtGui.QMainWindow, Ui_MainWindow):
      AttributeError: module ‘PyQt5.QtGui’ has no attribute ‘QMainWindow’

      here’ the code

      ////////////////////////////////////////////////////////////////////////////////////////////
      import sys

      from PyQt5 import QtCore, QtGui, QtWidgets
      from PyQt5 import uic

      Ui_MainWindow , QtBaseClass = uic.loadUiType(“prjtax_calc.py”)

      class MyApp(QtGui.QMainWindow, Ui_MainWindow):
      def __init__(self):
      super(MyApp , self).__init__()
      self.ui = Ui_MainWindow()
      self.ui.setupUi(self)
      self.ui.calc_tax_button.clicked.connect(self.CalculateTax)

      def CalculateTax(self):
      price = int(self.ui.price_box.toPlainText())
      tax = (self.ui.tax_rate.value())
      total_price = price + ((tax/100)*price)
      total_price_string = “The total price with tax is : “+str(total_price)
      self.ui.results_window.setText(total_price_string)

      if __init__ == “__main__”:
      app = QApplication(sys.argv)
      window = MyApp()
      window.show()
      sys.exit(app.exec_())

      I am usingPyQT5…..
      Python 3.5.2 32 bit

      1. My example is written in PyQt4.

        If you want to use PyQt5, look at the other comments, someone got it working with Pyqt5

  4. Its excellent,thanks for your tutorial,if you can share more tutorial then again it will helpful for all of us.i am trying to make application for raspeberry pi B

    1. Thanks Manoj.

      I am writing a few more articles. Subscribe to my list if you want to know when the next one will be out, or just check the website regularly.

  5. Hi,

    Your introduction about how to direct import ui file by ‘qtCreatorFile’ method instead pyuic was very useful to me; however I have question about popup windows by button click/press in main window…

    1. to design popup window, should I create new ui file by qt designer or can be save in mainwindow ui?
    2. how to load the popup window ui, and issue signal to trigger this popup window?

    Regards,
    Sawaichi

    1. Depends. Is it a new window, or do you want to put it in the existing one?

      If new, you’ll have to do a new design. Otherwise, chuck it in mainwindow.

      As to how to switch between them, I cant remember off the top of my head. You will have to Google it.

  6. Thank you so much, Shantnu and Sam : you two made my day !
    Shantnu, how can I subscribe your list please?
    Sam, on my Archlinux, I had to change ” to ‘ and had some indentation.

  7. Hi,
    I am following this skeleton but I get an error when calling setupUi. This is the code:
    from PyQt4 import QtCore, QtGui, uic

    Ui_MainWindow, QtBaseClass = uic.loadUiType(“mainwindow.ui”) # Load the UI

    class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
    ”’
    classdocs
    ”’
    def __init__(self, parent=None):
    QtGui.QMainWindow.__init__(self, parent)
    Ui_MainWindow.__init__(self)
    self.setupUi(self)

    And the error:
    self.ui.setupUi(self)
    File “”, line 29, in setupUi
    TypeError: __init__() takes exactly 1 argument (2 given)

    Any ideas? Has anybody else experienced this? No idea how to solve it…

    1. In the __init__ function, why are you passing *parent*? That’s what its complaining about. It only expects *self*, but is getting an extra variable.

  8. Hi Shantnu,

    Thanks for the tutorial!

    But I am stuck when I do

    python pyqt_first.py

    on Powershell

    it says no module named PyQt4.

    I am really a newbie in whole programming so I am not sure what this means. I searched on google but the subject quickly boils down to other things that I have difficulty understanding. Could you help me or guide me to some resources that I could solve this?

    Many thanks.

    1. It means PyQt isn’t on the path, or not installed correctly.

      How did you install Qt?

      I strongly recommend you install the Anaconda Python version, the link to which is at the start.

      You can have multiple versions of Python, so this won’t interfere with your existing Python.

  9. Hi Andre,

    Thanks for a great tutorial. Btw, i’ve encountered an error when execute the code and need ur advise on that.

    File “/home/pi/calculator_tax.py”, line 25, in
    window = MyApp()
    File “/home/pi/calculator_tax.py”, line 14, in __init__
    self.calc_tax_button.clicked.connect(self.CalculateTax)
    AttributeError: ‘MyApp’ object has no attribute ‘calc_tax_button’

    i’m totally newbies with programming world. currently running linux on RPI2.

    Thanks,
    Faizal

      1. Hi Andre,

        Thanks for your reply.
        Yes I did include the ui file and follow the the step as well.
        The program will be execute if I bypass the self.calc_tax_button.
        Anything wrong on the button naming?

        1. Yes, it looks like a typo. Check the names of the buttons, and how you are calling the buttons in the code. There’s going to be a typo in one of them.

  10. Great stuff. I could run from the cmd command line no problem. However, if I want to add some sweet debugging sauce what IDE/DE do you recommend and how would one get started running this little program within one. I tried to simply open the py file from within QtCreator (file/open) and the code-text looks nice and coloured but all the “run” options are greyed out.

  11. AS per my previous comment I fuigured out how to get an IDE working. After following your nice how-to I followed the instructions at http://popdevelop.com/2010/04/setting-up-ide-and-creating-a-cross-platform-qt-python-gui-application/ (although I installed LiClipse which has pyDev and eclipse bundled together). Then I copied your python code into the Main.py file I created inthe linked how to and the ui file into the same directory as my Main.py file and it ran using the “Run as” “python run” command.

  12. Hi and thank you for this great post!
    I want to have multiple UI in my program. what should i do?
    for example when a button pressed it goes to another UI (without opening new window).

    thank you agin!

  13. Like the way you explain in detail, something most stuff about linking the GUI to the code does not do well. The problem with YouTube videos is they sometimes jump around from one thing to another and get hard to follow… Thanks for your time and effort.

  14. Is there a way you have tried to convert the GUI to a Windows executable? Will py2exe work? I could do this with my old GUI tool and found it was extremely beneficial to create apps for my non-Python savvy co-engineers.

    1. There are several tools like Py2exe, each with their own quirks and problems. But I haven’t tried any, so can’t make any suggestions at the moment.

      1. I will have to try and see I guess. Thanks for putting the tutorial together! Your approach of a skeleton starting point is how I learned Python 12 years ago using PythonCard. I’ve looked at other PyQt tutorials but was hoping for the shortest path to a working GUI which is what you show here. I recently was introduced to Anaconda which has most of the tools I use but had to go shopping for a GUI solution. I think I found it in your tutorial.

  15. Hi Shantnu,
    I wanted to add my thanks for your great tutorial. I just started Mark S’s book, but was a little impatient to get a first py gui done. Everything worked flawlessly…now, I just have to learn to do it with decimal values. One quick comment, people might be interested to know that with Anaconda3, the QtDesigner is available without downloading the whole Qt suite. It took a little searching, but the executable should be in …\Anaconda3\Library\bin and is called designer-qt4.exe.
    Thanks again.

  16. Hi, can you explain how can i do a button that changes the screen, please? Im totally noob with python and pyqt.

  17. Another approach to using the “pyqt_skeleton.py” is to auto generate a .py file from the .ui file like this:

    pyuic my_GUI.ui -o my_GUI.py

    Or

    pyuic my_GUI.ui > my_GUI.py

    Then create a main.py and import my_GUI.py as follow:-

    #====================================================#

    from PyQt4 import QtGui # Import the PyQt4 module we’ll need
    import sys # We need sys so that we can pass argv to QApplication

    import my_GUI # This file holds our MainWindow and all design related things
    # it also keeps events etc that we defined in Qt Designer

    class MyWindow(QtGui.QMainWindow, my_GUI.Ui_MainWindow):
    def __init__(self):
    # Explaining super is out of the scope of this article
    # So please google it if you’re not familar with it
    # Simple reason why we use it here is that it allows us to
    # access variables, methods etc in the design.py file
    super(self.__class__, self).__init__()
    self.setupUi(self) # This is defined in design.py file automatically
    # It sets up layout and widgets that are defined

    self.calButton.clicked.connect(self.CalculateTax)

    # <<<>>>
    def CalculateTax(self):
    price = int(self.price_box.toPlainText())
    tax = (self.spinBox.value())
    total_price = price + ((tax / 100) * price)
    total_price_string = “The total price with tax is: ” + str(total_price)
    self.results_window.setText(total_price_string)

    def main():
    app = QtGui.QApplication(sys.argv) # A new instance of QApplication
    form = MyWindow() # We set the form to be our MyWindow (design)
    form.show() # Show the form
    app.exec_() # and execute the app

    if __name__ == ‘__main__’: # if we’re running file directly and not importing it
    main() # run the main function

  18. Hello, that was a great tutorial of linking QT Designer with PyQt. Very simple.
    How do I go about creating a QDialog by pressing a button? What should I do?

    Regards
    Lucas

  19. This is code for Qt5 and pyqt5 but I have a problem. it does not work. When I start it from spyder it reports kernel die, than on second attempt it shows window but when I enter number and press button nothing happens. When I start it from the shell it opens but when i enter a number and press button it shut down itself.

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

    Ui_MainWindow, QtBaseClass = uic.loadUiType(“tax_calc_qt.ui”)

    class MyApp(QMainWindow):
    def __init__(self):
    super(MyApp, self).__init__()
    self.ui = Ui_MainWindow()
    self.ui.setupUi(self)
    self.ui.calc_tax_button.clicked.connect(self.CalculateTax)

    def CalculateTax(self):
    price = int(self.price_box.toPlainText());
    tax = (self.tax_rate.value());
    total_price = price + ((tax / 100) * price);
    total_price_string = “The total price with tax is: ” + str(total_price);
    self.results_window.setText(total_price_string);

    if __name__ == “__main__”:
    app = QApplication(sys.argv)
    window = MyApp()
    window.show()
    sys.exit(app.exec_())

Leave a Reply