首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PyQt5: Qstyle.CC_ScrollBar呈现在错误的位置

PyQt5: Qstyle.CC_ScrollBar呈现在错误的位置
EN

Stack Overflow用户
提问于 2021-01-29 15:47:18
回答 1查看 96关注 0票数 1

我正在使用一个listView和一个自定义委托。通过paint函数,我绘制了一组控制元素,这样列表中的每一行行为就像它是一个小部件,而不是实际的小部件。这对于性能至关重要,因为列表由数十万个元素组成,如指向的这里这里。唯一的问题是QStyleOptionSlider复杂控件:如果我请求一个CC.ScrollBar,该控件将呈现在视图的左上角,而不是我想要的位置。如果在QApplication.style().drawComplexControl(QStyle.CC_ScrollBar, self.scrollOptions, painter)中,我请求一个CC_Slider (而不是CC_ScrollBar),则控件将按预期的方式呈现。我也尝试从一个真正的滚动小部件初始化样式,但是没有什么改变。

我想知道我是否做错了什么,或者它是否是库的问题,因为我绘制的所有其他控件都工作得很完美。我注意到的唯一不同是,当滚动条与滑块类合并时,其他元素(例如帧、标签、按钮)有自己的QStyleOption类,但是引用文档

QStyleOptionSlider包含QStyle函数绘制QSlider和QScrollBar所需的所有信息。

调试信息:Python3.8.6/ PyQt 5.15.1 / Pyqt-tools 5.15.1.2 / Windows 10

极小例子

代码语言:javascript
复制
from PyQt5.QtCore import QSize, Qt, QRect
from PyQt5.QtGui import QColor
from PyQt5.QtGui import QStandardItem
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QStyle
from PyQt5.QtWidgets import QStyledItemDelegate, QApplication, QStyleOptionFrame, \
    QStyleOptionSlider
from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.inferenceListView = QtWidgets.QListView(self.centralwidget)
        self.inferenceListView.setGridSize(QtCore.QSize(0, 200))
        self.inferenceListView.setObjectName("inferenceListView")
        self.gridLayout.addWidget(self.inferenceListView, 0, 1, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.setupProposals()

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

    def setupProposals(self):
        self.delegate = MyDelegate()
        # self.delegate.initScroll(self.horizontalScrollBar)
        model = QStandardItemModel(0, 0)
        for index in range(0, 5000):
            model.appendRow(QStandardItem(str(index)))
            self.inferenceListView.setItemDelegateForRow(index, self.delegate)
        self.inferenceListView.setModel(model)


class MyDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        QStyledItemDelegate.__init__(self, parent)
        self.frame = QStyleOptionFrame()
        # ---------------

        self.scrollOptions = QStyleOptionSlider()
        self.scrollOptions.orientation = Qt.Vertical
        self.scrollOptions.LayoutDirectionAuto = Qt.LayoutDirectionAuto
        self.scrollOptions.orientation = Qt.Vertical
        self.scrollOptions.state = QStyle.State_Enabled
        self.scrollOptions.maximum = 10
        self.scrollOptions.minimum = 0
        self.scrollOptions.sliderValue = 0

    def initScroll(self, scroll):
        self.scrollOptions.initFrom(scroll)

    def sizeHint(self, option, index):
        return QSize(150, 200)

    def paint(self, painter, option, index):
        optX = option.rect.x()
        optY = option.rect.y()
        optH = option.rect.height()
        optW = option.rect.width()

        painter.fillRect(option.rect, QColor(100, 100, 100, 100))
        painter.drawLine(optX, optY + optH, optX + optW, optY + optH)
        QApplication.style().drawControl(QStyle.CE_ShapedFrame, self.frame, painter)

        self.scrollOptions.rect = QRect(optX + 100, optY + 100, 50, 80)

        # OK WITH CC_SLIDER
        #QApplication.style().drawComplexControl(QStyle.CC_Slider, self.scrollOptions, painter)

        # WRONG PLACE WITH CC_SCROLLBAR
        QApplication.style().drawComplexControl(QStyle.CC_ScrollBar, self.scrollOptions, painter)

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


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

编辑

目前看来这是一个与Windows相关的问题。我有一个带有Mac的同事运行上面的代码,滚动条在正确的位置绘制。我附上一张Windows在这两种情况下发生的情况的图片:

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-29 19:19:31

这似乎是subControlRect在QCommonStyle中的一个可能不完整的实现,因为为CC_Slider返回的矩形总是位于左上角(参见来源)。

一个可能的解决方案可以是使用代理样式并返回一个转换后的矩形,如果subrect不包含在选项rect中:

代码语言:javascript
复制
class ProxyStyle(QtWidgets.QProxyStyle):
    def subControlRect(self, cc, opt, sc, widget=None):
        r = super().subControlRect(cc, opt, sc, widget)
        if cc == self.CC_ScrollBar and not opt.rect.contains(r):
            r.translate(opt.rect.topLeft())
        return r

# ...
app = QtWidgets.QApplication(sys.argv)
app.setStyle(ProxyStyle())
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65957575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档