GUI QT6

QT6 + оглавление

Платная лицензия Похоже надо углубиться в лицензирование opensource.

Страницы компонентов

Label Push button Radio button
Line edit Check box SpinBox
QLCD ComboBox Slider
ListWidget Table Calendar
ColorDialog FontDialog MessageBox
Dialogs (save)

Установка: 

pip install pyqt6
pip install pyqt6-tools

Минимальное приложение: 

from PyQt6.QtWidgets import QApplication, QWidget
import sys

app = QApplication(sys.argv)
window = QWidget()
window.show()
sys.exit(app.exec())

Архитектура QT прячется под стандартную, но это не так. QT основывается на цикле событий, внутри реализованы используемые системные процедуры (таймер, ...), и приходится использовать соответствующие QT-модули, а не системные модули. Поэтому в составе QT много модулей. 

Модуль Назначение
QtWidgets

Основной и шаблонные виджеты (окно, метка, ...)

QtGui

Классы для интеграции с оконной системой, обработки событий, 2D-графики, базовых изображений, шрифтов, иконок и текста. 

 

QIcon класс работы с иконками

QtCore

Системные модули.

Типы окон

QMainWindow Главное окно приложения и связанные с ним классы для управления главным окном. 

from PyQt6.QtWidgets import QApplication, QMainWindow
import sys

app = QApplication(sys.argv)
window = QMainWindow()
window.statusBar().showMessage("Welcome to pyqt6 coding")
window.show()
sys.exit(app.exec())

QMainWindow имеет свой собственный макет, содержащий QToolBars, QDockWidgets, QMenuBar и QStatusBar.

QDialog Базовый класс окна верхнего уровня, используемое для краткосрочных задач и краткого общения с пользователем. 
QDialogs может быть модальным или немодальным.

QWidget Базовый класс всех объектов пользовательского интерфейса, получает мышь, клавиатуру и другие события
из оконной системы и отображает свое изображение на экране.

Объектно-ориентированный подход настройки окна

Создаем класс-потомок например от QWidget или QMainWindow, настраиваем свойства и 

from PyQt6.QtWidgets import QApplication, QWidget 
from PyQt6.QtGui import QIcon 
import sys 
 
class Window(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.setGeometry(200,200, 700, 400) 
        self.setWindowTitle("Python GUI Development") 
        self.setWindowIcon(QIcon('pyqt6lessons\images\python.png')) 
        self.setStyleSheet('background-color:green') 
        self.setWindowOpacity(0.5) 
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec()) 

Управление событиями

Основной элемент всех приложений в Qt — класс QApplication. Каждому приложению нужен только один объект QApplication, который содержит цикл событий приложения. Это основной цикл, управляющий всем взаимодействием пользователя с графическим интерфейсом. 

изображение.png

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

Класс QApplication содержит цикл событий Qt (нужен один экземпляр QApplication). Приложение ждёт в цикле событий новое событие, которое будет сгенерировано при выполнении действия. Всегда выполняется только один цикл событий.

Сигналы — уведомления, отправляемые виджетами, когда что-то происходит. Это может быть нажатие кнопки, изменение текста в поле ввода, изменение текста в окне, ... Многие сигналы инициируются в ответ на действия пользователя, но не только: в сигналах могут отправляться данные с дополнительным контекстом произошедшего.

Слоты — приёмники сигналов. Слотом можно сделать любую функцию (или метод), просто подключив к нему сигнал. Принимающая функция получает данные, отправляемые ей в сигнале. У многих виджетов Qt есть встроенные слоты, эти виджеты можно подключать друг к другу напрямую.

class Window(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.setGeometry(200,200, 700, 400) 
        self.setWindowTitle("Python GUI Development") 
        self.create_button()

    def create_button(self):
        btn = QPushButton("Click", self)
        btn.clicked.connect(self.the_button_was_clicked)

    def the_button_was_clicked(self):
        print("Clicked")

Соединение сигнала и слота происходит в функции btn.clicked.connect(self.the_button_was_clicked) Таблицы событий:

Мышь:

Тип Описание
MouseButtonPress Нажата кнопка мыши
MouseButtonRelease Отпущена кнопка мыши
MouseButtonDblClick Двойной клик
MouseMove Движение мыши
Wheel Колёсико мыши
Enter Курсор вошёл в виджет
Leave Курсор покинул виджет
HoverEnter Hover вошёл
HoverMove Hover движение
HoverLeave Hover вышел

Клавиатура:

Тип Описание
KeyPress Нажата клавиша
KeyRelease Отпущена клавиша
Shortcut Сработал shortcut
ShortcutOverride Попытка перехвата shortcut
InputMethod IME ввод
InputMethodQuery Запрос IME

Фокус и активация

Тип Описание
FocusIn Получен фокус
FocusOut Потерян фокус
ActivationChange Изменение активности окна

Окна и виджеты

Тип Описание
Show Виджет показан
Hide Виджет скрыт
Close Закрытие
Resize Изменение размера
Move Перемещение
Paint Перерисовка
LayoutRequest Запрос layout
UpdateRequest Запрос обновления
Polish Финальная инициализация
PolishRequest Запрос polish
ParentChange Изменился родитель
ParentAboutToChange Родитель изменится
WindowStateChange Изменение состояния окна
WindowActivate Окно активировано
WindowDeactivate Окно деактивировано
WindowTitleChange Заголовок окна
WindowIconChange Иконка окна
WindowBlocked Окно заблокировано
WindowUnblocked Окно разблокировано

Геометрия и экран

Тип Описание
ScreenChangeInternal Изменился экран
ScreenChangeInternal DPI/Screen изменился
OrientationChange Смена ориентации
DevicePixelRatioChange Изменение DPR

Drag & Drop

Тип Описание
DragEnter Drag вошёл
DragMove Drag перемещение
DragLeave Drag покинул
Drop Drop

Буфер обмена

Тип Описание
Clipboard Изменился буфер обмена

Таймеры

Тип Описание
Timer Сработал таймер
ZeroTimerEvent Таймер с нулевой задержкой

Touch / Tablet / Gesture

Тип Описание
TouchBegin Touch начало
TouchUpdate Touch обновление
TouchEnd Touch конец
TabletPress Перо нажато
TabletMove Перо движение
TabletRelease Перо отпущено
Gesture Жест
GestureOverride Перехват жеста

Состояние

Тип Описание
EnabledChange Изменение enabled
FontChange Изменение шрифта
StyleChange Изменение стиля
PaletteChange Изменение палитры
LanguageChange Смена языка
LocaleChange Смена локали
ThemeChange Смена темы
ApplicationStateChange Состояние приложения

Продвинутые опции

Тип Описание
DynamicPropertyChange Изменение свойства
ChildAdded Добавлен ребёнок
ChildRemoved Удалён ребёнок
ChildPolished Ребёнок отполирован
MetaCall Вызов meta-object
ThreadChange Смена потока
DeferredDelete Отложенное удаление
Quit Завершение приложения
PlatformSurface Изменение поверхности
PlatformPanel Platform panel
User Начало пользовательских событий

Пользовательские события

Тип Описание
User Базовый пользовательский event
MaxUser Максимальный ID

event = QEvent(QEvent.Type.User)
QCoreApplication.postEvent(obj, event)

Поиск событий:

def event(self, event):
    print(event.type())
    return super().event(event)

#или
widget.installEventFilter(self)

def eventFilter(self, obj, event):
    print(obj, event.type())
    return False

QT6Core

QTime класс управления / работы со временем. 

time = QTime.currentTime()
text = time.toString('hh:mm')

QTimer класс тайминга. Настраивается при инициализации класса. 

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(200,200, 700, 400)
        self.setWindowTitle("Python GUI Development")

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_lcd)
        self.timer.start(1000)

        self.create_button()

 

 

 

QT6 настройка окна

Компоновщики (Layouts).

Нужны для автоматического упорядочивания и изменения размеров виджетов при изменении размера окна. Без Layouts виджеты имеют фиксированные позиции и размеры. Импортируются все типы компоновщиков через 

from PyQt6.QtWidgets import QHBoxLayout

Типы Layouts в Qt Designer 

Vertical Layout (Вертикальный компоновщик) Располагает виджеты сверху вниз в столбик. 
layout = QVBoxLayout()
layout.addWidget(button1)
layout.addWidget(button2)
Horizontal Layout (Горизонтальный компоновщик) Располагает виджеты слева направо в строку. 
QHBoxLayout()
Grid Layout (Сеточный компоновщик) Располагает виджеты в таблице (строках и столбцах). 
layout = QGridLayout()
layout.addWidget(button1, 0, 0)  # строка 0, столбец 0
layout.addWidget(button2, 0, 1)  # строка 0, столбец 1
Form Layout (Формовый компоновщик) Идеален для форм (метка + поле ввода).
Располагает виджеты в две колонки: labels слева, поля справа. 
QFormLayout()

 

class Window(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.setGeometry(200,200, 700, 400) 
        self.mainlayout = QVBoxLayout()

        bt1 = QPushButton("one")
        bt2 = QPushButton("two")
        bt3 = QPushButton("three")
        bt4 = QPushButton("four")

        self.mainlayout.addWidget(bt1)
        self.mainlayout.addWidget(bt2)
        self.mainlayout.addWidget(bt3)
        self.mainlayout.addWidget(bt4)

        self.setLayout(self.mainlayout)

 

Базовый подход:

Вложенные Layouts:

Main Vertical Layout
├── Horizontal Layout (для кнопок)
│   ├── Кнопка "Открыть"
│   ├── Кнопка "Сохранить"
│   └── Кнопка "Выход"
└── Text Edit (занимает оставшееся пространство)

Еще класс, просто для примера. Соотношение 1:2

class Window(QWidget): 
    '''
    Вложенные Layout
    '''
    def __init__(self): 
        super().__init__() 
        self.setGeometry(200,200, 700, 400) 
        self.setWindowTitle("Python GUI Development") 
        self.mainlayout = QVBoxLayout()

        lbl1 = QLabel("one label")
        lbl2 = QLabel("two label")

        bt1 = QPushButton("one")
        bt2 = QPushButton("two")

        self.innerlayout1 = QHBoxLayout()
        self.innerlayout1.addWidget(lbl1, stretch=1)
        self.innerlayout1.addWidget(bt1,stretch=2)
        self.mainlayout.addLayout(self.innerlayout1)

        self.innerlayout2 = QHBoxLayout()
        self.innerlayout2.addWidget(lbl2, stretch=1)
        self.innerlayout2.addWidget(bt2,stretch=2)
        self.mainlayout.addLayout(self.innerlayout2)

        self.setLayout(self.mainlayout)

Растяжения (Stretch):

В коде: layout.addStretch()
В Designer: есть специальный виджет "Horizontal Spacer" / "Vertical Spacer"

Выравнивание: В Property Editor настраивается

self.mainlayout.addSpacing(100)

Пожелания при использовании Layouts

Stretch Factors

Stretch factor — числовое значение, определяющее пропорцию, в которой виджеты делят доступное пространство при растяжении окна.

Базовые принципы:

Настройка при создании

Способ 1: Панель свойств (Property Editor)

изображение.png

В данном примере первая кнопка не будет менять размеры, вторая будет занимать 20% от оставшегося свободного места, третья 80%.

Способ 2:Через свойства виджетов внутри Layout

У каждого виджета есть свойство sizePolicy → horizontalStretch / verticalStretch

Способ 3: Через код 

# при добавлении нового виджета
self.mainlayout.addWidget(bt1, stretch=1)
self.mainlayout.addWidget(bt2, stretch=3)
self.mainlayout.addWidget(bt3, stretch=0)
self.mainlayout.addWidget(bt4, stretch=5)

Настройка после создания

Способ 1: Использовать setStretch(index, stretch)

# Предположим, у вас уже есть Layout с виджетами
self.mainlayout.addWidget(bt1, stretch=1)
self.mainlayout.addWidget(bt2, stretch=3) 
self.mainlayout.addWidget(bt3, stretch=0)
self.mainlayout.addWidget(bt4, stretch=5)

# Позже меняем stretch для bt4 (индекс 3, так как индексы начинаются с 0)
self.mainlayout.setStretch(3, 2)  # Меняем с 5 на 2

Способ 2: Получить индекс виджета динамически

# Находим индекс виджета bt4 в Layout
index = self.mainlayout.indexOf(bt4)
if index != -1:  # -1 означает "не найден"
    self.mainlayout.setStretch(index, 2)

Способ 3: Пересоздать Layout (более кардинальный)

# Удаляем все виджеты из Layout
while self.mainlayout.count():
    item = self.mainlayout.takeAt(0)
    if item.widget():
        item.widget().hide()

# Добавляем заново с новыми stretch factors
self.mainlayout.addWidget(bt1, stretch=1)
self.mainlayout.addWidget(bt2, stretch=3)
self.mainlayout.addWidget(bt3, stretch=0)
self.mainlayout.addWidget(bt4, stretch=2)  # Новое значение!

Способ 4: Изменить через setSizePolicy виджета. 

# Получаем текущую политику размеров
policy = bt4.sizePolicy()

# Устанавливаем горизонтальный/вертикальный stretch
policy.setHorizontalStretch(2)  # Для Horizontal Layout
policy.setVerticalStretch(2)    # Для Vertical Layout

bt4.setSizePolicy(policy)
bt4.update()  # Обновляем виджет

Важно: Этот метод влияет на поведение виджета во всех Layout, где он находится!

Способ 5: Временное отключение обновления для избежания мерцания при изменении:

# Блокируем обновление
self.setUpdatesEnabled(False)

# Меняем stretch
index = self.mainlayout.indexOf(bt4)
self.mainlayout.setStretch(index, 2)

# Включаем обновление и форсируем перерасчет
self.setUpdatesEnabled(True)
self.mainlayout.invalidate()  # Помечаем Layout как невалидный
self.mainlayout.activate()    # Принудительно пересчитываем

Особенности работы:

Проверка текущих значений:

# Получить текущий stretch factor
current_stretch = self.mainlayout.stretch(3)  # Для индекса 3
print(f"Текущий stretch: {current_stretch}")

# Получить список всех stretch factors
for i in range(self.mainlayout.count()):
    widget = self.mainlayout.itemAt(i).widget()
    stretch = self.mainlayout.stretch(i)
    if widget:
        print(f"Индекс {i}: {widget.text()} - stretch={stretch}")

 

Класс окна

Для управления классом окна, класс создается, затем настраиваются нужные свойства

from PyQt6.QtWidgets import QApplication, QWidget 
from PyQt6.QtGui import QIcon 
import sys 
 
class Window(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.setGeometry(200,200, 700, 400) 
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec())

Свойства:

         
        self.setWindowIcon(QIcon('pyqt6lessons\images\python.png')) 
        self.setStyleSheet('background-color:green') 
        self.setWindowOpacity(0.5) 

Свойство Применение
Размеры окна

self.setGeometry(x,y, height, width)

self.setGeometry(200,200, 700, 400)

Заголовок окна self.setWindowTitle("Python GUI Development")






QT6 desiner

Устанавливается при установке pyqt6-tools

У меня вызвался обычной командой 

(myenv) D:\projects\calclulator_long>pyside6-designer.exe

Типы создаваемых окон:

Различаются родительским классом и наличием дополнительных виджетов (кнопки, ...)

Предпросмотр результата

Блок меню Form - Preview... очень занимательный. 

изображение.png

QT использует стили операционных систем, поэтому вид будет отличаться на разных ОС.  

Слои (Layouts)

Настраивается отдельно тип для всей формы и для группы элементов. 

Настройка для группы элементов: выделяются виджеты, ПКМ - Lay Out - Нужный тип.

image.png

Для всей формы: ПКМ на пустом месте формы - Lay Out - Нужный тип.

image.png

Использование .ui файла

Использование в скрипте

Два варианта: преобразование в py файл и загрузка в py скрипт ui-файла во время выполнения.

Преобразование в python файл:

(myenv) D:\projects\calclulator_long>pyuic6 -x testui.ui -o testuicreated.py

После этого запуск *,py файла откроет пользовательский интерфейс. При изменении *.ui файла необходимо обновить файл исходного кода и связанных процедур.

Загрузка ui файла во время выполнения

from PyQt6.QtWidgets import QApplication, QWidget 
import sys 
from PyQt6 import uic 
 
class UI(QWidget): 
    def __init__(self): 
        super().__init__() 
        uic.loadUi("WindowUI.ui", self) 
 
app = QApplication(sys.argv) 
window = UI() 
window.show() 
app.exec()

Доступ к виджетам внутри .ui файла

Для дальнейшего доступа к виджетам из py скрипта необходимо знать тип виджета и имя объекта. Например, есть виджет типа QLineEdit, имя объекта lineEdit_price.

image.png

Создадим свойство объекта через FindChild

class UI(QWidget): 
    def __init__(self): 
        super().__init__() 
        uic.loadUi("double_spin.ui", self)

        self.linePrice = self.findChild(QLineEdit, "lineEdit_price")

Дальше с этим свойством работать также как с созданным объектом. Пример: 

lass UI(QWidget): 
    def __init__(self): 
        super().__init__() 
        uic.loadUi("double_spin.ui", self)

        self.linePrice = self.findChild(QLineEdit, "lineEdit_price")
        self.doublespin = self.findChild(QDoubleSpinBox, "doubleSpinBox")
        self.doublespin.valueChanged.connect(self.spin_selected)
        self.lineresult = self.findChild(QLineEdit, "lineEdit_total")

    def spin_selected(self):
        if self.linePrice.text() != 0:
            price = int(self.linePrice.text())
            totalPrice = self.doublespin.value() * price
            self.lineresult.setText(str(totalPrice))

Соединение действий виджетов

Функционал урезан. Нажать кнопку Edit signals/slots 

image.png

При наведении мыши виджет становится красным. Если нажать виджет, с которого сигнал будет исходить и, удерживая мышь, переместить указатель на виджет, на который будет влиять сигнал, появится стрелка и элемент выбора сигналов/слотов. 

image.png

Нужно установить флажок внизу. Выбирается сигнал, слот и все работает даже на превью. 

image.png

QT6 QLabel, LCD

QLabel

Класс QLabel используется для отображения сообщений и изображений, 

from PyQt6.QtWidgets import QApplication, QWidget, QLabel
import sys 
 
class Window(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.setGeometry(200,200, 700, 400) 
        self.setWindowTitle("Python GUI Development") 
        label = QLabel("", self)
        label.setText('first text in label')
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec())

Для создания метки с изображением текст не передается 

label = QLabel(self)

Таблица методов:

Метод Назначение
setText() Устанавливается новый текст метки
setNum() добавляет целое или двойное значение
clear() удаляет текст
setMovie()

установки изображения gif

movie = QMovie('images/sky.gif') 
movie.setSpeed(500) 
label.setMovie(movie) 
movie.start()

setFont() Изменения шрифта, setFont() ожидает класс QFont, (потомок QtGui) 
label.setFont(QFont("Sanserif", 15))
label.setStyleSheet()

Изменение цвета шрифта

label.setStyleSheet('color:red')

Добавление изображения


setPixamp() pixmap = QPixmap('images/python.png') 
label.setPixmap(pixmap) 
QImage, QBitmap QPicture

QLCDNumber

Класс для отображения 7-сегментного дисплея, отображает 5 (пять) 8- 10- 16- ричных элементов. 

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(200,200, 700, 400)
        self.setWindowTitle("Python GUI Development")

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_lcd)
        self.timer.start(1000)

        self.create_button()

    def create_button(self):
        vbox = QVBoxLayout()

        self.lcd = QLCDNumber()
        self.lcd.setStyleSheet('background:red')

        vbox.addWidget(self.lcd)

        time = QTime.currentTime()
        text = time.toString('hh:mm')

        self.lcd.display(text)
        self.setLayout(vbox)

    def update_lcd(self):
        time = QTime.currentTime()
        text = time.toString('hh:mm')
        self.lcd.display(text)

 

QT6 Buttons

QPushButtons

Командная кнопка является наиболее часто используемым виджетом в любом графическом интерфейсе пользователя. Нажатие (click) кнопки является командой компьютеру выполнить какое-либо действие. Типичными кнопками являются "ОК", "Применить", "Отмена", "Закрыть".,  Да, Нет и Справка. 
Командная кнопка имеет прямоугольную форму и обычно отображает текстовую метку, описывающую ее действие. Можно указать комбинацию клавиш, указав перед нужным символом амперсанд в тексте. 
чтобы отобразить кнопку в приложении, вам необходимо создать экземпляр класса QPushButton. 

from PyQt6.QtWidgets import QApplication, QWidget, QPushButton
import sys 
 
class Window(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.setGeometry(200,200, 700, 400) 
        self.setWindowTitle("Python GUI Development") 
        self.create_button()

    def create_button(self):
        btn = QPushButton("Click", self)
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec())

Методы класса:

Метод Описание
setText() Изменение текста
setIcon()

Добавление иконки на кнопку

btn.setIcon(QIcon("images/python.png")) 


Изменение размера иконки

from PyQt6.QtCore import QSize
from PyQt6.QtGui import QIcon 

    def create_button(self):
        btn = QPushButton("Click", self)
        btn.setGeometry(100, 100, 130, 50)
        btn.setIcon(QIcon('pyqt6lessons\images\python.png'))
        btn.setIconSize(QSize(36,36))

 

setGeometry() Настройка положения кнопки, 
setMenu()

Всплывающее меню над кнопкой. Сначала создать объект QMenu, класс QMenu связан с модулем QtWidgets, класс QMenu предоставляет виджет меню для использования в строках меню, контекстных меню и других всплывающих меню. 
Виджет меню - это меню выбора. Это может быть как выпадающее меню в строке меню, так и отдельное контекстное меню. Выпадающие меню отображаются в строке меню, когда пользователь щелкает на соответствующем элементе или нажимает указанную комбинацию клавиш. 

menu = QMenu() 
menu.setFont(QFont("Times", 14, 
QFont.Weight.ExtraBold)) 
menu.setStyleSheet('background-color:green') 
menu.addAction("Copy") 
menu.addAction("Cut") 
menu.addAction("Paste") 
btn.setMenu(menu) 

 изображение.png

setFont()

Настройка шрифта

btn.setFont(QFont("Times", 14, QFont.Weight.ExtraBold))

setCheckable()

Вид кнопки при нажатии меняется. Выделяется и снимается выделение.

QRadioButtons

Кнопка, которую можно включить (установить флажок) или выключить (снять флажок). Переключатели обычно предоставляют
пользователю возможность выбора "из многих". В группе переключателей одновременно может быть установлен только один переключатель, если пользователь выбирает другую кнопку, ранее выбранная кнопка отключается. Существуют различные методы, которые вы можете использовать, например, у нас есть IsChecked(), и он возвращает логическое значение true, если кнопка находится в выбранном состоянии, или у нас есть метод setIcon(), с помощью которого мы можем добавить значок для радиокнопки, а также setText(), который задает текст выбранной кнопки. Также существуют различные сигналы, которые вы можете использовать, например, у нас есть переключаемый сигнал, который используется всякий раз, когда переключатель меняет свое состояние с установленного на снятое и наоборот. 

RadioButtons объединенные в одном hbox рассматриваются как зависимые.

from PyQt6.QtWidgets import QApplication, QWidget, QHBoxLayout, QRadioButton, QLabel
from PyQt6.QtWidgets import QVBoxLayout
import sys 
 
class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(200,200, 700, 400)
        self.setWindowTitle("Python GUI Development")
        self.create_button()

    def create_button(self):
        hbox = QHBoxLayout()

        self.label = QLabel("", self)
        vbox = QVBoxLayout()
        vbox.addWidget(self.label)
        vbox.addLayout(hbox)

        rad1 = QRadioButton("Python")
        rad1.toggled.connect(self.radio_selected)
        hbox.addWidget(rad1)
        rad2 = QRadioButton("Java")
        rad2.toggled.connect(self.radio_selected)
        hbox.addWidget(rad2)
        rad3 = QRadioButton("JavaScript")
        rad3.toggled.connect(self.radio_selected)
        hbox.addWidget(rad3)

        self.setLayout(vbox)

    def radio_selected(self):
        radio_btn = self.sender()
        if radio_btn.isChecked():
            self.label.setText(f'Selected: {radio_btn.text()}')

app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())

Методы класса:

Метод Описание
isChecked() Возвращает True если кнопка выбрана
setChecked() Переводит кнопку в выбранное состояние
setIcon() Устанавливает иконку кнопки
setText() Текст

QT6 QLineEdit

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


Методы:

Метод Назначение
setEchoMode()

Режим эхо. Варианты:

  • Normal: все введенные символы отображаются
  • NoEcho: ни один введенный символ не отображается
  • Password: вместо символов выводится звездочка
  • PasswordEchoOnEdit: При редактировании полей пароля отображается фактический текст, в противном случае текст будет помечен звездочками
setFont() Настройка шрифта
maxLength() Максимальная длина текста
setText() Устанавливает текст
text() Получает текст
clear() Очищает строку ввода
setReadOnly() Установка режима только для чтения
setEnabled() Доступность компонента пользователю
setFocus() Установить фокус
setPlaceholderText() Текст когда поле пустое

 

 

QT6 CheckBox, SpinBox, ComboBox

QCheckbox

Это кнопка выбора, которую можно включить (установить флажок) или выключить (снять флажок). Флажки обычно  используются для обозначения функций в приложении, которые можно включать или отключать, не затрагивая другие. При изменении состояния флажка выдается сигнал StateChanged(). Метод IsChecked() используется для запроса, установлен ли флажок. 

Методы: 

Метод Описание
isChecked()
setIcon()
setText()
setChecked()

Сигналы:

stateChanged

QSpinbox

QSpinBox предназначен для обработки целых чисел и дискретных наборов значений, позволяет выбирать значение, нажимая кнопки вверх / вниз или нажимая клавиши вверх / вниз на клавиатуре, чтобы увеличить / уменьшить отображаемое в данный момент значение. Также возможно ввести значение вручную. 

Методы: 

Метод Описание
value() текущее выбранное целое значение
text() отображения текста в окне прокрутки

setMinimum()


setMaximum()
setPrefix() текстовый префикс, добавляемый перед значением, возвращаемым полем прокрутки. 
setSuffix() текст суффикса, добавляемый к значению, возвращаемому блоком spin.

Сигналы:

valueChanged()

editingFinished() выдается при потере фокуса на spinbox. Предполагаю, актуально для приложений с web backend при передаче финальных данных.

from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QLineEdit
from PyQt6.QtWidgets import QSpinBox
import sys 
 
class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(200,200, 700, 400)
        self.setWindowTitle("Python GUI Development")
        self.create_button()

    def create_button(self):
        hbox = QHBoxLayout()
        label = QLabel("Laptop price: ")
        self.lineedit = QLineEdit()
        self.spinbox = QSpinBox()
        self.spinbox.valueChanged.connect(self.spin_selected)

        self.total_result = QLineEdit()

        hbox.addWidget(label)
        hbox.addWidget(self.lineedit)
        hbox.addWidget(self.spinbox)
        hbox.addWidget(self.total_result)
        self.setLayout(hbox)

    def spin_selected(self):
        if self.lineedit.text() != 0:
            price = int(self.lineedit.text())
            totalPrice = self.spinbox.value() * price
            self.total_result.setText(str(totalPrice))
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec())

QComboBox

Виджет выбора, отображающий текущий элемент. Также отображает список выбираемых элементов. Может быть редактируемым.

Также есть специализированный ComboBox: для выбора шрифтов (fontComboBox). 

Методы: 

Метод Описание
setItemText() Устанавливает или изменяет текст элемента в поле со списком. 
removeItem() Удаляет определенный элемент из поля со списком. 
clear() Удаляет все элементы из поля со списком.
currentText() Возвращает текст текущего элемента, то есть элемента, который выбран в данный момент. 
setCurrentIndex() Устанавливает текущий индекс поля со списком, то есть задает желаемый элемент в поле со списком в качестве выбранного в данный момент элемента. 
count() Возвращает количество элементов в поле со списком. 
setEditable() Сделайте поле со списком доступным для редактирования, то есть пользователь можно редактировать элементы в поле со списком. 
addItem() Добавляет указанное содержимое в поле со списком. 
itemText() Возвращает текст в указанное расположение индекса в поле со списком.
currentIndex() Возвращает индексное местоположение текущего выбранного элемента в поле со списком. Если поле со списком пусто или в поле со списком в данный момент не выбран ни один элемент, метод вернет значение -1 в качестве индекса.

Сигналы

currentIndexChanged() выбор нового элемента

editTextChanged() изменение текста в редактируемом комбобоксе

from PyQt6.QtWidgets import QApplication, QWidget, QComboBox, QLabel, QHBoxLayout, QVBoxLayout
import sys 
 
class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(200,200, 700, 400)
        self.setWindowTitle("Python GUI Development")
        self.create_button()

    def create_button(self):
        hbox = QHBoxLayout()
        label = QLabel('Select type: ')
        self.combo = QComboBox()
        self.combo.addItem('')
        self.combo.addItem('Current account')
        self.combo.addItem('Deposite account')
        self.combo.addItem('Saving account')
        self.combo.currentTextChanged.connect(self.updresult)
        hbox.addWidget(label)
        hbox.addWidget(self.combo)
        
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)

        self.label_result = QLabel('')
        vbox.addWidget(self.label_result)
        
        self.setLayout(vbox)

    def updresult(self):
        self.label_result.setText('Your type: ' + self.combo.currentText())
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec())

QT6 QSlider, QListWidget

QSlider

Ползунок - виджет управления ограниченным значением. Позволяет перемещать ручку ползунка и преобразовывать положение ручки в целое значение в допустимом диапазоне. 

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

self.slider.setOrientation(Qt.Orientation.Horizontal)

Настройка положения галочки ползунка 

self.slider.setTickPosition(QSlider.TickPosition.TicksAbove)

Интервал шага 

self.slider.setTickInterval(5)

Границы диапазона 

self.slider.setMinimum(0) 
self.slider.setMaximum(100) 

Методы

Метод Назначение
minimum() возвращает минимальное значение ползунка
maximum() возвращает максимальное значение ползунка
setValue() используется для установки значения ползунка

Сигналы

Сигнал Назначение
valueChanged() подается при перемещении ручки ползунка
sliderPressed() подается, когда пользователь начинает перетаскивать ручку ползунка. 
sliderMoved() подается, когда пользователь перемещает ручку ползунка.
sliderReleased() подается, когда пользователь отпускает ручку ползунка

QListWidget

QListWidget - представление списка, аналогичное QListView, но с классическим интерфейсом на основе элементов для добавления и удаления элементов. QListWidget использует внутреннюю модель для управления удалением элементов. QListWidget использует внутреннюю модель для управления каждым QListWidgetItem в списке.

Методы

Метод Назначение
insertItem() вставляет новый элемент в виджет списка в указанном месте. 
insertItems() вставляет несколько элементов из предоставленного списка, начиная с указанного места 
count() возвращает количество элементов в списке. 
takeItem() удаляет и возвращает элементы из указанной строки
CurrentItem() возвращает текущий элемент в списке
addItem() добавляет элемент с указанным текстом в конец
currentRow() возвращает номер строки выбранного элемента. Если ни один элемент не выбран, возвращает -1

Сигналы

Сигнал Назначение
clicked() подается при щелчке по элементу в виджете списка 
currentRowChanged() подается при изменении строки текущего элемента списка
currentTextChanged() подается при каждом изменении текста в текущем элементе списка
currentItemChanged() подается при изменении фокуса текущего элемента списка



 

 

 

 

QT6 QTable, QMessageBox, Dialogs

QTable

Отображение таблиц. Элементы в QTableWidget  предоставляются с помощью QTableWidgetItem. 

Методы:

Метод Назначение
setRowCount() определения количества строк
setColumnCount() определения количества столбцов
rowCount() возвращает количество строк
columnCount() возвращает количество столбцов
from PyQt6.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout
import sys 
 
class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(200,200, 700, 400)
        self.setWindowTitle("Python GUI Development")
        self.create_button()

    def create_button(self):
        vbox = QVBoxLayout()
        curtable = QTableWidget()
        curtable.setRowCount(3)
        curtable.setColumnCount(3)

        curtable.setItem(0, 0, QTableWidgetItem('Заголовок столбца 1'))
        curtable.setItem(0, 1, QTableWidgetItem('Заголовок столбца 2'))
        curtable.setItem(0, 2, QTableWidgetItem('Заголовок столбца 3'))

        vbox.addWidget(curtable)

        self.setLayout(vbox)
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec())

QMessageBox

QMessageBox - модальный диалог информирования пользователя и получения ответа. В окне сообщения отображается текст, есть необязательный подробный текст в случае необходимости. Также может отображаться значок и стандартные кнопки для принятия ответа пользователя. Существуют различные типы диалогов (about messagebox, information messagebox, warning messagebox,  multichoice messagebox).

from PyQt6.QtWidgets import QApplication, QDialog, QPushButton
from PyQt6.QtWidgets import QMessageBox

from PyQt6 import uic
import sys 
 
class Window(QDialog):
    def __init__(self):
        super().__init__()
        self.setGeometry(200,200, 700, 400)
        self.setWindowTitle("Python GUI Development")
        uic.loadUi("messagedemo.ui", self)
        
        self.loadguiobjects()

    def loadguiobjects(self):
        self.butt_warn = self.findChild(QPushButton, "pushButton_warn")
        self.butt_warn.clicked.connect(self.show_warn)
        self.butt_info = self.findChild(QPushButton, "pushButton_info")
        self.butt_info.clicked.connect(self.show_info)
        self.butt_abt = self.findChild(QPushButton, "pushButton_abt")
        self.butt_abt.clicked.connect(self.show_about)

    def show_warn(self):
        QMessageBox.warning(self, 'Warning', 'This is a warning message')
    
    def show_info(self):
        #кастомный messagebox + стандартные кнопки
        msg_box = QMessageBox(self)
        msg_box.setWindowTitle('Information')
        msg_box.setText('This is a information message')
        msg_box.setIcon(QMessageBox.Icon.Information)

        # Добавляем кнопки
        ok_button = msg_box.addButton('OK', QMessageBox.ButtonRole.AcceptRole)
        cancel_button = msg_box.addButton('Отменить задание', QMessageBox.ButtonRole.RejectRole)

        # Показываем сообщение и ждем нажатия кнопки
        msg_box.exec()

        # Проверяем какая кнопка была нажата
        if msg_box.clickedButton() == cancel_button:
            print("Действие отменено")

        elif msg_box.clickedButton() == ok_button:
            print("OK нажата")

    def show_about(self):
        # другой способ с разными кнопкам
        msg_box = QMessageBox(
            QMessageBox.Icon.NoIcon,
            'About',
            'This is a about message',
            QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel
        )

        # Изменяем текст стандартных кнопок
        msg_box.button(QMessageBox.StandardButton.Ok).setText('Продолжить')
        msg_box.button(QMessageBox.StandardButton.Cancel).setText('Отменить задание')

        result = msg_box.exec()

        if result == QMessageBox.StandardButton.Ok:
            print("Продолжаем выполнение")
        else:
            print("Задание отменено")
 
app = QApplication(sys.argv) 
window = Window() 
window.show() 
sys.exit(app.exec())

SaveFile

Сама кнопка меню в сформированном из QtDesiner, класс Ui_MainWindow

from PyQt6.QtWidgets import QMainWindow, QApplication, QFileDialog, QMessageBox
import sys
from notepadapp import Ui_MainWindow

class NotePadWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.show()

        self.actionSave.triggered.connect(self.save_file)

    def save_file(self):
        filename = QFileDialog.getSaveFileName(self, 'Save file')
        if filename[0]:
            f = open(filename[0], 'w')
            with f:
                text = self.textEdit.toPlainText()
                f.write(text)
                QMessageBox.about(self, 'Save file', 'File saved successfully!')

app = QApplication(sys.argv)
Note = NotePadWindow()
sys.exit(app.exec())

 

 

Пример: notepad

Начальная информация

Внешний вид приложения:

image.png

Элементы интерфейса: меню, быстрые кнопки и многострочное поле ввода. Элементы меню:

image.png

image.png

image.png

Установленные модули:

pip install pyqt6

Параметры интерфейса:

Окно - MainWindow

from PyQt6.QtWidgets import QMainWindow, QApplication, QFileDialog, QMessageBox
from PyQt6.QtPrintSupport import QPrinter, QPrintDialog, QPrintPreviewDialog
from PyQt6.QtCore import QFileInfo
from PyQt6.QtGui import QFont
import sys
from notepadapp import Ui_MainWindow

class NotePadWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.show()

        self.actionSave.triggered.connect(self.file_save)
        self.actionNew.triggered.connect(self.file_new)
        self.actionOpen.triggered.connect(self.file_open)
        self.actionPrint.triggered.connect(self.file_print)
        self.actionPrint_preview.triggered.connect(self.preview_dialog)
        self.actionExport_PDF.triggered.connect(self.exporting_pdf)
        self.actionQuit.triggered.connect(self.exit_app)

        self.actionUndo.triggered.connect(self.textEdit.undo)
        self.actionRedo.triggered.connect(self.textEdit.redo)

        self.actionCut.triggered.connect(self.textEdit.cut)
        self.actionCopy.triggered.connect(self.textEdit.copy)
        self.actionPaste.triggered.connect(self.textEdit.paste)

        self.actionBold.triggered.connect(self.text_bold)

    def maybe_save(self) -> bool:
        if not self.textEdit.document().isModified():
            return True
        
        ret = QMessageBox.warning(self, "Application", 
                                  "The document changed \n Save working?",
                                  QMessageBox.StandardButton.Save | 
                                  QMessageBox.StandardButton.Discard | 
                                  QMessageBox.StandardButton.Cancel)
        if ret == QMessageBox.StandardButton.Save:
            self.file_save()
            return True
        elif ret == QMessageBox.StandardButton.Cancel:
            return False
        
        return True
    
    def file_new(self):
        if self.maybe_save():
            self.textEdit.clear()

    def file_save(self):
        filename = QFileDialog.getSaveFileName(self, 'Save file')
        if filename[0]:
            f = open(filename[0], 'w')
            with f:
                text = self.textEdit.toPlainText()
                f.write(text)
                QMessageBox.about(self, 'Save file', 'File saved successfully!')

    def file_open(self):
        self.maybe_save()
        filename = QFileDialog.getOpenFileName(self, 'Open file')
        if filename[0]:
            f = open(filename[0], 'r')
            with f:
                data = f.read()
                self.textEdit.setText(data)

    def file_print(self):
        printer = QPrinter(QPrinter.PrinterMode.HighResolution)
        dialog = QPrintDialog(printer)
        if dialog.exec() == QPrintDialog.DialogCode.Accepted:
            self.textEdit.print(printer)

    def print_preview(self, printer):
        self.textEdit.print(printer)

    def preview_dialog(self):
        printer = QPrinter(QPrinter.PrinterMode.HighResolution)
        preview_dialog = QPrintPreviewDialog(printer, self)
        preview_dialog.paintRequested.connect(self.print_preview)
        preview_dialog.exec()

    def exporting_pdf(self):
        #fn, _ = QFileDialog.getSaveFileName(self, 'Export PDF', "PDF Files (.pdf) ;; AllFiles()")
        fn, _ = QFileDialog.getSaveFileName(self, 'Export PDF','',"PDF Files (.pdf) ;; All Files (*)")
        if QFileInfo(fn).suffix() == "":
            fn += '.pdf'
        printer = QPrinter(QPrinter.PrinterMode.HighResolution)
        printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat)
        printer.setOutputFileName(fn)
        self.textEdit.document().print(printer)

    def exit_app(self):
        self.close()

    def text_bold(self):
        font = QFont()
        font.setBold(True)
        self.textEdit.setFont(font)


app = QApplication(sys.argv)
Note = NotePadWindow()
sys.exit(app.exec())

Это неполный код, операции однотипные.

QT6: База данных

Пример для работы с Mysql

pip install mysql-connector-python

Пример кода для подключения к базе и создания БД: 

from PyQt6 import QtCore, QtGui, QtWidgets
import mysql.connector as mc


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(456, 300)
        self.verticalLayout = QtWidgets.QVBoxLayout(Form)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label_dbname = QtWidgets.QLabel(parent=Form)
        font = QtGui.QFont()
        font.setPointSize(14)
        self.label_dbname.setFont(font)
        self.label_dbname.setObjectName("label_dbname")
        self.horizontalLayout.addWidget(self.label_dbname)
        self.lineEdit_dbname = QtWidgets.QLineEdit(parent=Form)
        font = QtGui.QFont()
        font.setPointSize(14)
        self.lineEdit_dbname.setFont(font)
        self.lineEdit_dbname.setText("")
        self.lineEdit_dbname.setObjectName("lineEdit_dbname")
        self.horizontalLayout.addWidget(self.lineEdit_dbname)
        self.verticalLayout.addLayout(self.horizontalLayout)
        spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
        self.verticalLayout.addItem(spacerItem)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.pushButton_dbcreate = QtWidgets.QPushButton(parent=Form)
        self.pushButton_dbcreate.setObjectName("pushButton_dbcreate")
        self.pushButton_dbcreate.clicked.connect(self.create_db)
        self.horizontalLayout_2.addWidget(self.pushButton_dbcreate)
        self.pushButton_dbconn = QtWidgets.QPushButton(parent=Form)
        self.pushButton_dbconn.setObjectName("pushButton_dbconn")
        self.pushButton_dbconn.clicked.connect(self.check_connect)
        self.horizontalLayout_2.addWidget(self.pushButton_dbconn)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.label_result = QtWidgets.QLabel(parent=Form)
        font = QtGui.QFont()
        font.setFamily("PMingLiU-ExtB")
        font.setPointSize(14)
        self.label_result.setFont(font)
        self.label_result.setText("")
        self.label_result.setObjectName("label_result")
        self.verticalLayout.addWidget(self.label_result)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def create_db(self):
        try:
            mydb = mc.connect(
                host="192.168.1.193",
                user="root",
                password="rootpassword"
            )
            cursor = mydb.cursor()
            dbname = self.lineEdit_dbname.text()
            cursor.execute("CREATE DATABASE {} ".format(dbname))
            self.label_result.setText('Database {} created!'.format(dbname))
        except mc.Error as e:
            self.label_result.setText(str(e))

    def check_connect(self):
        try:
            mydb = mc.connect(
                host="192.168.1.193",
                user="root",
                password="rootpassword",
                database="pyqtdb"
            )
            self.label_result.setText("Connected!")
        except mc.Error as e:
            self.label_result.setText(str(e))

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.label_dbname.setText(_translate("Form", "Database name:"))
        self.pushButton_dbcreate.setText(_translate("Form", "Create Database"))
        self.pushButton_dbconn.setText(_translate("Form", "Database connection"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec())