Самый простой способ создать подкласс виджета в Python для использования с Qt Designer - PullRequest
0 голосов
/ 20 февраля 2020

Я создаю приложение с использованием PyQt5, при этом (большая часть) GUI создается с использованием Qt Designer. У меня есть несколько элементов пользовательского интерфейса, которые делают в основном то же самое, и кажется разумным переместить их код в классы, которые наследуются от базового класса (который, в свою очередь, наследует от QTableWidget).

Это кажется действительно простым, за исключением того, что я я не уверен, как заставить Qt Designer использовать эти классы при генерации его файлов UI. Я нашел руководство по выполнению этого в PyQt4 и , еще одно, предназначенное для Qt 5, но с собственным кодом C ++ и , еще одно , предназначенное для PyQt5, но не не имеет дело с (самым сложным) аспектом доступности подклассов в Qt Designer.

Как сделать подкласс виджета, созданного с использованием PyQt5, доступным для использования в Qt Designer?

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

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Хотя создание плагинов для Qt Designer возможно, это не простая задача: официальная документация устарела, а иногда и неполна, а некоторые функции не полностью перенесены для прозрачного использования PyQt.

Самый простой способ - использовать продвинутые виджеты .

Допустим, у вас есть виджет, который причудливо отображает текущее время:

from PyQt5 import QtCore, QtGui, QtWidgets, uic

class TimeFrame(QtWidgets.QFrame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.updateTimer = QtCore.QTimer(interval=60000, timeout=self.update)
        self._time = None

    @QtCore.pyqtProperty(QtCore.QTime)
    def time(self):
        return self._time

    @time.setter
    def time(self, time):
        self._time = time
        self.update()

    def paintEvent(self, event):
        super().paintEvent(event)
        size = min(self.width(), self.height()) - 10
        rect = QtCore.QRect(0, 0, size, size)
        rect.moveCenter(self.rect().center())
        qp = QtGui.QPainter(self)
        qp.setRenderHints(qp.Antialiasing)
        qp.drawEllipse(rect)
        qp.setPen(QtCore.Qt.NoPen)
        qp.setBrush(QtCore.Qt.blue)
        time = self._time or QtCore.QTime.currentTime()
        minuteAngle = time.minute() * 6
        qp.drawPie(rect, 1440, -minuteAngle * 16)
        qp.setBrush(QtCore.Qt.red)
        hourAngle = (time.hour() % 12 + time.minute() / 60) * 30
        qp.drawPie(rect.adjusted(30, 30, -30, -30), 1440, -hourAngle * 16)

Это простой виджет часов, который показывает пару «пирогов», чем больше минут, тем меньше часов (на этом скриншоте время 2:03):

fancy clock widget


Теперь, чтобы иметь возможность добавить этот виджет из Designer, вам нужно повысить виджет. Продвижение виджетов - это способ для Qt расширить возможности и функциональные возможности виджета, добавленного в пользовательский интерфейс.
Это очень полезно, потому что вы можете расширить любой стандартный класс виджетов по-своему: например Если вы добавляете QTableView в пользовательский интерфейс и продвигаете его, он позволяет вам установить стандартные свойства QPushButton из интерфейса Designer, а затем реализовать другие функции из вашего кода.

Процедура довольно проста, если вы знать, как это работает.

1. Создайте пользовательский интерфейс и добавьте виджет на основе класса, который вы хотите расширить

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

basic GUI

Как вы можете видеть, класс, сообщаемый из инспектора объектов, по-прежнему является QFrame .

2. Продвигайте виджет

Щелкните правой кнопкой мыши на виджете, который вы хотите использовать для своего класса, и выберите Promote to..., затем установите «Имя продвигаемого класса» для имени класса виджета, созданного ранее, и «Файл заголовка» к имени модуля , содержащему этот класс. Я сохранил файл python как promoted.py, поэтому значение поля будет promoted. Учтите, что пути к файлам заголовков относятся к пути, из которого будет загружен файл пользовательского интерфейса.

promote widget in Designer

Затем нажмите «Добавить», чтобы создать новый продвинутый виджет "класс" и, наконец, "продвижение", чтобы официально продвигать его. После этого вы можете перевести любой виджет в ранее установленный продвигаемый класс, если базовый класс совместим: если у вас есть другой QFrame в вашем интерфейсе, вы можете щелкнуть по нему правой кнопкой мыши и выбрать продвинутый класс из «Повышать в» подменю.

Теперь класс, отображаемый в Инспекторе объектов, равен TimeFrame.

The object class has changed

3. Задайте свойства объекта, сохраните, создайте код и запустите

Поскольку мы используем QFrame, мы можем установить его фрейм (это потому, что мы ранее также вызывали реализацию базового класса в методе paintEvent(event)).

Watch, a raised frame!

Теперь вам просто нужно реализовать базовый класс для основного виджета. Помните, что каждый раз, когда загружаемый виджет загружается, его «заголовочный файл» будет загружен, что означает, что его код будет всегда выполняться. Вот почему важно, чтобы кодовый блок if __name__ == '__main__': помещался в файл, если он содержит как основную «программу», так и продвигаемый класс виджетов.

promoted.py code:

class Test(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi('test.ui', self)

        self.timeEdit.timeChanged.connect(self.updateTimeFrame)

        self.timeEdit.setTime(QtCore.QTime.currentTime())

    def updateTimeFrame(self):
        self.timeFrame.time = self.timeEdit.time()


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Test()
    w.show()
    sys.exit(app.exec())

Теперь, очевидно, в Designer в любом случае ничего не будет отображаться, , но , как только мы запустим наш код, продвинутый виджет будет отображаться, как и ожидалось!

The promoted widget at work! Cool!

И теперь вы также можете узнать, сколько времени мне понадобилось, чтобы создать этот ответ, круто; -)

2 голосов
/ 20 февраля 2020

Чтобы использовать пользовательский виджет в Qt Designer, есть следующие опции:

  • Плагин Qt Designer:

    Вы должны создать класс это наследуется от QPyDesignerCustomWidgetPlugin, который указывает характеристики того, как он будет отображаться в Qt Designer. Преимущество этого метода заключается в том, что вы можете изменять свойства q, а также создавать диалоговые окна и меню, которые позволяют вносить изменения дружественным образом. В исходном коде PyQt5 в папке "examples / designer / plugins" есть пример.

  • Продвигать виджеты

    Преимущество состоит в том, что нет необходимости создавать что-либо, а недостатком является то, что он не позволяет настраивать сверх того, что обеспечивает плагин базового класса. В SO есть несколько примеров: 1 , 2 , 3 .

Если вы хотите расположить только Затем виджеты просто продвигают виджет, если вместо этого вы хотите использовать Qt Designer для изменения свойств, тогда необходим плагин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...