Sytuacja kobiet w IT w 2024 roku
13.08.20215 min
Dorel Masasa

Dorel MasasaPython DeveloperBig Data Researcher

Proste GUI w Pythonie z PyQt5

Sprawdź, jak możesz zbudować proste GUI, używając do tego pakietu Pythona o nazwie Pyqt5.

Proste GUI w Pythonie z PyQt5

PyQt jest pakietem Pythona do pracy z wieloplatformowym Qt GUI. Ogólnie chodzi o to, że możesz napisać swój kod, gdzie Ci się podoba i będzie on działał na każdym systemie operacyjnym. Nie programuję GUI, ale jeżeli Ty chcesz to robić, to nie polecam robić tego w Pythonie, ale jeżeli potrzebujesz czegoś szybkiego dla np. rozwiązania małego problemu dla teamu, to moduł ten pasuje jak ulał. 

Na końcu tego artykułu pokażę GUI, które wybiera, z jakim plikiem chce pracować. 

Designer 

PyQt ma GUI designer, który znacznie ułatwia pracę, oszczędzając Ci sporo czasu, w porównaniu np. do Tkintera. 


Widok designera


Jak widać, już zbudowałem prosty UI. Po prawej możesz wybrać nazwę i domyślne elementy każdego obiektu. Po lewej możesz dodać obiekty wejściowe, zmienne itd. 

Po zapisaniu zmian w projekcie otrzymamy plik .ui, który może zostać przekonwertowany do skryptu Pythona po użyciu następującej komendy:

python -m PyQt5.uic.pyuic -x [FILENAME].ui -o [FILENAME].py


Stworzyliśmy tutaj plik python, który pozwoli nam uruchomić nasze UI

Niczego nie zmieniaj

Modyfikacje naszego nowego pliku python byłyby sporym błędem, ponieważ jeśli kiedykolwiek chcemy edytować nasze GUI, to popsujemy wprowadzone zmiany. Tak naprawdę należy stworzyć własną klasę, która dziedziczy z naszego GUI. 

Po prostu skopiuj importy i utwórz nową klasę, co powinno wyglądać następująco:

from file_choosing import Ui_Dialog
from PyQt5 import QtCore, QtGui, QtWidgets

# our class
class MainWindow(Ui_Dialog):
    def __init__(self):
        super(MainWindow).__init__()
def setupUi(self, Dialog):
    super(MainWindow, self).setupUi(Dialog)
    # Todo: add our own functions
# running GUI instance
if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = MainWindow()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

Jak wprowadzić pożądane zmiany?

Musimy zmodyfikować pewną istotną funkcję — setupUI. Funkcja ta tworzy UI, a my musimy połączyć funkcje z naszymi przyciskami. 

Powinno to wyglądać tak:

def setupUi(self, Dialog):
    super(MainWindow, self).setupUi(Dialog)

    # adding functions to buttons from here
    self.toolButton.clicked.connect(self._create_window)
    self.pushButton.clicked.connect(self._clicked_push_button)

Tutaj wchodzi Twój kod

Udało nam się stworzyć GUI, ale nic ono nie robi. Funkcje connect pozwalają nam dodać do GUI kod, aby coś zaczęło się tam dziać. 

Jak połączymy już funkcje z przyciskami, to każde kliknięcie uruchomi naszą funkcję. 

Tak na marginesie — to program jednowątkowy, więc jeżeli robisz obliczenia w głównym wątku i jest to długa operacja, to GUI przestanie odpowiadać.

Funkcje

Aby zaoszczędzi Ci trochę czasu na szukaniu odpowiedzi w internecie, tutaj jest kilka kluczowych funkcji:

# setting text on a text box / line
[object].setText(file)
# reading text of text box / line
[object].text()
# adding functonality to button
[object].clicked.connect([your function])


I na koniec: pokażę pełen kod, który wybiera plik. Użyłem dokumentacji Pyqt5. Jeśli chcesz, aby Twoje GUI wyglądało i działało lepiej, to zachęcam do poczytania na ten temat. 

Główny kod

from file_choosing import Ui_Dialog
from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(Ui_Dialog):
    def __init__(self):
        super(MainWindow).__init__()
        self.title = 'Choose file'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480

    def setupUi(self, Dialog):
        super(MainWindow, self).setupUi(Dialog)

        # adding functions to buttons from here
        self.toolButton.clicked.connect(self._create_window)
        self.pushButton.clicked.connect(self._clicked_push_button)
        #

    def _create_window(self):
        self._shared_memory = {}
        self.ex = App(self._shared_memory)
        self._clicked_tool_button()

    def _clicked_tool_button(self):
        file = self._shared_memory.get('filename')
        if file is not None:
            self.lineEdit.setText(file)

    def _clicked_push_button(self):
        # Todo: your script
        if self.lineEdit.text() != '':
            print('now your script should do something')
            self.textBrowser.setText(f'my scripts just did something with file: {self._shared_memory.get("filename")}')
            pass

        else:
            print('now your script should do something')
            self.textBrowser.setText(f'choose file, or my script wont do a thing')


# choosing file window
class App(QtWidgets.QWidget):

    def __init__(self, shared):
        super().__init__()
        self.title = 'PyQt5 file dialogs - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.shared = shared
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.openFileNameDialog()

    def openFileNameDialog(self):
        options = QtWidgets.QFileDialog.Options()
        options |= QtWidgets.QFileDialog.DontUseNativeDialog
        fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self, "QFileDialog.getOpenFileName()", "",
                                                            "All Files (*);;Python Files (*.py)", options=options)
        if fileName:
            self.shared['filename'] = fileName
            return fileName


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = MainWindow()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

Kod UI

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'file_choosing.ui'
#
# Created by: PyQt5 UI code generator 5.14.2
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(677, 341)
        self.pushButton = QtWidgets.QPushButton(Dialog)
        self.pushButton.setGeometry(QtCore.QRect(530, 210, 101, 21))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(Dialog)
        self.lineEdit.setGeometry(QtCore.QRect(90, 32, 441, 31))
        self.lineEdit.setObjectName("lineEdit")
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(40, 40, 31, 16))
        self.label.setObjectName("label")
        self.toolButton = QtWidgets.QToolButton(Dialog)
        self.toolButton.setGeometry(QtCore.QRect(540, 30, 81, 31))
        self.toolButton.setObjectName("toolButton")
        self.textBrowser = QtWidgets.QTextBrowser(Dialog)
        self.textBrowser.setGeometry(QtCore.QRect(40, 110, 391, 192))
        self.textBrowser.setObjectName("textBrowser")
        self.label_2 = QtWidgets.QLabel(Dialog)
        self.label_2.setGeometry(QtCore.QRect(220, 80, 59, 15))
        self.label_2.setObjectName("label_2")

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Main"))
        self.pushButton.setText(_translate("Dialog", "OK"))
        self.label.setText(_translate("Dialog", "File"))
        self.toolButton.setText(_translate("Dialog", "Choose File"))
        self.label_2.setText(_translate("Dialog", "results"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

Użyłem domyślnych nazw dla uproszczenia sprawy, więc odtwarzanie naszego UI będzie proste.

Podsumowanie

To, co powyżej pokazałem, warto wiedzieć, nawet jeśli nie będzie się tego używać. 

Zwykle używam tego przy kompilowaniu kodu w Pythonie, nawet jeśli nie jest to tak wydajne lub powszechne. Czasami Twój kolega/koleżanka z zespołu może skorzystać z Twojego narzędzia, w formie pliku EXE z prostym GUI, co czyni taki program bardzo prosty w użyciu.


Oryginał tekstu w języku angielskim możesz przeczytać tutaj

<p>Loading...</p>