Пользовательский QPushButton внутри QStyledItemDelegate - PullRequest
0 голосов
/ 25 апреля 2020

Проблема:

Я могу добавить QPushButton в QStyledItemDelegate просто отлично. Я имитирую нажатие кнопки внутри метода editorEvent делегата, поэтому при нажатии происходит действие. У меня проблемы с работой таблицы стилей моего QPushButton - он читает только первый фоновый параметр, который "красный" и не изменяется при наведении курсора мыши или нажатии .

Неясно, как мне go настроить настройки нажатия кнопки и определения при наведении, чтобы кнопка действовала как настоящая кнопка для делегата. Нужно ли настраивать eventFilter? Должен ли я сделать это на уровне просмотра? Я делаю это внутри метода рисования делегата? Комбинация всего?

Цели:

  • При наведении курсора мыши на время списка будет отображаться значок кнопки.
  • Мышь, наведенная на кнопку, изменит цвет фона.
  • Щелчки мышью по кнопке затемняют цвет фона, показывая, что щелчок произошел.
  • Я бы хотел установить эти параметры в таблице стилей, если это возможно, но я также не против делать все это в функции рисования. Что бы ни работало!

Текущая реализация

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

enter image description here

Спасибо !

Вот что я собрал до сих пор:

import sys

from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtWidgets


class DelegateButton(QtWidgets.QPushButton):
    def __init__(self, parent=None):
        super(DelegateButton, self).__init__(parent)

        # self.setLayout(QHBoxLayout())
        size = 50
        self.setFixedSize(size, size)
        self.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_DialogOpenButton))
        self.setStyleSheet("""
            QPushButton{
                background:red;
                height: 30px;
                font: 12px "Roboto Thin";
                border-radius: 25
            }
            QPushButton:hover{
                background: green;
            }
            QPushButton:hover:pressed{
                background: blue;
            }
            QPushButton:pressed{
                background:  yellow;
            }
            """)


class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.resize(300, 300)

        # Model/View
        entries = ['one', 'two', 'three']
        model = QtGui.QStandardItemModel()
        delegate = ListItemDelegate()
        self.listView = QtWidgets.QListView(self)
        self.listView.setModel(model)
        self.listView.setItemDelegate(delegate)

        for i in entries:
            item = QtGui.QStandardItem(i)
            model.appendRow(item)

        # Layout
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.addWidget(self.listView)
        self.setLayout(main_layout)

        # Connections
        delegate.delegateButtonPressed.connect(self.on_delegate_button_pressed)

    def on_delegate_button_pressed(self, index):

        print('"{}" delegate button pressed'.format(index.data(QtCore.Qt.DisplayRole)))


class ListItemDelegate(QtWidgets.QStyledItemDelegate):
    delegateButtonPressed = QtCore.Signal(QtCore.QModelIndex)

    def __init__(self):
        super(ListItemDelegate, self).__init__()

        self.button = DelegateButton()

    def sizeHint(self, option, index):
        size = super(ListItemDelegate, self).sizeHint(option, index)
        size.setHeight(50)
        return size

    def editorEvent(self, event, model, option, index):

        # Launch app when launch button clicked
        if event.type() == QtCore.QEvent.MouseButtonRelease:
            click_pos = event.pos()
            rect_button = self.rect_button

            if rect_button.contains(click_pos):
                self.delegateButtonPressed.emit(index)
                return True
            else:
                return False
        else:
            return False

    def paint(self, painter, option, index):
        spacing = 10
        icon_size = 40

        # Item BG #########################################
        painter.save()
        if option.state & QtWidgets.QStyle.State_Selected:
            painter.setBrush(QtGui.QColor('orange'))
        elif option.state & QtWidgets.QStyle.State_MouseOver:
            painter.setBrush(QtGui.QColor('black'))
        else:
            painter.setBrush(QtGui.QColor('purple'))
        painter.drawRect(option.rect)
        painter.restore()

        # Item Text ########################################
        rect_text = option.rect
        QtWidgets.QApplication.style().drawItemText(painter, rect_text, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignLeft, QtWidgets.QApplication.palette(), True, index.data(QtCore.Qt.DisplayRole))

        # Custom Button ######################################
        self.rect_button = QtCore.QRect(
            option.rect.right() - icon_size - spacing,
            option.rect.bottom() - int(option.rect.height() / 2) - int(icon_size / 2),
            icon_size,
            icon_size
        )

        option = QtWidgets.QStyleOptionButton()
        option.initFrom(self.button)
        option.rect = self.rect_button
        # Button interactive logic
        if self.button.isDown():
            option.state = QtWidgets.QStyle.State_Sunken
        else:
            pass
        if self.button.isDefault():
            option.features = option.features or QtWidgets.QStyleOptionButton.DefaultButton
        option.icon = self.button.icon()
        option.iconSize = QtCore.QSize(30, 30)

        painter.save()
        self.button.style().drawControl(QtWidgets.QStyle.CE_PushButton, option, painter, self.button)
        painter.restore()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

1 Ответ

1 голос
/ 25 апреля 2020

Попробуйте: https://doc.qt.io/qt-4.8/qstyle.html#StateFlag -enum

import sys
import PySide.QtCore as core
import PySide.QtGui as gui

QPushButton#pushButton {
    background-color: yellow;
}

QPushButton#pushButton:hover {
    background-color: rgb(224, 255, 0);
}

QPushButton#pushButton:pressed {
    background-color: rgb(224, 0, 0);     
}

Ваш пользовательский QStyledItemDelegate перехватывает событие мыши, так что оно не передается в QListView. Поэтому в QStyledItemDelegate.editor (Event) нужно просто добавить.

if event.type() == core.QEvent.MouseButtonPress:
    return False

Теперь выделение распознается в методе paint () с использованием option.state & gui .QStyle.State_Selected.

if __name__ == '__main__':


    app = gui.QApplication(sys.argv)
    app.setStyleSheet('QListView::item:hover {background: none;}')
    mw = gui.QMainWindow()

    model = MyListModel()
    view = gui.QListView()
    view.setItemDelegate(MyListDelegate(parent=view))
    view.setSpacing(5)
    view.setModel(model)

    mw.setCentralWidget(view)
    mw.show()

    sys.exit(app.exec_())

class MyListDelegate(gui.QStyledItemDelegate):

    w = 300
    imSize = 90
    pad = 5
    h = imSize + 2*pad
    sepX = 10

    def __init__(self, parent=None):
        super(MyListDelegate, self).__init__(parent)

    def paint(self, painter, option, index):
        mouseOver = option.state in [73985, 73729]

        if option.state & QStyle.State_MouseOver::
            painter.fillRect(option.rect, painter.brush())

        pen = painter.pen()
        painter.save()

        x,y = (option.rect.x(), option.rect.y())
        dataRef = index.data()
        pixmap = dataRef.pixmap()
        upperLabel = dataRef.upperLabel()
        lowerLabel = dataRef.lowerLabel()

        if mouseOver:
            newPen = gui.QPen(core.Qt.green, 1, core.Qt.SolidLine)
            painter.setPen(newPen)
        else:
            painter.setPen(pen)
        painter.drawRect(x, y, self.w, self.h)
        painter.setPen(pen)

        x += self.pad
        y += self.pad

        painter.drawPixmap(x, y, pixmap)

        font = painter.font()
        textHeight  = gui.QFontMetrics(font).height()

        sX = self.imSize + self.sepX
        sY = textHeight/2

        font.setBold(True)
        painter.setFont(font)
        painter.drawText(x+sX, y-sY, 
                         self.w-self.imSize-self.sepX, self.imSize,
                         core.Qt.AlignVCenter,
                         upperLabel)
        font.setBold(False)
        font.setItalic(True)
        painter.setFont(font)
        painter.drawText(x+sX, y+sY,
                         self.w-self.imSize-self.sepX, self.imSize,
                         core.Qt.AlignVCenter,
                         lowerLabel)

        painter.restore()

    def sizeHint(self, option, index):
        return core.QSize(self.w, self.imSize+2*self.pad)

    def editorEvent(self, event, model, option, index):
        if event.type() == core.QEvent.MouseButtonRelease:
            print 'Clicked on Item', index.row()
        if event.type() == core.QEvent.MouseButtonDblClick:
            print 'Double-Clicked on Item', index.row()
        return True


window.button->setAutoFillBackground(false);
window.button->setAutoFillBackground(true);
window.button->setPalette(*palette_red);

Другое решение для установки CSS:

import sys
from PyQt5 import Qt as qt 

class TopLabelNewProject(qt.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        layout = qt.QHBoxLayout(self)
        layout.setContentsMargins(40, 0, 32, 0)
        self.setLayout(layout)
        self.setFixedHeight(80)

        self.label = qt.QLabel("Dashboard")

        layout.addWidget(self.label, alignment=qt.Qt.AlignLeft)

#        self.newProjectButton = Buttons.DefaultButton("New project", self)
        self.newProjectButton = qt.QPushButton("New project", self)
        layout.addWidget(self.newProjectButton, alignment=qt.Qt.AlignRight)


style = '''
QWidget {
    background-color: white;
} 

QLabel {
    font: medium Ubuntu;
    font-size: 20px;
    color: #006325;     
}        

QPushButton {
    background-color: #006325;
    color: white;

    min-width:  70px;
    max-width:  70px;
    min-height: 70px;
    max-height: 70px;

    border-radius: 35px;        
    border-width: 1px;
    border-color: #ae32a0;
    border-style: solid;
}
QPushButton:hover {
    background-color: #328930;
}
QPushButton:pressed {
    background-color: #80c342;
}    

'''


if __name__ == '__main__':
    app = qt.QApplication(sys.argv)

    app.setStyleSheet(style)

    ex = TopLabelNewProject()
    ex.show()
    sys.exit(app.exec_())  
...