Home  Contents

PyQt4 Widgets

Widgets sind die grundlegenden Bausteine einer Anwendung. Das PyQt4-Programmier-Toolkit verfügt über eine breite Auswahl verschiedener Widgets: Knöpfe, Auswahlboxen, Schiebregler, Listenboxen etc. - Alles, was ein Programmierer für seinen Job braucht. In diesem Abschnitt des Tutorials, werden wir einige nützliche Widgets vorstellen.

QCheckBox

QCheckBox ist ein Widget mit zwei Zuständen: An und Aus. Es besteht aus einer Box und einem Label. Immer wenn eine Auswahlbox angehakt oder geleert wird, wirft sie das Signal stateChanged().

#!/usr/bin/python

# checkbox.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class CheckBox(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Checkbox')

        self.cb = QtGui.QCheckBox('Show title', self)
        self.cb.setFocusPolicy(QtCore.Qt.NoFocus)
        self.cb.move(10, 10)
        self.cb.toggle();
        self.connect(self.cb, QtCore.SIGNAL('stateChanged(int)'), self.changeTitle)

    def changeTitle(self, value):
        if self.cb.isChecked():
            self.setWindowTitle('Checkbox')
        else:
            self.setWindowTitle('')

app = QtGui.QApplication(sys.argv)
icon = CheckBox()
icon.show()
app.exec_()

In unserem Beispiel werden wir eine Auswahlbox erstellen, die den Fenstertitel einstellt.

 self.cb = QtGui.QCheckBox('Show title', self)

Das ist der QCheckBox-Konstruktor.

 self.cb.setFocusPolicy(QtCore.Qt.NoFocus)

Wir verbinden die zuvor erstellte Methode changeTitle() mit dem stateChanged()-Signal. Die changeTitle()-Methode stellt den Fenstertitel um.

 self.connect(self.cb, QtCore.SIGNAL('stateChanged(int)'), self.changeTitle)

Standardmäßig lässt sich die QCheckbox fokussieren. Dies geschieht durch ein dünnes Rechteck um das Label der Auswahlbox herum, das jedoch so schrecklich aussieht, dass ich es lieber deaktiviere, indem ich die Widget-Fokuseinstellung auf Qt.NoFocus setze.

 self.cb.toggle();

Wir setzen den Fenstertitel, also müssen wir die Auswahlbox anhaken. Standardmäßig ist der Fenstertitel nicht gesetzt und die Auswahlbox leer.

QCheckBox

Abbildung: QCheckBox

Umschaltknopf

PyQt4 verfügt über kein eigenes Widget für einen Umschaltknopf. Um einen solchen zu erzeugen, verwenden wir einen QPushButton in einem speziellen Modus. Ein Umschaltknopf ist ein Knopf mit zwei Zuständen: Gedrückt und ungedrückt. Sie können zwischen den Zuständen wechseln, indem auf den Knopf klicken. Es gibt Situationen, in denen diese Funktionsweise genau das ist, was man braucht.

#!/usr/bin/python

# togglebutton.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class ToggleButton(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.color = QtGui.QColor(0, 0, 0) 

        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('ToggleButton')

        self.red = QtGui.QPushButton('Red', self)
        self.red.setCheckable(True)
        self.red.move(10, 10)

        self.connect(self.red, QtCore.SIGNAL('clicked()'), self.setRed)

        self.green = QtGui.QPushButton('Green', self)
        self.green.setCheckable(True)
        self.green.move(10, 60)

        self.connect(self.green, QtCore.SIGNAL('clicked()'), self.setGreen)

        self.blue = QtGui.QPushButton('Blue', self)
        self.blue.setCheckable(True)
        self.blue.move(10, 110)

        self.connect(self.blue, QtCore.SIGNAL('clicked()'), self.setBlue)

        self.square = QtGui.QWidget(self)
        self.square.setGeometry(150, 20, 100, 100)
        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())

        QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('cleanlooks'))

    def setRed(self):
        if self.red.isChecked():
            self.color.setRed(255)
        else: self.color.setRed(0)

        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())

    def setGreen(self):
        if self.green.isChecked():
            self.color.setGreen(255)
        else: self.color.setGreen(0)

        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())

    def setBlue(self):
        if self.blue.isChecked():
            self.color.setBlue(255)
        else: self.color.setBlue(0)

        self.square.setStyleSheet("QWidget { background-color: %s }" % 
            self.color.name())



app = QtGui.QApplication(sys.argv)
tb = ToggleButton()
tb.show()
app.exec_()

In unserem Beispiel erzeugen wir drei Umschaltknöpfe. Darüber hinaus erzeugen wir ein QWidget, dessen Hintergrundfarbe wir auf Schwarz setzen. Die Umschaltknöpfe ändern die Rot-, Grün- und Blauanteile des Farbwertes. Das heißt, die Hintergrundfarbe hängt davon ab, welche Umschaltknöpfe wir drücken.

 self.color = QtGui.QColor(0, 0, 0)

Das ist der Startwert der Farbe: Kein Rot, kein Grün und kein Blau ergeben Schwarz. Theoretisch ausgedrückt handelt es sich bei Schwarz nicht um eine Farbe, sondern vielmehr um Keine Farbe.

 self.red = QtGui.QPushButton('Red', self)
 self.red.setCheckable(True)

Um einen Umschaltknopf zu erzeugen, erzeugen wir einen QPushButton und machen ihn auswählbar, indem wir die setCheckable-Methode aufrufen.

 self.connect(self.red, QtCore.SIGNAL('clicked()'), self.setRed)

Wir verbinden ein clicked()-Signal mit unserer selbst erstellten Methode.

 QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('cleanlooks'))

Ich habe den Style der Applikation auf cleanlooks gestellt, da der Standardstyle unter Linux (Plastique) einen Design-Fehler hat. Dort kann man nicht einfach festlegen, ob der Umschaltknopf gedrückt ist oder nicht. Das geht unter CleanLooks besser.

 if self.red.isChecked():
     self.color.setRed(255)
 else: self.color.setRed(0)

Wir prüfen, ob der Knopf gedrückt wurde und der Farbwert entsprechend angepasst wurde.

 self.square.setStyleSheet("QWidget { background-color: %s }" % self.color.name())

Um die HIntergrundfarbe zu ändern, verwenden wir Stylesheets.

Umschaltknopf

Abbildung: Umschaltknopf

QSlider, QLabel

QSlider ist ein Widget, das über einen einfachen Anfasser verfügt. Der Anfasser kann vor und zurück gezogen werden. Auf diese Weise wählen wir einen Wert zu einem bestimmten Zweck. Manchmal ist ein solcher Schiebregler viel natürlicher als einfach eine Zahl zu übergeben oder einen Drehschalter zu verwenden. QLabel zeigt einen Text oder ein Bild an.

In unserem Beispiel verwenden wir einen Regler und ein Label. Diesmal wird mit dem Label ein Bild angezeigt und über den Regler kontrolliert.

#!/usr/bin/python

# slider-label.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class SliderLabel(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('SliderLabel')

        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
        self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
        self.slider.setGeometry(30, 40, 100, 30)
        self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)


        self.label = QtGui.QLabel(self)
        self.label.setPixmap(QtGui.QPixmap('mute.png'))
        self.label.setGeometry(160, 40, 80, 30)


    def changeValue(self, value):
        pos = self.slider.value()

        if pos == 0:
            self.label.setPixmap(QtGui.QPixmap('mute.png'))
        elif pos > 0 and pos <= 30:
            self.label.setPixmap(QtGui.QPixmap('min.png'))
        elif pos > 30 and pos < 80:
            self.label.setPixmap(QtGui.QPixmap('med.png'))
        else:
            self.label.setPixmap(QtGui.QPixmap('max.png'))

app = QtGui.QApplication(sys.argv)
icon = SliderLabel()
icon.show()
app.exec_()

In unserem Beispiel simulieren wir einen Lautstärkeregler. Durch Ziehen des Anfassers verändern wir das Bild des Labels.

 self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)

Hier erzeugen wir einen waagerechten QSlider.

 self.label = QtGui.QLabel(self)
 self.label.setPixmap(QtGui.QPixmap('mute.png'))

Wir erzeugen ein QLabel und verpassen ihm ein Anfangsbild für die Stummschaltung.

 self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)

Wir verbinden das valueChanged-Signal mit der selbst erstellten changeValue()-Methode.

 pos = self.slider.value()

Wir erhalten die Positione des Schiebreglers über den Aufruf der value()-Methode. Wir ändern das Bild des Labels entsprechend.

Regler und Label

Abbildung: Regler und Label

QProgressBar

Ein Fortschrittsbalken ist ein Widget, das verwendet wird, wenn wir länger andauernde Aufgaben bearbeiten. Er ist animiert, damit der Nutzer weiß, dass unsere Aufgabe noch verarbeitet wird. Das QProgressBar-Widget bietet einen horizontalen und einen vertikalen Fortschrittsbalken. Die Aufgabe wird in Abschnitte unterteilt. Der Programmierer kann für den Balken einen Minimal- und einen Maximalwert bestimmen. Die Standartwerte sind 0 und 99.

#!/usr/bin/python

# progressbar.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class ProgressBar(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('ProgressBar')

        self.pbar = QtGui.QProgressBar(self)
        self.pbar.setGeometry(30, 40, 200, 25)

        self.button = QtGui.QPushButton('Start', self)
        self.button.setFocusPolicy(QtCore.Qt.NoFocus)
        self.button.move(40, 80)

        self.connect(self.button, QtCore.SIGNAL('clicked()'), self.onStart)

        self.timer = QtCore.QBasicTimer()
        self.step = 0;


    def timerEvent(self, event):
        if self.step >= 100:
            self.timer.stop()
            return
        self.step = self.step + 1
        self.pbar.setValue(self.step)

    def onStart(self):
        if self.timer.isActive():
            self.timer.stop()
            self.button.setText('Start')
        else:
            self.timer.start(100, self)
            self.button.setText('Stop')


app = QtGui.QApplication(sys.argv)
icon = ProgressBar()
icon.show()
app.exec_()

In unserem Beispiel haben wir einen horizontalen Fortschrittsbalken und einen Druckknopf, der den Balken startet und stoppt.

 self.pbar = QtGui.QProgressBar(self)

QProgressBar-Konstruktor.

 self.timer = QtCore.QBasicTimer()

Um den Fortschrittsbalken zu aktivieren, verwenden wir das Timer-Objekt.

 self.timer.start(100, self)

Um das Timer-Ereignis zu auszulösen, rufen wir die start()-Methode aus. Diese Methode hat zwei Parameter: Zeitpunkt und Objekt, das die Ereignisse empfängt.

 def timerEvent(self, event):
     if self.step >= 100:
         self.timer.stop()
         return
     self.step = self.step + 1
     self.pbar.setValue(self.step)

Jedes QObject und seine Abkömmlinge verfügen über einen QObject.timerEvent-Ereignishandler. Um auf Timer-Ereignisse zu reagieren überschreiben wir den Ereignishandler.

Fortschrittsbalken

Abbildung: Fortschrittsbalken

QCalendarWidget

Das QCalendarWidget ist ein Kalender-Widget mit Monatsansicht. Es erlaubt dem Benutzer, auf einfache und intuitive Weise ein Datum auszuwählen.

#!/usr/bin/python

# calendar.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore


class Calendar(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('Calendar')

        self.cal = QtGui.QCalendarWidget(self)
        self.cal.setGridVisible(True)
        self.cal.move(20, 20)
        self.connect(self.cal, QtCore.SIGNAL('selectionChanged()'), self.showDate)


        self.label = QtGui.QLabel(self)
        date = self.cal.selectedDate()
        self.label.setText(str(date.toPyDate()))
        self.label.move(130, 260)


    def showDate(self):
        date = self.cal.selectedDate()
        self.label.setText(str(date.toPyDate()))


app = QtGui.QApplication(sys.argv)
icon = Calendar()
icon.show()
app.exec_()

Das Beispiel umfasst ein Kalender-Widget und ein Label-Widget. Das aktuelle ausgewählte Datum wird im Label-Widget angezeigt.

 self.cal = QtGui.QCalendarWidget(self)

Wir bauen ein Kalender-Widget.

 self.connect(self.cal, QtCore.SIGNAL('selectionChanged()'), self.showDate)

Wenn wir mit dem Widget ein Datum auswählen, wird dadurch ein selectionChanged()-Signal geworfen. Wir verbinden diese Methode mit der benutzerdefinierten showDate()-Methode.

 def showDate(self):
     date = self.cal.selectedDate()
     self.label.setText(str(date.toPyDate()))

Wir holen uns das gewählte Datum über Aufruf der selectedDate()-Methode. Dann wandeln wir das Datums-Objekt in einen String um und übertragen ihn an das Label-Widget.

Kalender-Widget

Abbildung: Kalender-Widget