Меню
Видеоучебник
Видеоучебник  /  Информатика  /  Основы алгоритмизации и программирования на языке Python  /  Управление макетом графического интерфейса: сеточный макет

Управление макетом графического интерфейса: сеточный макет

Урок 31. Основы алгоритмизации и программирования на языке Python

На этом уроке ученики рассмотрят ещё один тип макетов, применяющихся в графической библиотеке PyQt5, – сеточные – и принцип их работы. Также ученики узнают о политике размеров элементов управления, для чего она нужна и какой бывает.

Конспект урока "Управление макетом графического интерфейса: сеточный макет"

Вопросы:

·     Принцип работы сеточного макета.

·     Программирование сеточного макета.

·     Задание работы программы при изменении размеров её окна.

Итак, наиболее универсальным макетом графического интерфейса является сеточный макет. В графической библиотеке PyQt5 он реализован классом QGridLayout из модуля QtWidgets. В отличие от классов блочного макета, представляющих собой горизонтальный и вертикальный ряды ячеек, которые заполняются виджетами, объект этого класса представляет собой целую прямоугольную таблицу таких ячеек. Обратиться к этим ячейкам можно, указав индексы их строки и столбца. При этом, как и в случае со списками, важно помнить, что нумерация строк и столбцов начинается с нуля, а не с единицы. Один виджет в таком макете может занимать одну ячейку или же прямоугольный участок ячеек, размещающийся сразу в нескольких строках и столбцах. Заполняется сеточный макет, в отличие от блочных контейнеров, в произвольном порядке. При добавлении виджета в него, достаточно просто указать, какие ячейки этот виджет будет занимать. Размерность таблицы ячеек устанавливается объектом автоматически, в зависимости от того, какие ячейки заполнены.

Рассмотрим использование сеточного макета, создав интерфейс окна для ввода информации о пользователе. Подумаем, как должно выглядеть такое окно. Предположим, что пользователю нужно задать свою фамилию, имя, отчество, а также домашний адрес. В правой верхней части окна будут находиться три однострочных поля ввода: для фамилии, имени и отчества пользователя. Ниже этих трёх полей будет располагаться многострочное поле ввода для домашнего адреса пользователя. Слева от каждого поля ввода будет находиться метка с текстом, поясняющая, что необходимо задать в поле ввода. Под нижним полем ввода будет располагаться кнопка «Ввод».

Теперь рассмотрим, как элементы управления должны вести себя при изменении размеров окна. При горизонтальном увеличении размеров окна должны расширяться поля ввода и кнопка под ними. Остальные размеры окна должны оставаться постоянными. При вертикальном увеличении размеров окна должна увеличиваться высота поля ввода для домашнего адреса. Все остальные размеры окна должны оставаться постоянными.

Перейдём к программированию заданного интерфейса. Создав модуль в среде разработки языка Питон, мы должны описать в нём класс, который будет отвечать за работу окна, а также инструкции, необходимые для запуска приложения. Сначала загрузим в наш модуль классы, которые нам понадобятся для запуска приложения и создания интерфейса. Прежде всего подключим модуль sys. Далее из модуля QtWidgets библиотеки PyQt5 загрузим все классы. После чего из модуля QtCore загрузим класс Qt.

import sys

from PyQt5.QtWidgets import *

from PyQt5.QtCore import Qt

Создадим класс MainWindow, который унаследуем от класса QWidgets. Пока пропустим его описание. Теперь опишем основную программу. В ней, в переменной a, создадим объект класса QApplication, а в качестве параметра зададим методу-конструктору значение переменной argv из модуля sys. Далее в переменной window создадим объект класса MainWindow, после чего вызовем у созданного объекта метод show без параметров. И, наконец, из модуля sys вызовем функцию exit, которой в качестве параметра зададим метод exec, вызванный у объекта a.

class MainWindow (QWidget):

    pass       

 

a = QApplication (sys.argv)

window = MainWindow ()

window.show ()

sys.exit (a.exec ())

Теперь перейдём к описанию класса MainWindow. Создадим его метод-конструктор. В нём вызовем метод-конструктор класса-предка QWidgets. После чего вызовем методы setupUI и setForm, которые опишем далее.

def __init__ (self):

        super ().__init__ ()

        self.setupUI ()

        self.setForm ()

Опишем метод setupUI для настройки окна программы и его элементов управления. В нём зададим заголовок окна «Ввод пользовательских данных». Далее вызовем у окна метод move, который передвинет его в точку экрана с заданными координатами. Зададим точку с координатами 650 и 250. Таким образом мы создали окно программы и разместили его на экране, но пока в нём нет элементов управления. Создадим их. Начнём с поясняющих меток. В поле lblSurname создадим объект класса QLabel, то есть это будет поясняющая метка для поля «Фамилия». При создании сразу зададим текст метки: «Фамилия:». Точно так же в полях lblName, lblMiddleName и lblHomeAddress создадим поясняющие метки для полей «Имя», «Отчество» и «Домашний адрес». По умолчанию текст меток всегда выравнивается по левому краю, нам же нужно выровнять текст по правому краю. Исправим выравнивание в метке lblSurname. Для этого вызовем у неё метод setAlignment, которому в качестве параметра зададим горизонтальное выравнивание по правому краю и вертикальное по центру. Точно так же изменим выравнивание текста в метках lblName, lblMiddleName и lblHomeAddress.

def setupUI (self):

    self.setWindowTitle ('Ввод пользовательских данных')

    self.move (650, 250)

    self.lblSurname = QLabel ('Фамилия:', self)

    self.lblName = QLabel ('Имя:', self)

    self.lblMiddleName = QLabel ('Отчество:', self)

    self.lblHomeAddress = QLabel ('Домашний адрес:', self)

    self.lblSurname.setAlignment (Qt.AlignRight|Qt.AlignCenter)

    self.lblName.setAlignment (Qt.AlignRight|Qt.AlignCenter)

    self.lblMiddleName.setAlignment (Qt.AlignRight|Qt.AlignCenter)

    self.lblHomeAddress.setAlignment (Qt.AlignRight|Qt.AlignCenter)

Далее создадим поля ввода. Для этого в поле txtSurname создадим однострочное поле ввода, то есть объект класса QLineEdit. Создадим под именами txtName и txtMiddleName такие же однострочные поля ввода для имени и отчества. Для домашнего адреса нам нужно многострочное поле ввода. Чтобы его получить, создадим в поле txtHomeAddress объект класса QTextEdit. После того, как мы создали метки и поля ввода, нам осталось создать лишь кнопку «Ввод». Для этого в поле btnInput создадим объект класса QPushButton. При создании сразу зададим текст кнопки – «Ввод».

self.txtSurname = QLineEdit (self)

self.txtName = QLineEdit (self)

self.txtMiddleName = QLineEdit (self)

self.txtHomeAddress = QTextEdit (self)

self.btnInput = QPushButton ('Ввод', self)

Теперь, после того, как мы создали все элементы управления, нужно настроить их расположение на форме. Для этого опишем метод setForm. В этом методе, в переменной grid, создадим объект класса QGridLayout. После того, как мы создали контейнер для макета нашего графического интерфейса, нужно добавить в него элементы управления. Начнём с меток. Вызовем у объекта grid метод addWidget, в котором в качестве параметра зададим метку lblSurName.

В классе QGridLayout метод addWidget вызывается иначе, чем у классов блочного макета. Помимо имени виджета, в качестве параметров он принимает на вход несколько целых чисел. Это могут быть два целых числа – индексы ячейки, в которой будет располагаться соответствующий элемент управления, если он будет занимать единственную ячейку. Или же это могут быть четыре числа в том случае, когда для виджета отводится прямоугольный промежуток ячеек. Тогда первые два числа – это индексы левой верхней ячейки промежутка, который будет занят виджетом, а вторые два числа – это, соответственно, вертикальный и горизонтальный размеры этого промежутка. Они указываются количеством занимаемых ячеек.

При размещении метки lblSurname укажем ячейку из нулевой строки и нулевого столбца. Таким же образом в нулевом столбце первой, второй и третьей строк разместим соответственно метки lblName, lblMiddleName и lblHomeAddress. Теперь разместим поля ввода: txtName, txtMiddleName и txtHomeAddress — в первом столбце, в нулевой, первой и второй строках соответственно. Теперь нам нужно разместить многострочное поле ввода txtHomeAddress. Сделаем так, чтобы оно занимало одну ячейку по горизонтали и две ячейки по вертикали. Его левая верхняя ячейка будет располагаться в третьей строке и первом столбце. Поле ввода будет располагаться в двух строках и одном столбце. Теперь нужно разместить кнопку btnInput под нижним полем ввода, которое занимает третью и четвёртую строки. То есть кнопка будет находиться в пятой строке и первом столбце. Добавим между ячейками макета свободное пространство, вызвав у объекта grid метод setSpacing. Сделаем расстояние между ячейками, а также границы в десять пикселей. Теперь нужно отобразить макет на форме. Для этого у формы вызовем метод setLayout, в котором зададим объект grid в качестве параметра.

def setForm (self):

    grid = QGridLayout ()

    grid.addWidget (self.lblSurname, 0, 0)

    grid.addWidget (self.lblName, 1, 0)

    grid.addWidget (self.lblMiddleName, 2, 0)

    grid.addWidget (self.lblHomeAddress, 3, 0)

    grid.addWidget (self.txtSurname, 0, 1)

    grid.addWidget (self.txtName, 1, 1)

    grid.addWidget (self.txtMiddleName, 2, 1)

    grid.addWidget (self.txtHomeAddress, 3, 1, 2, 1)

    grid.addWidget (self.btnInput, 5, 1)

    grid.setSpacing (10)

    self.setLayout (grid)

Сохраним модуль и запустим его на выполнение. На экран было выведено окно программы, в котором размещены элементы управления. При изменении размеров окна все элементы управления ведут себя так, как и было задумано: на изменение размеров формы реагируют те элементы управления, которые должны на них реагировать.

Однако, при изменении размеров формы также можно заметить несколько недостатков. Во-первых, при минимально возможном размере формы не полностью виден её заголовок.

Чтобы это исправить, изменим минимальный размер окна. Для этого в методе setupUI добавим строку кода, которая вызывает у формы метод setMinimumSize. В этом методе зададим минимальный размер окна 350´250 пикселей.

self.setMinimumSize (350, 250)

Снова запустим модуль на выполнение. Теперь даже при минимальном размере окна его заголовок виден полностью. Однако кнопка ввода многим может показаться слишком узкой. Дело в том, что вертикальный размер кнопки по умолчанию и при изменении размера её ячейки остаётся постоянным, равным минимальному. Поэтому изменим минимальный размер кнопки. Сделаем его 100´30. Горизонтальный размер кнопки не очень важен, так как он зависит от ширины окна программы, а вертикальный размер кнопки теперь будет равен тридцати пикселям.

self.btnInput.setMinimumSize (100, 30)

Сохраним модуль и запустим его на выполнение. Теперь кнопка ввода стала шире. Однако у нашей формы остался ещё один недостаток: текст метки для домашнего адреса расположен ниже относительно своего поля ввода по сравнению с остальными метками, а также при увеличении вертикального размера окна текст этой метки смещается вниз.

Дело в политике размеров. Она описывает поведение элементов управления в ячейках макетов при изменении их размеров и хранится в классе QSizePolicy модуля QtWidgets. По умолчанию у каждого класса виджетов она своя. Так, отдельно может быть установлена политика вертикального и горизонтального размеров. У неё может быть одно из семи значений: игнорируемый размер – Ignored, фиксированный размер – Fixed, предпочтительный размер – Preferred, минимальный размер – Minimum, максимальный размер – Maximum, минимально расширяемый размер – MinimumExpanding и расширяемый размер – Expanding. Так, фиксированный размер элемента управления не изменяется при изменении размеров окна. При предпочтительном размере элемент управления принимает размер ячейки, в которой он находится. Вы можете самостоятельно рассмотреть поведение элементов управления при других значениях политики размеров. Пока важно лишь то, что значение этой политики мы можем задать самостоятельно.

По умолчанию у метки установлен предпочтительный вертикальной размер, а выравнивание текста мы установили по центру. Изменим политику размеров метки lblHomeAddress, вызвав у неё метод setSizePolicy. Зададим у неё предпочтительный горизонтальный размер Preferred и фиксированный вертикальный – Fixed. Снова запустим модуль на выполнение. На этот раз форма выглядит и ведёт себя при изменении размеров точно так же, как было задумано изначально. Задача решена.

self.lblHomeAddress.setSizePolicy (QSizePolicy.Preferred, QSizePolicy.Fixed)

Помимо управления размерами и положением виджетов, при изменении размеров окна иногда требуется делать что-то ещё. Для этого нужно обратиться к событию изменения размеров окна. Чтобы это сделать в классе, который описывает окно программы, необходимо переопределить метод resizeEvent, описанный у его предка QWidgets. Этот метод срабатывает при изменении размеров окна. Сделаем так, чтобы при изменении размеров окна, его размеры выводились на экран. Для этого запишем инструкцию print, которая будет выводить на экран результаты методов width и height, вызванных у формы, разделённые точкой с запятой.

def resizeEvent (self, event):

    print (self.width (), '; ', self.height (), sep = '')

Запустим модуль на выполнение. И попытаемся изменить размеры окна. При этом его размеры выводятся на экран.

Мы узнали:

·     Cеточный макет графического интерфейса реализован классом QGridLayout. Объект этого класса представляет собой прямоугольную таблицу ячеек, которые заполняются виджетами. При этом виджет может занимать как одну ячейку таблицы, так и прямоугольный промежуток ячеек.

·     Политика размеров определяет поведение элементов управления графическим интерфейсом при изменении размеров ячеек, в которых они находятся.

·     Метод resizeEvent описывает работу программы при изменении размеров её окна.

0
1650

Комментарии 0

Чтобы добавить комментарий зарегистрируйтесь или на сайт