Композитный виджет содержит кнопки, метки и т. Д. c. Как построить такой и как его использовать - PullRequest
0 голосов
/ 17 января 2020

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

В основном я пытался создать пользовательские объекты QWidget, QLabel и QFrame, которые я буду использовать в нескольких местах. Я подготовил такой пример:

class FansLabelsRight(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        print('is it working?')
        self.setGeometry(275,65,110,140)
        self.setStyleSheet("background: rgba(255,0,0,50)")
        #self.layout = QLayout(self)
        self.pane1 = QLabel(self)
        self.pane2 = QLabel(self)
        self.pane3 = QLabel(self)
        pixmap1 = QPixmap('rtC.png')
        pixmap2 = QPixmap('rtB.png')
        pixmap3 = QPixmap('rtA.png')
        self.pane1.setPixmap(pixmap1)
        self.pane2.setPixmap(pixmap2)
        self.pane3.setPixmap(pixmap3)
        #self.layout.addWidget(self.pane1)
        #self.layout.addWidget(self.pane2)
        #self.layout.addWidget(self.pane3)
        self.pane1.setGeometry(30,10,pixmap1.width(), pixmap1.height())
        self.pane2.setGeometry(35,30,pixmap2.width(), pixmap2.height())
        self.pane3.setGeometry(40,30,pixmap3.width(), pixmap3.height())
        self.setLayout(self.layout)

        self.show()

Не сработало. Как и немногие другие подходы, которые я тестировал без положительных результатов, ожидаем, что я создаю их на основе Q tDesigner - создаю пользовательский объект, который фактически добавляет в мой класс QMainWindow другие виджеты, но это не то, что я ожидал, и то, что я читаю, должно быть возможным. Другими словами, я думаю о наличии контейнера с подвиджетами. Это действительно возможно?

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        self.label = QLabel(Form)
        self.label.setGeometry(QtCore.QRect(60, 10, 61, 81))
        self.label.setPixmap(QPixmap("rtA.png"))
        self.label.setObjectName("label")
        self.label_2 = QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(70, 30, 51, 111))
        self.label_2.setPixmap(QPixmap("rtB.png"))
        self.label_2.setObjectName("label_2")
        self.label_3 = QLabel(Form)
        self.label_3.setGeometry(QtCore.QRect(60, 90, 47, 61))
        self.label_3.setPixmap(QPixmap("rtC.png"))
        self.label_3.setObjectName("label_3")
        self.pushButton = QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(0, 0, 75, 61))
        self.pushButton.setFlat(True)
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QPushButton(Form)
        self.pushButton_2.setGeometry(QtCore.QRect(0, 100, 75, 61))
        self.pushButton_2.setFlat(True)
        self.pushButton_2.setObjectName("pushButton_2")

        QtCore.QMetaObject.connectSlotsByName(Form)

Не могли бы вы подсказать, как этого добиться? Как создать собственный виджет, который будет построен из нескольких объектов и будет хранить целые логи c между ними внутри своего класса? (Что касается логики c, я понимаю, что нажатие одной кнопки покажет другую метку, а другая кнопка укажет, и т. Д. c ...)

Одной из проблем, с которыми я столкнулся, были макеты, которые не позволяли мне Разместите эти ярлыки там, где я хотел.

А вот пример того, как это должно выглядеть.

1 Ответ

0 голосов
/ 18 января 2020

Делать то, что вы хотите, с помощью базовых c виджетов, предоставляемых Qt, возможно, но есть некоторые недостатки и соображения, о которых следует помнить.

Я полагаю, что три изображения, которые вы хотите показать, это " Выровняйте фигуры справа, и если это так, вы не можете использовать макет, потому что их геометрия перекрывается: для виджета этого типа и вида вы должны «встроить» дочерние виджеты, не назначая их макету.

Затем, если вы хотите, чтобы эти полукруглые стрелки реагировали как кнопки, очевидно, что вы не можете использовать basi c QPushButtons, поскольку они имеют прямоугольную форму angular. Решением может быть создание подкласса, переопределение paintEvent (для предоставления пользовательского рисунка кнопки с использованием вашего изображения), а затем использование изображения для создания маски для виджета, чтобы события щелчка происходили только в пределах его границ.

Это базовый c пример того, что это может быть:

class MyButton(QtWidgets.QPushButton):
    def __init__(self, image, parent):
        super().__init__(parent)
        self.image = QtGui.QPixmap(image)
        self.setFixedSize(self.image.size())
        self.setMask(self.image.createHeuristicMask())

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        qp.drawPixmap(QtCore.QPoint(), self.image)


class MyWidget(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setFixedSize(110, 140)
        self.upButton = MyButton('uparrow.png', self)
        self.downButton = MyButton('downarrow.png', self)
        self.downButton.move(0, self.height() - self.downButton.height())

        self.rtcA = QtWidgets.QLabel(self)
        self.rtcA.setPixmap(QtGui.QPixmap('rtcA.png'))

        self.rtcB = QtWidgets.QLabel(self)
        self.rtcB.setPixmap(QtGui.QPixmap('rtcB.png'))

        self.rtcC = QtWidgets.QLabel(self)
        self.rtcC.setPixmap(QtGui.QPixmap('rtcC.png'))

        for label in self.rtcA, self.rtcB, self.rtcC:
            label.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)

        self.upButton.clicked.connect(self.up)
        self.downButton.clicked.connect(self.down)

        p = self.palette()
        p.setColor(p.Window, QtGui.QColor(57, 57, 57))
        self.setPalette(p)

    def up(self):
        print('going up')

    def down(self):
        print('going down')

А вот как это выглядит:

screenshot of the running example

Как видите, я не использовал никакой разметки: вы можете добавить дочерние элементы в виджет "контейнер", просто добавив этот виджет в качестве аргумента parent; это заставляет этих детей появляться внутри контейнера, и их можно свободно перемещать в пределах родительских границ.

Некоторые небольшие заметки.
Для трех индикаторов я использовал изображения, которые уже "переводят" msgstr "фактическое содержимое изображения (это означает, что оно размещено в верхнем левом углу виджета). Это делается для того, чтобы они были правильно выровнены и чтобы избежать непрерывных проб и ошибок, чтобы получить позицию на виджете; например, третье изображение на самом деле выглядит так:

image with alpha channel shown

Чтобы эта работа работала, как и ожидалось, мне пришлось сделать эти виджеты «прозрачными для событий мыши» : поскольку они добавляются после кнопок, они будут над ними, и кнопки не получат никакого события мыши, потому что метки будут в пути. Другая возможность - добавить кнопки после надписей или, в противном случае, использовать raise_() или lower():

    self.upButton.raise_()
    self.downButton.raise_()
    # or, alternatively
    for label in self.rtcA, self.rtcB, self.rtcC:
        label.lower()

. В качестве дополнительной возможности вы можете создавать «маскирующие изображения». «для каждой метки (с solid -нон-альфа-фоном вокруг границ каждого раздела) и используйте setMask(QtGui.QPixmap('rtcA_mask.png').createHeuristicMask()) аналогично тому, что я сделал для кнопок. Преимущество этого подхода состоит в том, что события мыши могут быть правильно получены от этих меток, если они вам когда-либо понадобятся.

...