"My Graph Generation Application" by Python (PySide + PyQtGraph) Part 2

Part 2-GUI programming with PySide

How to create a GUI for PySide

There are two ways to create a PySide GUI. "(1) How to hit directly" and "(2) How to use Qt Designer". The former is written directly in the program code, and the latter uses tools. I personally think that ① will help you understand PySide when creating a GUI, so I will use this one this time.

Roughly speaking, PySide creates a GUI by nesting layouts and widgets (GUI parts) as shown below. The main layouts are those that arrange elements horizontally like a grandchild layout, those that arrange elements vertically like a child layout, and those that arrange elements on a grid (grid).

┏ Window ━━━━━━━━━━━━━━━━━━━┓
┃                        ┃
┃┏ Parent layout ━━━━━━━━━━━━━━━━┓┃
┃┃┏ child layout ━━━━━━━━━━━┓┏━┓┃┃
┃┃┃┏ Grandchild layout ━━━━━━━━━┓┃┃┃┃┃
┃┃┃┃┏━━━━━━┳━━━━━━┓┃┃┃U┃┃┃
┃┃┃┃┃Widget ┃Widget ┃┃┃┃i┃┃┃
┃┃┃┃┗━━━━━━┻━━━━━━┛┃┃┃ji┃┃┃
┃┃┃┗━━━━━━━━━━━━━━━┛┃┃e┃┃┃
┃┃┃┏━━━━━━━━━━━━━━━┓┃┃ ┃┃┃
┃┃┃┃ Widget ┃ ┃ ┃ To ┃ ┃ ┃
┃┃┃┗━━━━━━━━━━━━━━━┛┃┃ ┃┃┃
┃┃┗━━━━━━━━━━━━━━━━━┛┗━┛┃┃
┃┗━━━━━━━━━━━━━━━━━━━━━━┛┃
┗━━━━━━━━━━━━━━━━━━━━━━━━┛

In creating the GUI this time, we will use horizontal layout, vertical layout and a little special layout. Also, the grid layout (like) will be used while working with PyQtGraph.

When actually writing the GUI in the program, it is basic to create it from the contents. In other words

  1. Widget generation and initialization
  2. Layout generation
  3. Store widget layouts in the upper layout in order from the inside
  4. Set the parent layout as the main layout of the window

I will write the code that has the flow.

GUI programming with PySide

Let's create a GUI at once. Below, I will explain the code in order from the top. Please add in order in the previous [4] \ _ \ _ init \ _ \ _ (). The full text of the function is at the very end.

# [4]
    #Initialization of MainWindow class(GUI generation, signal slot connection)
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)
        # [4-1]Set the title of the window
        self.setWindowTitle('I'm a graph generation application')
        

In GUI programming, the task of deciding on an application name is a very sacred ritual. You can bring your application to life by using the setWindowTitle () function like ** [4-1] **. When I start it at this point, the contents are still blank, but the title bar and taskbar now show my name. Doesn't it feel like it's a little less tasty? ……Is that so.

ウィンドウタイトルの表示

By the way, it is also possible to set the icon with the self.setWindowIcon () function. However, it is troublesome to prepare, so I will omit it here.


        # [4-2]Set the coefficient
        self.keisu1 = 5.
        self.keisu2 = 10.
        
        # [4-3]Create GUI parts
        self.keisu1Label = QLabel('Coefficient 1')
        self.keisu1Edit = QLineEdit(str(self.keisu1))
        self.keisu2Label = QLabel('Coefficient 2')
        self.keisu2Edit = QLineEdit(str(self.keisu2))
        self.folderPathLabel = QLabel("Folder path:")
        self.folderPathEdit = QLineEdit(".\\")
        self.fileNameListWidget = QListWidget()
        self.button = QPushButton('Image output')
        
        # [4-4]Set GUI parts
        self.fileNameListWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        

Next, prepare two float type coefficients to be used when formatting the data with ** [4-2] **. In ** [4-3] **, the GUI parts required for this application, QLabel (label), QLineEdit (one-line text box), QListWidget (list widget), and QPushButton (button) are generated. QLabel, QLineEdit, QPushButton can display the character string inside the widget at the same time as it is generated by putting a character string in the argument. folderPathEdit is generated as a text box to enter the directory to display the file list later. For the time being, let's specify the folder where this program file (graphApp.py) is located with a relative path. If the folder containing the data file of the experimental result is decided, it is easy to specify it, and if you create a setting file, you can take over the directory that was opened last time. In ** [4-4] **, the QListWidget fileNameListWidget has been reconfigured so that multiple contents can be selected. Please refer to PySide Reference for various setting items and functions of each GUI component. Even if I start the program when the GUI part is generated, the contents of the window remain blank. This is because the layout has not been generated and set yet.


        # [4-5]Create a graph drawing area for PyQtGraph
        self.lw = pg.LayoutWidget()
        self.lw.setMinimumSize(800, 600)
        self.lw.setMaximumSize(800, 600)
        

The LayoutWidget, which is a PyQtGraph widget, is generated by ** [4-5] **. As mentioned last time, PyQtGraph is a GUI library specializing in graph drawing derived from PySide (Qt). LayoutWidget is actually a widget whose inheritance source is QWidget, so it can be installed in the layout of PySide. Details will be explained one after another. Since I just added more widgets, the window does not change even if I start it as usual. Next, let's create the layout.


        # [4-6]Create a layout and add a widget
        keisuLayout = QFormLayout()
        keisuLayout.addRow(self.keisu1Label, self.keisu1Edit)
        keisuLayout.addRow(self.keisu2Label, self.keisu2Edit)
        folderLayout = QFormLayout()
        folderLayout.addRow(self.folderPathLabel, self.folderPathEdit)
        
        leftLayout = QVBoxLayout()
        leftLayout.addLayout(keisuLayout)
        leftLayout.addLayout(folderLayout)
        leftLayout.addWidget(self.fileNameListWidget)
        leftLayout.addWidget(self.button)
        
        layout = QHBoxLayout()
        layout.addLayout(leftLayout)
        layout.addWidget(self.lw)
        

There are three layouts used for this application: QFormLayout, QVBoxLayout, and QHBoxLayout as shown in ** [4-6] **. QFormLayout is a layout that makes it easy to compose a label on the left and a text box or radio button on the right, which are common on form screens. Use the addRow () function to add labels and various widgets as a set in the layout. On the other hand, QVBoxLayout and QHBoxLayout are layouts in which elements can be arranged vertically (Vertical) and horizontally (Horizontal). By using the addLayout () function in addition to the addWidget () function, you can create a more complex GUI with a nested structure. If you start the program here ... nothing will change as usual. Finally, you need to "set the parent layout to the main layout of the window".


        # [4-7]Set the window layout
        self.setLayout(layout)
        

** [4-7] **'s setLayout () function sets the layout for the main layout of this application's window. Now you can finally display the GUI below in the window.

その2成果

How about that. This completes the basic form of the graph generation application to be developed in this summary.

  1. Widget generation and initialization
  2. Layout generation
  3. Store widget layouts in the upper layout in order from the inside
  4. Set the parent layout as the main layout of the window

By following the steps in, I think it was surprisingly easy to create an application with a GUI like that. In each layout, the elements are lined up from the top (from the left) in the order of adding. Please find your own "I" GUI by changing the order and adding other GUI parts.

And, although the GUI has just been completed, it will continue for a while.


        # [4-8]Connect signals and slots
        self.folderPathEdit.textEdited.connect(lambda: self.updateFileNameListWidget(self.fileNameListWidget, self.folderPathEdit.text()))
        self.fileNameListWidget.itemSelectionChanged.connect(lambda: self.createGraph(self.folderPathEdit.text(), self.fileNameListWidget.selectedItems()[0].text()))
        
        # [4-9]Update fileNameListWidget
        self.updateFileNameListWidget(self.fileNameListWidget, self.folderPathEdit.text())

I will talk about signal slots in the next section, so I will leave the story of ** [4-8] ** for now. Finally, use the ** [4-9] ** updateFileNameListWidget () function on the otherwise empty fileNameListWidget to display the file list in the specified folder as soon as it is started. However, since the processing part of the updateFileNameListWidget () function is not implemented yet, at the moment it is only output to ʻupdateFileNameListWidget` and the command prompt (terminal / terminal) at the same time as starting.

Signals and slots

The initialization function [4] \ _ \ _ init \ _ \ _ () in PySide plays a major role in creating the GUI and connecting ** [4-8] ** signals and slots.

Unlike procedural CUI programs, which only require processing such as "when you enter a name, height, and weight, BMI is output" in order from the top, GUI applications are operated at any time and in any order. It is necessary to perform the processing corresponding to the button and the text box. In order to perform this so-called event-driven programming, PySide (Qt) provides the above-mentioned signal and slot mechanism.

I will return to ** [4-8] ** and explain accordingly.

        # [4-8]Connect signals and slots
        self.folderPathEdit.textEdited.connect(lambda: self.updateFileNameListWidget(self.fileNameListWidget, self.folderPathEdit.text()))
        self.fileNameListWidget.itemSelectionChanged.connect(lambda: self.createGraph(self.folderPathEdit.text(), self.fileNameListWidget.selectedItems()[0].text()))
        

The above code uses the signal slot mechanism to achieve the following two operations.

  1. The text box is edited → Update the file list of the list widget
  2. Items in the list widget are selected → Draw a graph

"Signal slot connection", "above code" and "statement 1" of the two lines of code, respectively

Is supported. The meaning of the code is that the signal that the text box has been edited (textEdited) and the function that updates the list widget (updateFileNameListWidget ()) are used as slots, and the two are connected (connect () function).

Is the signal slot connection a remote control and a TV, for example? It is said that the signal of the unique pattern transmitted from the remote control when the button is pressed and the corresponding TV function (channel change, volume up, etc.) are linked in advance.

To check if the signal slot connection is actually made, start this application and edit the contents of folderPathEdit on the GUI. You should probably get ʻupdateFileNameListWidget` and a command prompt (terminal / terminal) every time you type or erase.

In addition to this, various signals are prepared for each widget, such as button clicked (QButton.clicked) and text selected (QPlainTextEdit.selectionChanged), and you can also create your own. Widget. By the way, lambda: means that you are using a lambda expression, but if you remember it for the time being, you will be very happy (using a lambda expression allows you to give arguments to slot functions as you like. Will be).

Next time preview

That's all about GUI programming with PySide. Next time, we will implement a function that displays a file list in a list widget on the GUI that the processing unit has not implemented this time, and even read the file and generate the data used for graph drawing. Well, to be honest, I think that it may be necessary to explain depending on the person, so in such a case you can skip it.

Part 1-Introduction and program overview

About GUI creation using QtDesigner

Finally, I will briefly explain the GUI creation method "② How to use Qt Designer" mentioned in "How to create a GUI for PySide". Qt Designer is a Qt tool that allows you to create a GUI on the GUI that will be downloaded at the same time you install PySide. It should be in "(Python installation destination) \ Lib \ site-packages \ PySide" with a name such as "designer.exe", so start it and touch it. In addition to the GUI parts used to create the graph generation application this time, you can see that there are a wide variety of GUI parts available. QtDesigner allows you to place layouts and widgets in D & D, so it's fun to create a GUI easily. Actually, the .ui file generated by QtDesigner is read by QtUiTools.QUiLoader in the program itself and used.

[4] \ _ \ _ init \ _ \ _ () function full text

# [4]
    #Initialization of MainWindow class(GUI generation, signal slot connection)
    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)
        # [4-1]Set the title of the window
        self.setWindowTitle('I'm a graph generation application')
        
        # [4-2]Set the coefficient
        self.keisu1 = 5.
        self.keisu2 = 10.
        
        # [4-3]Create GUI parts
        self.keisu1Label = QLabel('Coefficient 1')
        self.keisu1Edit = QLineEdit(str(self.keisu1))
        self.keisu2Label = QLabel('Coefficient 2')
        self.keisu2Edit = QLineEdit(str(self.keisu2))
        self.folderPathLabel = QLabel("Folder path:")
        self.folderPathEdit = QLineEdit(".\\")
        self.fileNameListWidget = QListWidget()
        self.button = QPushButton('Image output')
        
        # [4-4]Set GUI parts
        self.fileNameListWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        
        # [4-5]Create a graph drawing area for PyQtGraph
        self.lw = pg.LayoutWidget()
        self.lw.setMinimumSize(800, 600)
        self.lw.setMaximumSize(800, 600)
        
        # [4-6]Create a layout and add a widget
        keisuLayout = QFormLayout()
        keisuLayout.addRow(self.keisu1Label, self.keisu1Edit)
        keisuLayout.addRow(self.keisu2Label, self.keisu2Edit)
        folderLayout = QFormLayout()
        folderLayout.addRow(self.folderPathLabel, self.folderPathEdit)
        
        leftLayout = QVBoxLayout()
        leftLayout.addLayout(keisuLayout)
        leftLayout.addLayout(folderLayout)
        leftLayout.addWidget(self.fileNameListWidget)
        leftLayout.addWidget(self.button)
        
        layout = QHBoxLayout()
        layout.addLayout(leftLayout)
        layout.addWidget(self.lw)
        
        # [4-7]Set the window layout
        self.setLayout(layout)
        
        # [4-8]Connect signals and slots
        self.folderPathEdit.textEdited.connect(lambda: self.updateFileNameListWidget(self.fileNameListWidget, self.folderPathEdit.text()))
        self.fileNameListWidget.itemSelectionChanged.connect(lambda: self.createGraph(self.folderPathEdit.text(), self.fileNameListWidget.selectedItems()[0].text()))
        
        # [4-9]Update fileNameListWidget
        self.updateFileNameListWidget(self.fileNameListWidget, self.folderPathEdit.text())


Recommended Posts

"My Graph Generation Application" by Python (PySide + PyQtGraph) Part 2
"My Graph Generation Application" by Python (PySide + PyQtGraph) Part 1
My PySide (Python)
Python application: Pandas Part 1: Basic
Python application: Pandas Part 2: Series
Python Application: Data Handling Part 3: Data Format
Prime number generation program by Python
Python application: Numpy Part 3: Double array
Python application: data visualization part 1: basic
Python Application: Data Visualization Part 3: Various Graphs
Python application: Pandas Part 4: DataFrame concatenation / combination
Draw a graph with PyQtGraph Part 1-Drawing
Draw a graph with PyQtGraph Part 3-PlotWidget settings
Video frame interpolation by deep learning Part1 [Python]
Draw a graph with PyQtGraph Part 4-PlotItem settings
Draw a graph with PyQtGraph Part 6-Displaying a legend
Python Application: Data Handling Part 2: Parsing Various Data Formats