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.