Qt Designer to aplikacja dostarczana wraz z biblioteką Qt służąca do tworzenia interfejsów użytkownika naszych aplikacji. Za pomocą przeciągania widżetów z dostępnej palety możemy umieścić wszystkie potrzebne elementy. Co ważne możemy także zadbać o rozmieszczenie poszczególnych widżetów za pomocą szablonów (Layouts), jak i o nadanie etykiet i domyślnych ustawień poszczególnym widgetom. W tym artykule opiszę tworzenie proste interfejsu prezentującego proces poprawnego tworzenia interfejsu w QtDesignerze.
W przypadku Windowsa QtDesigner będzie dostępny po zainstalowaniu PyQt4. W przypadku Linuksa będzie w pakiecie Qt, lub np. w przypadku Ubuntu, które stosuje rozbite pakiety - jako oddzielny pakiet (szukaj "designer").
Naszym celem będzie stworzenie prostej aplikacji, która będzie startowała pasek postępu przyrastający co sekundę:
Trzy przyciski QPushButton (Start, Stop, Exit) odpowiednio do uruchamiania i zatrzymywania paska postępu, oraz do zamykania aplikacji. Do tego jeden QProgressBar.
Otwieramy Qt Designera i tworzymy nowy Widget:
Z menu po lewej przeciągamy trzy przyciski ("Push Button") i jeden pasek postępu ("Progress Bar").
Klikając na przycisk możemy edytować tekst jaki wyświetla. Gdy zaznaczymy jakiś widget na oknie - w menu po prawej stronie pojawią się jego ustawienia. W przypadku QProgressBar znajdziemy ustawienia określające startową wartość (mamy 24, a wypada zmienić na 0):
Zmieniamy nazwy na przyciskach, a także startową wiadomość paska postępu.
Każdy widżet ma swoją unikalną etykietę, po której w kodzie można go identyfikować i wykorzystywać. Warto nazwać wszystkie używane widgety spójnie i zgodnie z ich funkcją/przeznaczeniem. Etykietę zmieniamy w menu ustawień:
Przycisk "Start" nazwałem "startButton", "Stop" - "stopButton", "Exit" - "exitButton". Pasek postępu pozostał jako "progressBar".
Interfejs mamy już gotowy jeżeli chodzi o zawartość. W menu górnym możesz sprawdzić wygląd zaprojektowanego okna: Formularz - Podgląd. Spróbuj rozszerzyć wyświetlone okno. Zobaczysz efekt tego typu:
Widgety nie skalują się wraz z oknem. By widżety skalowały się i odpowiednio układały się w oknie należy zastosować Layout ("szablon"). Taki szablon możemy (i zazwyczaj to robimy) ustawić dla danego okna wybierając szablon z górnego menu QtDesignera
Mamy odpowiednio poziomy i pionowy szablon (rozmieszcza odpowiednio widżety jeden po drugim i jeden pod drugim), następnie poziomy i pionowy Splitter (użytkownik może później przesuwać granicę podziału). Ostatni szablon do "grid" umożliwiający rozmieścić szablony w poziomie i pionie. Te same szablony można także wykorzystywać do zgrupowania kilku widżetów.
Zaznacz obecne trzy przyciski (klikaj na nie z wciśniętym klawiszem CTRL) a następnie kliknij na poziomy szablon (pierwszy):
Przyciski zostały zgrupowane w szablonie. Teraz nie mając zaznaczonego żadnego widżeta wybierz szablon pionowy (drugi) - by ustawić go dla całego okna. Oto efekt:
Przyciski skalują się do równych długości, jak i też szablon zajmuje całą wolną wysokość.
Do dopasowywania skalowania się widgetów możemy użyć "wirtualnych" widżetów "Spacers" ("odstępy"):
Wstaw poziomy odstep między przyciskiem Stop a Exit:
A pionowy pod paskiem postępu:
Teraz widżety w naszym oknie będą płynnie skalowały się wraz z rozmiarem okna:
Interfejs jest gotowy i można przystąpić do jego oprogramowania. Zapisz interfejs w pustym katalogu jako np. counter.ui
Gdzie from counter import Ui_CounterWindow to import klasy naszego okna z pliku counter.py. Otwierając ten plik zdobędziemy nazwę klasy (Ui_CounterWindow w tym przypadku). Będzie to nazwa wg. schematu "Ui_etykietaOkna". Uruchom plik run.py - powinno wyświetlić się okno.
Zaczynamy od połączenia sygnału kliknięcia w przycisk z własnym slotem - metodą wykonującą określony kod. Oto rozwinięty kod szkieletu:
# -*- coding: utf-8 -*-importsysfromPyQt4importQtCore,QtGuifromcounterimportUi_CounterWindowclassMyCounter(QtGui.QWidget):def__init__(self,parent=None):QtGui.QWidget.__init__(self,parent)self.ui=Ui_CounterWindow()self.ui.setupUi(self)QtCore.QObject.connect(self.ui.startButton,QtCore.SIGNAL("clicked()"),self.start)QtCore.QObject.connect(self.ui.stopButton,QtCore.SIGNAL("clicked()"),self.stop)QtCore.QObject.connect(self.ui.exitButton,QtCore.SIGNAL("clicked()"),self.close_app)defstart(self):""" Start the counter """print'start'defstop(self):""" Stop the counter """print'stop'defclose_app(self):""" Close the app """app.exit()if__name__=="__main__":app=QtGui.QApplication(sys.argv)myapp=MyCounter()myapp.show()sys.exit(app.exec_())
Metoda close_app zostanie wywołana po kliknięciu na przycisk "Exit". Sygnał kliknięcia (clicked()) został połączony z tą metodą za pomocą QtCore.QObject.connect. Przycisk określony jest jako self.ui.exitButton, gdzie exitButton to etykieta widżeta ustawiona przez nas w Qt Designerze. Podobnie połączyłem pozostałe dwa przyciski. Na razie metody wypisują tekst w konsoli gdy przycisk został kliknięty.
By stworzyć ładnie postępujący stan paska postępu użyję Stoperów opisanych w podlinkowanym artykule.
Oto gotowy kod pliku run.py:
# -*- coding: utf-8 -*-importsysfromPyQt4importQtCore,QtGuifromcounterimportUi_CounterWindowclassMyCounter(QtGui.QWidget):def__init__(self,parent=None):QtGui.QWidget.__init__(self,parent)self.ui=Ui_CounterWindow()self.ui.setupUi(self)QtCore.QObject.connect(self.ui.startButton,QtCore.SIGNAL("clicked()"),self.start)QtCore.QObject.connect(self.ui.stopButton,QtCore.SIGNAL("clicked()"),self.stop)QtCore.QObject.connect(self.ui.exitButton,QtCore.SIGNAL("clicked()"),self.close_app)# stoperself.progress_timer=QtCore.QTimer()QtCore.QObject.connect(self.progress_timer,QtCore.SIGNAL("timeout()"),self.progress_update)defprogress_update(self):""" Update the progress bar """val=self.ui.progressBar.value()+10ifval<=100:self.ui.progressBar.setValue(val)else:self.progress_timer.stop()defstart(self):""" Start the counter """print'start'self.progress_timer.start(1000)defstop(self):""" Stop the counter """print'stop'self.progress_timer.stop()defclose_app(self):""" Close the app """app.exit()if__name__=="__main__":app=QtGui.QApplication(sys.argv)myapp=MyCounter()myapp.show()sys.exit(app.exec_())
Metoda start uruchamia stoper, który co 1 sekundę będzie wywoływał metodę progress_update, która to o 10% zwiększy postęp paska postępu :)
Comment article