pyside2 实现一个带有滑块视觉的输入框

pyside2 Implement an input box with a slider visual

我想在 Autodesk Maya 中使用 pyside2 实现类似搅拌机的 属性 调整框,如下所示。

我找到了一些类似的链接,但没有成功,具体怎么做。 How to create graphic slider in Python that can be modified with mouse?

import sys

from PySide2.QtCore import Qt, QEvent
from PySide2.QtGui import QStandardItemModel, QStandardItem
from PySide2.QtWidgets import QApplication, QWidget, QTableView, QHBoxLayout, QStyledItemDelegate, QStyle, QStyleOptionProgressBar, QStyleOptionButton

class MyTableView(QTableView):
    def __init__(self):
        super(MyTableView, self).__init__()


class MyDelgate(QStyledItemDelegate):
    def __init__(self):
        super(MyDelgate, self).__init__()


    def paint(self, painter, option, index):
        if index.column() == 1:
            style = QStyleOptionProgressBar()
            style.minimum = 0
            style.maximum = 10
            style.progress= index.data(Qt.DisplayRole)
            style.rect = option.rect
            QApplication.style().drawControl(QStyle.CE_ProgressBar, style, painter)

        elif index.column() == 2:
            style = QStyleOptionButton()
            if index.data(Qt.DisplayRole) == True:
                style.state = QStyle.State_On
            else:
                style.state = QStyle.State_Off
            style.state |= QStyle.State_Enabled
            style.rect = option.rect
            style.rect.setX(option.rect.x() + option.rect.width() / 2 - 7)
            QApplication.style().drawControl(QStyle.CE_CheckBox, style, painter)
        else:
            return QStyledItemDelegate.paint(self, painter, option, index)

    def editorEvent(self, event, model, option, index):
        if index.column() == 2:
            if event.type() == QEvent.MouseButtonPress and option.rect.contains(event.pos()):
                data = not index.data(Qt.DisplayRole)
                model.setData(index, data, Qt.DisplayRole)
            return True
        else:
            return QStyledItemDelegate.editorEvent(self, event, model, option, index)

class MyWidget(QWidget):
    def __init__(self):
        super(MyWidget, self).__init__()

        self.mode = QStandardItemModel()
        root = self.mode.invisibleRootItem()

        item1 = QStandardItem()
        item1.setData('a', Qt.DisplayRole)

        item2 = QStandardItem()
        item2.setData(1, Qt.DisplayRole)

        item3 = QStandardItem()
        item3.setData(False, Qt.DisplayRole)

        item4 = QStandardItem()
        item4.setData('b', Qt.DisplayRole)

        item5 = QStandardItem()
        item5.setData(2, Qt.DisplayRole)

        item6 = QStandardItem()
        item6.setData(True, Qt.DisplayRole)

        root.setChild(0, 0, item1)
        root.setChild(0, 1, item2)
        root.setChild(0, 2, item3)
        root.setChild(1, 0, item4)
        root.setChild(1, 1, item5)
        root.setChild(1, 2, item6)

        tableView = MyTableView()
        tableView.setModel(self.mode)
        tableView.setItemDelegate(MyDelgate())

        layout = QHBoxLayout()
        layout.addWidget(tableView)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.resize(500, 300)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()
    sys.exit(app.exec_())

感谢任何建议。

您需要在editorEvent中跟踪鼠标位置,并根据样式选项的子元素矩形计算比例。

    def editorEvent(self, event, model, option, index):
        if index.column() == 1:
            if event.type() in (event.MouseMove, event.MouseButtonPress):
                progressOpt = QStyleOptionProgressBar()
                progressOpt.rect = option.rect
                style = option.widget.style()
                rect = style.subElementRect(style.SE_ProgressBarGroove,
                    progressOpt, option.widget)
                pos = max(0, min(rect.width(), event.x() - rect.x()))
                model.setData(index, round(pos / rect.width() * 10), Qt.DisplayRole)
                return True
        elif index.column() == 2:
            if event.type() == QEvent.MouseButtonPress and option.rect.contains(event.pos()):
                data = not index.data(Qt.DisplayRole)
                model.setData(index, data, Qt.DisplayRole)
            return True
        return super().editorEvent(event, model, option, index)