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

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

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

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

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

Вопросы:

·     Что такое макет графического интерфейса?

·     Типы макетов используются в PyQt5.

·     Блочный макет графического интерфейса.

Рассмотрим программу для выбора цвета, которую мы описали ранее. При изменении размеров окна, размер элементов управления остаётся прежним, как и их положение. Так при минимальном размере окна элементы управления могут пропасть из виду.

Подумаем, как можно устранить недостаток, связанный с изменением размеров окна программы. Самый простой способ – это запретить пользователю изменять размеры окна. Давайте посмотрим, как это можно сделать. Откроем код нашего приложения. Как мы помним, в нём форму окна описывает класс MainWindow. Причём за настройку формы и её элементов отвечает метод setupUI.

import sys

from PyQt5.QtWidgets import *

from PyQt5.QtCore import Qt

 

class MainWindow (QWidget):

    def __init__ (self):

        super ().__init__ ()

        self.setupUI ()

 

    def setupUI (self):

        self.setGeometry (550, 400, 500, 200)

        self.setWindowTitle ('Выбор цвета')

        self.frmColor = QFrame (self)

        self.frmColor.setGeometry (310, 10, 180, 180)

        self.frmColor.setStyleSheet ('background-color: rgb(0, 0, 0)')

        self.sldRed = QSlider (Qt.Horizontal, self)

        self.sldRed.setGeometry (10, 40, 280, 20)

        self.sldRed.setRange (0, 255)

        self.lblRed = QLabel ('Красный: 0', self)

        self.lblRed.setGeometry (10, 10, 280, 20)

        self.sldGreen = QSlider (Qt.Horizontal, self)

        self.sldGreen.setGeometry (10, 100, 280, 20)

        self.sldGreen.setRange (0, 255)

        self.lblGreen = QLabel ('Зелёный: 0', self)

        self.lblGreen.setGeometry (10, 70, 280, 20)

        self.sldBlue = QSlider (Qt.Horizontal, self)

        self.sldBlue.setGeometry (10, 160, 280, 20)

        self.sldBlue.setRange (0, 255)

        self.lblBlue = QLabel ('Синий: 0', self)

        self.lblBlue.setGeometry (10, 130, 280, 20)

        self.show ()

        self.sldRed.valueChanged.connect (self.ResetColor)

        self.sldGreen.valueChanged.connect (self.ResetColor)

        self.sldBlue.valueChanged.connect (self.ResetColor)

 

    def ResetColor (self):

        r = self.sldRed.value ()

        g = self.sldGreen.value ()

        b = self.sldBlue.value ()

        self.lblRed.setText ('Красный: ' + str (r))

        self.lblGreen.setText ('Зелёный: ' + str (g))

        self.lblBlue.setText ('Синий: ' + str (b))

        self.frmColor.setStyleSheet ('background-color: rgb({0:d}, {1:d}, {2:d})'.format (r, g, b))

 

a = QApplication (sys.argv)

window = MainWindow ()

sys.exit (a.exec ())

Добавим в этот метод ещё одну строку кода. Вызовем у формы окна метод setFixedSize. Этот метод принимает на вход два целочисленных аргумента – постоянные размеры окна. Укажем их такими же, как и при вызове метода setGeometry, то есть 500 на 200 пикселей.

self.setFixedSize (500, 200)

Сохраним изменённый код модуля и запустим его на выполнение. Теперь, когда мы наведём указатель мыши на границу окна, он не примет вид двунаправленной стрелки для изменения размера окна, как раньше. Это означает, что размер окна изменить нельзя.

Запрет на изменение размера окна – это очень простое, но не всегда самое лучшее решение. Разберёмся, почему же возникает сама проблема. Дело в том, что при создании и настройке формы мы использовали абсолютное позиционирование элементов управления. Что же это означает? Когда мы вызывали метод setGeometry у элементов управления на форме, то мы задавали им конкретные числовые значения положения и размеров. Они остаются постоянными независимо от размера окна. Кроме того, абсолютное позиционирование элементов управления имеет целый ряд недостатков. Такой интерфейс приложения может по-разному выглядеть на разных платформах. Изменение шрифтов может испортить форму нашего окна. Также если мы решим переделать форму нашего приложения, то придётся изменять координаты и размеры всех элементов управления.

В качестве альтернативы абсолютному позиционированию виджетов в графической библиотеке PyQt5 используются макеты графического интерфейса. По сути, макет – это каркас графического интерфейса, который автоматически подстраивается под размеры его окна. Есть два основных типа макетов: блочный и сеточный. Сегодня мы рассмотрим блочный макет.

Для создания блочного макета графического интерфейса из библиотеки PyQt5 используется, в основном, два класса: QVBoxLayout и QHBoxLayout из модуля QtWidgets. Они позволяют расположить виджеты горизонтально или вертикально относительно друг друга. Так, объект класса QVBoxLayout – это контейнер, который заполняется виджетами сверху вниз. То есть его можно представить в виде вертикальной последовательности свободных ячеек. Новые виджеты в нём всегда помещаются в верхнюю ячейку из свободных. Размер этих ячеек автоматически изменяется в зависимости от размера виджетов и окна, в котором они размещаются.

Объект класса QHBoxLayout представляет собой такой же блок с той лишь разницей, что он располагается горизонтально и заполняется слева направо.

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

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

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

Так, главный блок можно представить объектом класса QHBoxLayout, а его левую и правую части – в виде объектов класса QVBoxLayout.

Теперь осталось описать это в программе. Прежде всего в классе MainWindow, в описании метода setupUI, нужно убрать все вызовы метода setGeometry, так как они устанавливают абсолютное позиционирование элементов управления, а также строку кода, которая устанавливает поcтоянный размер окна программы. Для программирования блочного макета интерфейса опишем отдельный метод, который назовём setForm. В этом методе, в переменной MainBox, создадим объект класса QHBoxLayout. Точно так же в переменных LBox и RBox создадим объекты класса QVBoxLayout. Теперь добавим созданные вертикальные блоки в главный. Для этого у объекта MainBox вызовем метод addLayout, в котором в качестве параметра укажем левый вертикальный блок, то есть LBox. Точно так же добавим и правый блок.

def setForm (self):

        self.frmColor.setFixedSize (180, 180)

        MainBox = QHBoxLayout ()

        LBox = QVBoxLayout ()

        RBox = QVBoxLayout ()

        MainBox.addLayout (LBox)

        MainBox.addLayout (RBox)

Теперь нужно заполнить левый и правый блоки. Начнём с правого блока. Вертикальные блоки заполняются сверху вниз. Вначале нужно добавить свободное пространство, которое будет располагаться выше квадрата цвета. Для этого у объекта RBox вызовем метод addStretch. Этот метод добавляет в блок свободное пространство. Он принимает на вход единственный числовой параметр – коэффициент растяжения этого пространства. Установим его равным единице. Теперь добавим в блок квадрат цвета. Для этого вызовем у него метод addWidget, в котором в качестве параметра укажем поле frmColor. Теперь ниже квадрата также добавим блок свободного пространства. Для этого снова вызовем у блока RBox метод addStretch. Так как этот блок свободного пространства должен быть равен первому, установим у него коэффициент растяжения также равным единице. Так как мы условились, что размер квадрата отображения цвета будет постоянным, вызовем у него метод setFixedSize и зададим постоянный размер квадрата 180´180 пикселей.

RBox.addStretch (1)

RBox.addWidget (self.frmColor)

RBox.addStretch (1)

self.frmColor.setFixedSize (180, 180)

Теперь заполним левый блок. У него в верхней части должна находиться метка, содержащая информацию о количестве красного цвета. Добавим её. Для этого вызовем у объекта RBox метод addWidget, в котором в качестве параметра укажем метку lblRed. Ниже метки точно так же добавим в блок ползунок sldRed. После того, как мы добавили в блок элементы управления для красного цвета, нужно добавить после них свободное пространство с помощью метода addStretch. Установим у него коэффициент растяжения равным единице. Теперь дважды скопируем код размещения элементов управления красным цветом, после чего изменим его соответственно для зелёного и синего цветов. После элементов управления для синего цвета свободное пространство нам не нужно. Уберём его из кода программы.

LBox.addWidget (self.lblRed)

LBox.addWidget (self.sldRed)

LBox.addStretch (1)

LBox.addWidget (self.lblGreen)

LBox.addWidget (self.sldGreen)

LBox.addStretch (1)

LBox.addWidget (self.lblBlue)

LBox.addWidget (self.sldBlue)

Таким образом мы заполнили левый и правый блоки окна программы. Теперь добавим немного свободного пространства между блоками. Для этого у блока MainBox вызовем метод setSpacing. Он задаёт расстояние между ячейками блока. Зададим расстояние в десять пикселей. Теперь нужно отобразить содержимое главного блока на форме. Для этого у формы вызовем метод setLayout, в котором в качестве параметра укажем наш главный блок. Описание метода setForm завершено. Теперь нужно добавить вызов этого метода в конце конструктора класса MainWindow.

MainBox.setSpacing (50)

self.setLayout (MainBox)

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

Мы узнали:

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

·     В графической библиотеке PyQt5 используются два основных типа макетов: блочный и сеточный.

·     Блочный макет реализован классами QHBoxLayout и QVBoxLayout. Они представляют собой горизонтальные и вертикальные последовательности ячеек для элементов управления, которые заполняются слева направо и сверху вниз соответственно.

0
1841

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

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