PyQt4 — Управление расположением виджетов

http://zetcode.com/tutorials/pyqt4/layoutmanagement/
  • Перевод
Важной частью программирования является управление расположением элементов. Управление расположением это то, как мы размещаем виджеты на форме. Тут есть два пути: использование абсолютного позиционирования (absolute positioning) или же использование классов расположения (layout classes).

Абсолютное позиционирование
Программист указывает положение и размер каждого виджета в пикселях. Когда вы используете абсолютное расположение вы должны понимать несколько вещей:
размер и положение виджета не изменяется при изменении размеров окна
приложение может выглядеть различно на разных платформах
изменение шрифта в вашем приложении может испортить расположение
если вы решаете изменить раскладку, вы должны полностью повторить её, что отнимает много времени
#!/usr/bin/python
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_())

Мы просто вызываем метод move() для изменения положения виджетов, в нашем случае это QLabel. Мы располагаем их согласно координатам X и Y. Начало системы координат находится в левом верхнем углу окна. Координата X растёт справа налево, а Y сверху вниз.
Абсолютное расположение

Box Layout (не придумал перевода)
Управление расположением с помощью классов раскладки является более гибким и практичным. Это предпочтительный способ расположения виджетов. Простые классы раскладки это QHBoxLayout и QVBoxLayout. Они располагают виджеты горизонтально и вертикально.
Представим, что мы хотим разместить две кнопки в правом нижнем углу формы. Чтобы создать такую раскладку мы будем использовать один горизонтальный и один вертикальный ящик (box). Необходимое пространство мы получим добавив фактор растяжения (stretch factor).
#!/usr/bin/python

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")

Здесь мы создаём две кнопки QPushButton.
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(ok)
hbox.addWidget(cancel)

Создаём горизонтальную раскладку и добавляем фактор растяжения для обоих кнопок.
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)

Создаём верктикальную раскладку.
self.setLayout(vbox)

И в конце устанавливаем главную раскладку для окна.
Box layout

QGridLayout
Самый универсальный класс раскладок это расположение таблицей. Эта раскладка делит пространство на строки и столбцы. Для её создания используется класс QGridLayout.

#!/usr/bin/python

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_())

В нашем примере, мы создаём таблицу кнопок. Одну ячейку оставляем пустой, добавляя один виджет QLabel.
grid = QtGui.QGridLayout()

Здесь мы создаём раскладку таблицей.
if j == 2:
    grid.addWidget(QtGui.QLabel(''), 0, 2)
else:
    grid.addWidget(button, pos[j][0], pos[j][1])

Чтобы добавить виджет в таблицу мы должны вызвать метод addWidget(), передав в качестве аргументов виджет, а также номера строки и столбца.
Табличная раскладка

Виджеты могут занимать несколько строк или столбцов и в следующем примере мы покажем это.
#!/usr/bin/python

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)

Создаём раскладку таблицей и указываем расстояние между виджетами.
grid.addWidget(reviewEdit, 3, 1, 5, 1)

Если мы добавляем виджет в раскладку, мы можем указать сколько строк или столбцов он объединяет. В нашем случае reviewEdit объединяет 5 строк.
Табличная раскладка 2
Метки:
Поделиться публикацией
Похожие публикации
Комментарии 14
  • 0
    Вы нас просто завалили отличными постами которые не хочется добавлять в закладки а хочется читать и пробовать все сразу! Спасибо!
    • 0
      Выходной выдался =)
    • 0
      Супер! Я вот настроил Qt4 под питон на маке.. Теперь пробую все =))
      • 0
        Живо напомнило Swing :) Только там больше раскладок.
        • 0
          Оу, мне бы Q'Basic вспомнить, а тут такооое!)
          • 0
            Элементарных знаний языка и ооп достаточно для работы с окошками особенно если пользоваться дизайнером интерфейсов
          • 0
            Возможно, я предвосхищаю события, но не лучше ли создавать layout в Qt Designer? Uic в PyQT уже прикрутили.

            #!/usr/bin/python
            import sys
            from PyQt4.QtGui import *
            from PyQt4.QtCore import *
            from PyQt4 import uic

            app = QApplication(sys.argv)
            widget = QWidget()
            uic.loadUi("editor.ui", widget)
            widget.show()
            app.exec_()
            • +1
              В общем, этот вопрос уже поднимался. Я с вами согласен - по мне это тоже лучший вариант, однако здесь я поставил целью донести перевод =)
              • +1
                Я вот предпочитаю генерировать код из ui файлов. Удобнее както.
              • 0
                хорошая статья. Вопрос как к специалисту Qt: у меня есть некоторый кастомизированный диалог логина. Я хочу "чтобы красиво" следующее поведение:
                человек кликает на "войти" происходит наложение полупрозрачного слоя, на котором крутится индикатор подключения к серверу.. Я гуглил на тему "qt layers", "qt transparency", но ничего не получил. Есть ли вообще что нибудь на эту тему?
                • 0
                  Есть еще довольно молодой QFormLayout - про него бы еще написали, а то черт его знает, чем он от Grid отличается.
                  • 0
                    QFormLayout - что-то типа частного случаю грида. Из названия понятно, что его можно использовать для создания форм ввода данных, поэтому у него только 2 колонки - label (описывает чего вводится) и контрол (например, эдитор). Преимущество относительно грида - простота использования:

                    formLayout = QFormLayout()
                    formLayout.addRow("&Login:", loginEdit)
                    formLayout.addRow("&Pasw:", paswEdit)
                    self.setLayout(formLayout)

                    QGridLayout'ом можно сделать тоже самое:

                    gridLayout = QGridLayout()
                    gridLayout.addWidget(QLabel('Login'), 0, 0)
                    gridLayout.addWidget(loginEdit, 0, 1)
                    gridLayout.addWidget(QLabel('Pasw'), 1, 0)
                    gridLayout.addWidget(paswEdit, 1, 1)
                    self.setLayout(gridLayout)
                    • 0
                      Мне кажется, что первый вариант просто более компактен и как раз для Форм и сделан %))
                      • 0
                        Угу, там еще вроде есть автоматическое выравнивание лэйблов для разных платформ, например, в винде - по левому краю

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.