Управление макетом в PyQt5 [Урок №4]
Изучение PyQt5 PyQt, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QTextEdit, QWidget, примеры PyQt
Существенная сторона в программировании графических приложений – управление макетом. Управление макетом – это способ, которым мы размещаем виджеты в окне приложения. Управление может быть выполнена двумя основными путями. Мы можем использовать абсолютное позиционирование или классы макета.
Абсолютное позиционирование
Программист указывает позицию и размер каждого виджета в пикселях. При использовании абсолютного позиционирования, мы должны понимать следующие ограничения:
- Размер и позиция виджета не меняются, если мы меняем размер окна
- Приложения могут выглядеть по-разному на разных платформах
- Изменение шрифтов в нашем приложении может испортить макет
- Если мы решаем изменить наш макет, мы должны полностью переделать его, что утомительно и время-затратно.
Следующий пример размещает виджеты в абсолютных координатах.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
lbl1 = QLabel('Zetcode', self)
lbl1.move(15, 10)
lbl2 = QLabel('tutorials', self)
lbl2.move(35, 40)
lbl3 = QLabel('for programmers', self)
lbl3.move(55, 70)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Absolute')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Мы используем метод move(), чтобы разместить наши виджеты. В этом случае ими являются метки. Мы размещаем их путём предоставления координат x и y. Начало координатной системы – левый верхний угол. Значения x возрастают слева направо. Значения y растут сверху вниз.
lbl1 = QLabel('Zetcode', self)
lbl1.move(15, 10)
Виджет метки расположен в x=15 и y=10.
Рисунок: абсолютное позиционирование
Блочный макет
Управление макетом с классами макета является более гибким и практичным. Это предпочтительный путь размещения виджетов в окне. QHBoxLayout и QVBoxLayout – это основные классы макета, которые выстраивают виджеты горизонтально или вертикально.
Представьте, что мы хотим разместить две кнопки в правом нижнем углу. Чтобы создать такой макет, мы будем использовать один горизонтальный и один вертикальный блок. Чтобы создать необходимое свободное пространство, мы добавим показатель растяжения.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
okButton = QPushButton("OK")
cancelButton = QPushButton("Cancel")
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('Buttons')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Пример размещает две кнопки в нижнем правом углу окна. Они остаются там, когда мы изменяем размер окна приложения. Мы можем использовать и HBoxLayout, и QVBoxLayout.
okButton = QPushButton("OK")
cancelButton = QPushButton("Cancel")
Здесь мы создаём две кнопки.
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)
Мы создаём макет горизонтального блока, добавляем показатель растяжения и обе кнопки. Растяжение добавляет растянутое свободное пространство перед двумя кнопками. Это прижмёт их к правому краю окна.
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
Чтобы создать необходимый макет, мы поставим горизонтальный макет в вертикальный. Показатель растяжения в вертикальном блоке прижмёт горизонтальный блок с кнопками к нижней части окна.
self.setLayout(vbox)
Наконец, мы устанавливаем главный макет окна.
Рисунок: Кнопки
QGridLayout
Самый универсальный класс макета – это сеточный макет. Этот макет делит пространство на строки и столбцы. Чтобы создать сеточный макет, мы используем класс QGridLayout.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, QPushButton, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
names = ['Cls', 'Bck', '', 'Close', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '0', '.', '=', '+']
positions = [(i,j) for i in range(5) for j in range(4)]
for position, name in zip(positions, names):
if name == '':
continue
button = QPushButton(name)
grid.addWidget(button, *position)
self.move(300, 150)
self.setWindowTitle('Calculator')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
В нашем примере, мы создаём сетку из кнопок. Чтобы заполнить один промежуток, мы добавляем один виджет QLabel.
grid = QGridLayout()
self.setLayout(grid)
Создаётся экземпляр QGridLayout, он назначается как макет окна приложения.
names = ['Cls', 'Bck', '', 'Close', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '0', '.', '=', '+']
Это метки, используемые в дальнейшем для кнопок.
positions = [(i,j) for i in range(5) for j in range(4)]
Мы создаём список позиций для сетки.
for position, name in zip(positions, names):
if name == '':
continue
button = QPushButton(name)
grid.addWidget(button, *position)
Используя метод addWidget, создаются и добавляются кнопки к макету.
Рисунок: Каркас калькулятора
Обзорный пример
Виджеты могут охватывать несколько столбцов и строк в сетке. В следующем примере мы продемонстрируем это.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit, QTextEdit, QGridLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
title = QLabel('Title')
author = QLabel('Author')
review = QLabel('Review')
titleEdit = QLineEdit()
authorEdit = QLineEdit()
reviewEdit = QTextEdit()
grid = 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.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Review')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Купить подписчиков в группу Телеграмма от 1,2 рублей можно только на https://doctorsmm.com/. На данном сайте представлен широкий спектр услуг по продвижению в данной социальной сети. Здесь Вы сможете найти качественные аккаунты с высоким скоростным режимом (до 1000 ед. в сутки) и большими оптовыми скидками. Все предложения действуют ограниченное время, поэтому торопитесь сделать самый выгодный заказ!
Мы создаём окно, в котором мы имеем три метки, две строки правки и один виджет редактирования текста. Макет сделан с помощью QGridLayout.
grid = QGridLayout()
grid.setSpacing(10)
Мы создаём сеточный макет и устанавливаем промежуток между виджетами.
grid.addWidget(reviewEdit, 3, 1, 5, 1)
Если мы добавляем виджет к сетке, мы можем обеспечить объединение строк и столбцов виджета. В нашем примере, мы делаем так, что виджет reviewEdit объединяет 5 строк.
Рисунок: Обзорный пример
Эта часть руководства по PyQt5 была посвящена управлению макетом.
Если у вас возникнет резонный вопрос, почему не работает gridLayout в mainwindow, а в QWidget нельзя создать меню и панель инструментов, то вот решение:
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
widget = QWidget(self)
self.setCentralWidget(widget)
grid = QGridLayout(widget)
...
grid.addWidget(Что угодно)
Мы создаем экземпляр mainwindow, а уже в нем - объект QWidget, который назначаем центральным окном.
Меню и тулбар спокойно создаются, как и раньше в самом mainwindow
...
menubar = self.menuBar()
...
self.toolbar = self.addToolBar(Что угодно)