Layoutmanagement in PyQt4
Ein wichtiges Thema beim Programmieren grafischer Oberflächen ist das Layoutmanagement, mittels dessen wir Widgets im Fenster platzieren. Das Management kann auf zwei Wege von statten gehen: Durch absolutes Positionieren oder Layout-Klassen.
Absolutes Positionieren
Der Programmierer legt die Position und die Größe jedes Widgets in Pixeln fest. Wenn Sie absolutes Positionieren anwenden, müssen Sie zuvor einige Dinge verstehen.
- Die Größe und die Position eines Widget ändern sich nicht, wenn Sie die Größe eines Fensters ändern.
- Anwendungen können sich in ihrem Aussehen abhängig von der Plattform unterscheiden.
- Veränderte Schriften können das Layout Ihrer Anwendung zerschießen.
- Entscheiden Sie sich, Ihr Layout zu ändern, müssen Sie es vollständig neu erstellen, was lästig und zeitraubend ist.
#!/usr/bin/python
# absolute.py
import sys
from PyQt4 import QtGui
class Absolute(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('Communication')
label = QtGui.QLabel('Couldn\'t', self)
label.move(15, 10)
label = QtGui.QLabel('care', self)
label.move(35, 40)
label = QtGui.QLabel('less', self)
label.move(55, 65)
label = QtGui.QLabel('And', self)
label.move(115, 65)
label = QtGui.QLabel('then', self)
label.move(135, 45)
label = QtGui.QLabel('you', self)
label.move(115, 25)
label = QtGui.QLabel('kissed', self)
label.move(145, 10)
label = QtGui.QLabel('me', self)
label.move(215, 10)
self.resize(250, 150)
app = QtGui.QApplication(sys.argv)
qb = Absolute()
qb.show()
sys.exit(app.exec_())
Wir rufen einfach die move()-Methode zur Platzierung unserer Widgets auf, in diesem Fall QLabel. Wir positionieren sie, indem wir die x- und y-Koordinaten übergeben. Der Nullpunkt des Koordinatensystems befindet sich in der linken oberen Ecke. Der x-Wert wächst von links nach rechts, der y-Wert von oben nach unten.
Abbildung: Absolutes Positionieren
Box-Layout
Das Layoutmanagement mit Hilfe von Layout-Klassen is erheblich flexibler und praktischer. Dieser Weg, Widgets in einem Fenster zu platzieren, ist der grundsätzlich vorzuziehende. Die grundlegenden Layout-Klassen sind QHBoxLayout und QVBoxLayout. Sie reihen Widgets horizontal z.B. vertikal aneinander.
Stellen Sie sich vor, wir wollten zwei Knöpfe in der rechten unteren Ecke platzieren. Um ein solches Layout zu erzeugen, werden wir eine horizontale und eine vertikale Box verwenden. Für die erforderliche Fläche fügen wir einen Ausdehnungsfaktor hinzu.
#!/usr/bin/python
# boxlayout.py
import sys
from PyQt4 import QtGui
class BoxLayout(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('box layout')
ok = QtGui.QPushButton("OK")
cancel = QtGui.QPushButton("Cancel")
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(ok)
hbox.addWidget(cancel)
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.resize(300, 150)
app = QtGui.QApplication(sys.argv)
qb = BoxLayout()
qb.show()
sys.exit(app.exec_())
ok = QtGui.QPushButton("OK")
cancel = QtGui.QPushButton("Cancel")
Hier erzeugen wir zwei Druckknöpfe.
hbox = QtGui.QHBoxLayout() hbox.addStretch(1) hbox.addWidget(ok) hbox.addWidget(cancel)
Wir erzeugen ein horizontales Box-Layout, fügen den Ausdehnungsfaktor (stretch factor) und beide Knöpfe hinzu.
vbox = QtGui.QVBoxLayout() vbox.addStretch(1) vbox.addLayout(hbox)
Zur Erzeugung des gewünschten Layouts packen wir ein horizontales Layout in ein vertikales.
self.setLayout(vbox)
Abschließend bestimmen wir das Hauptlayout des Fensters.
Abbildung: Box-Layout
QGridLayout
Die universellste Layout-Klasse ist das Rasterlayout, welches die Fläche in Reihen und Spalten einteilt. Um ein Rasterlayout zu erzeugen, verwenden wir die QGridLayout-Klasse.
#!/usr/bin/python
# gridlayout.py
import sys
from PyQt4 import QtGui
class GridLayout(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('grid layout')
names = ['Cls', 'Bck', '', 'Close', '7', '8', '9', '/',
'4', '5', '6', '*', '1', '2', '3', '-',
'0', '.', '=', '+']
grid = QtGui.QGridLayout()
j = 0
pos = [(0, 0), (0, 1), (0, 2), (0, 3),
(1, 0), (1, 1), (1, 2), (1, 3),
(2, 0), (2, 1), (2, 2), (2, 3),
(3, 0), (3, 1), (3, 2), (3, 3 ),
(4, 0), (4, 1), (4, 2), (4, 3)]
for i in names:
button = QtGui.QPushButton(i)
if j == 2:
grid.addWidget(QtGui.QLabel(''), 0, 2)
else: grid.addWidget(button, pos[j][0], pos[j][1])
j = j + 1
self.setLayout(grid)
app = QtGui.QApplication(sys.argv)
qb = GridLayout()
qb.show()
sys.exit(app.exec_())
In unserem Beispiel erzeugen wir ein Raster mit Knöpfen. Um ein Feld zu füllen, fügen wir ein QLabel-Widget ein.
grid = QtGui.QGridLayout()
Wir erzeugen hier ein Rasterlayout.
if j == 2:
grid.addWidget(QtGui.QLabel(''), 0, 2)
else: grid.addWidget(button, pos[j][0], pos[j][1])
Um ein Widget einem Raster hinzuzufügen, rufen wir die addWidget()-Methode auf. Ihre Argumente sind das Widget, dieNummer der Reihe und der Spalte.
Abbildung: Rasterlayout
Widgets können mehrere Spalten und Reihen eines Rasters umfassen. Wir werden dies im folgenden Beispiel demonstrieren.
#!/usr/bin/python
# gridlayout2.py
import sys
from PyQt4 import QtGui
class GridLayout2(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('grid layout')
title = QtGui.QLabel('Title')
author = QtGui.QLabel('Author')
review = QtGui.QLabel('Review')
titleEdit = QtGui.QLineEdit()
authorEdit = QtGui.QLineEdit()
reviewEdit = QtGui.QTextEdit()
grid = QtGui.QGridLayout()
grid.setSpacing(10)
grid.addWidget(title, 1, 0)
grid.addWidget(titleEdit, 1, 1)
grid.addWidget(author, 2, 0)
grid.addWidget(authorEdit, 2, 1)
grid.addWidget(review, 3, 0)
grid.addWidget(reviewEdit, 3, 1, 5, 1)
self.setLayout(grid)
self.resize(350, 300)
app = QtGui.QApplication(sys.argv)
qb = GridLayout2()
qb.show()
sys.exit(app.exec_())
grid = QtGui.QGridLayout() grid.setSpacing(10)
Wir erzeugen ein Rasterlayout und definieren den Abstand zwischen den Widgets.
grid.addWidget(reviewEdit, 3, 1, 5, 1)
Wenn wir ein Widget in ein Raster einfügen, können wir Reihen- und Spaltenspanne des Widgets angeben. In unserem Fall lassen wir das reviewEdit-Widget sich über 5 Reihen erstrecken.
Abbildung: Rasterlayout 2