为了账号安全,请及时绑定邮箱和手机立即绑定

最初在 QGraphics 中移动滚动条

最初在 QGraphics 中移动滚动条

小唯快跑啊 2022-05-24 10:42:32
我正在尝试设置最初在 QGraphicsScene 小部件内移动的垂直和水平滚动条。以下代码应移动条形并将它们设置在中间,但它们不会移动:from PyQt5 import QtCore, QtGui, QtWidgetsimport sysclass Diedrico(QtWidgets.QWidget):    def paintEvent(self, event):        qp = QtGui.QPainter(self)        pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.black), 5)        qp.setPen(pen)        qp.drawRect(500, 500, 1000, 1000)class UiVentana(QtWidgets.QMainWindow):    def __init__(self, parent=None):        super(UiVentana, self).__init__(parent)        self.resize(1000, 1000)        self.setFixedSize(1000, 1000)        self.scene = QtWidgets.QGraphicsScene(self)        self.view = QtWidgets.QGraphicsView(self.scene)        # This two lines should move the scroll bar        self.view.verticalScrollBar().setValue(500)        self.view.horizontalScrollBar().setValue(500)        self.diedrico = Diedrico()        self.diedrico.setFixedSize(2000, 2000)        self.scene.addWidget(self.diedrico)        self.setCentralWidget(self.view)    def keyPressEvent(self, event):        if event.key() == QtCore.Qt.Key_R:            self.view.setTransform(QtGui.QTransform())        elif event.key() == QtCore.Qt.Key_Plus:            scale_tr = QtGui.QTransform()            scale_tr.scale(1.5, 1.5)            tr = self.view.transform() * scale_tr            self.view.setTransform(tr)        elif event.key() == QtCore.Qt.Key_Minus:            scale_tr = QtGui.QTransform()            scale_tr.scale(1.5, 1.5)            scale_inverted, invertible = scale_tr.inverted()            if invertible:                tr = self.view.transform() * scale_inverted                self.view.setTransform(tr)if __name__ == "__main__":    app = QtWidgets.QApplication(sys.argv)    ui = UiVentana()    ui.show()    sys.exit(app.exec_())当我使用滚动区域时,我可以移动条形图,例如这个问题
查看完整描述

2 回答

?
交互式爱情

TA贡献1712条经验 获得超3个赞

给出的答案很好,但我想补充一些关于您为什么面临这个问题以及“幕后”发生的事情的见解。

首先,在您的代码中,您尝试在将任何对象添加到场景之前设置滚动条的值。
那时,您刚刚创建了视图和场景。视图小部件尚未显示(因此它还不“知道”它的实际大小),并且场景是空的,这意味着它sceneRectnull,如 0 宽度和 0 高度:在这种情况下,滚动条有最大值为 0,设置任何值都不会产生任何结果。

注意:要记住一个非常重要的方面:除非显式声明或请求,否则sceneRectQGraphicsScene 的 始终为,直到视图显示它。我所说的“请求”是指即使只是调用scene.sceneRect()也足以确保场景实际上并最终“知道”它的范围。

尝试设置滚动条(没有结果)后,您将小部件添加到场景中。问题是视图(它是 QAbstractScrollArea 的后代)只有在实际映射到屏幕上时才更新其滚动条。
这是一个复杂的“路径”,从显示主父窗口(如果有)开始,它根据其内容调整自身大小,并在需要时再次调整其内容大小,最终基于它们的 [嵌套小部件] 大小策略. 只有这样,视图才会“决定”是否需要滚动条,并最终设置它们的最大值。而且,只有这样你才能为这些滚动条设置一个值,那是因为只有这样视图才会“询问”sceneRect.
这也(部分)解释了为什么视图的行为方式与标准滚动区域不同:小部件有一个sizeHint由 QWidget 使用的,将它们包含在滚动区域内,并且理论上,它们的大小在它们被映射后立即映射创建的。但是。这取决于它们的大小提示和策略,因此在最终映射/显示之前,您无法保证实际的滚动区域内容大小;长话短说:它“有效”,但并不完美——至少在一切最终展示之前不会。

一个测试例子

根据您的需求和实施,有不同的方法可以解决您的问题。

  • 独立设置 sceneRect,甚至在向场景添加任何对象之前(但如果这些对象边界超出场景,您将面临一些不一致)

  • scene.sceneRect()如上所述调用,添加所有对象

  • 仅在视图显示并调整大小后设置 scoll 条

我准备了一个例子来展示上面解释的三种情况。它将创建一个新视图并根据复选框在不同点更新其滚动条,以显示它们的行为方式有何不同。请注意,在设置 sceneRect 时,我使用了一个小于小部件大小的矩形来更好地显示其行为:您可以看到“设置场景矩形”和“检查场景矩形”的视觉结果相似,但滚动条位置不同.

import sys

from PyQt5 import QtCore, QtGui, QtWidgets


class Diedrico(QtWidgets.QWidget):

    def paintEvent(self, event):

        qp = QtGui.QPainter(self)

        pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.black), 5)

        qp.setPen(pen)

        qp.drawRect(500, 500, 1000, 1000)


class TestView(QtWidgets.QGraphicsView):

    def __init__(self, setRect=False, checkScene=False, showEventCheck=False):

        super(TestView, self).__init__()

        self.setFixedSize(800, 800)

        scene = QtWidgets.QGraphicsScene()

        self.setScene(scene)

        self.diedrico = Diedrico()

        self.diedrico.setFixedSize(2000, 2000)

        scene.addWidget(self.diedrico)

        if setRect:

            scene.setSceneRect(0, 0, 1500, 1500)

        elif checkScene:

            scene.sceneRect()

        self.showEventCheck = showEventCheck

        if not showEventCheck:

            self.scroll()


    def scroll(self):

        self.verticalScrollBar().setValue(500)

        self.horizontalScrollBar().setValue(500)    


    def showEvent(self, event):

        super(TestView, self).showEvent(event)

        if not event.spontaneous() and self.showEventCheck:

            self.scroll()


class ViewTester(QtWidgets.QWidget):

    def __init__(self):

        QtWidgets.QWidget.__init__(self)

        layout = QtWidgets.QVBoxLayout()

        self.setLayout(layout)


        self.setRectCheck = QtWidgets.QCheckBox('Set scene rect')

        layout.addWidget(self.setRectCheck)


        self.checkSceneCheck = QtWidgets.QCheckBox('Check scene rect')

        layout.addWidget(self.checkSceneCheck)


        self.showEventCheck = QtWidgets.QCheckBox('Scroll when shown')

        layout.addWidget(self.showEventCheck)


        showViewButton = QtWidgets.QPushButton('Show view')

        layout.addWidget(showViewButton)

        showViewButton.clicked.connect(self.showView)

        self.view = None


    def showView(self):

        if self.view:

            self.view.close()

            self.view.deleteLater()

        self.view = TestView(

            setRect = self.setRectCheck.isChecked(), 

            checkScene = self.checkSceneCheck.isChecked(), 

            showEventCheck = self.showEventCheck.isChecked()

            )

        self.view.show()


if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)

    viewTester = ViewTester()

    viewTester.show()

    sys.exit(app.exec_())

最后,请记住对滚动条使用绝对值并不是一个好主意。如果要“居中”视图,请考虑使用centerOn(及其基于项目的重载),或基于scrollBar.maximum()/2.


查看完整回答
反对 回复 2022-05-24
?
繁花如伊

TA贡献2012条经验 获得超12个赞

您想在小部件尚未形成时设置该值,请稍等片刻。


import sys

from PyQt5 import QtCore, QtGui, QtWidgets



class Diedrico(QtWidgets.QWidget):

    def paintEvent(self, event):

        qp = QtGui.QPainter(self)

        pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.black), 5)

        qp.setPen(pen)

        qp.drawRect(500, 500, 1000, 1000) 



class UiVentana(QtWidgets.QMainWindow):


    def __init__(self, parent=None):

        super(UiVentana, self).__init__(parent)


        self.resize(1000, 1000)

        self.setFixedSize(1000, 1000)


        self.scene = QtWidgets.QGraphicsScene(self)

        self.view  = QtWidgets.QGraphicsView(self.scene)


        # This two lines should move the scroll bar

        QtCore.QTimer.singleShot(0, self.set_Value)                   # +++


        self.diedrico = Diedrico()

        self.diedrico.setFixedSize(2000, 2000)


        self.scene.addWidget(self.diedrico)


        self.setCentralWidget(self.view)


    def set_Value(self):                                              # +++

        self.view.verticalScrollBar().setValue(500)

        self.view.horizontalScrollBar().setValue(500)    


    def keyPressEvent(self, event):

        if event.key() == QtCore.Qt.Key_R:

            self.view.setTransform(QtGui.QTransform())


        elif event.key() == QtCore.Qt.Key_Plus:

            scale_tr = QtGui.QTransform()

            scale_tr.scale(1.5, 1.5)

            tr = self.view.transform() * scale_tr

            self.view.setTransform(tr)


        elif event.key() == QtCore.Qt.Key_Minus:

            scale_tr = QtGui.QTransform()

            scale_tr.scale(1.5, 1.5)

            scale_inverted, invertible = scale_tr.inverted()

            if invertible:

                tr = self.view.transform() * scale_inverted

                self.view.setTransform(tr)



if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)

    ui = UiVentana()

    ui.show()

    sys.exit(app.exec_())


查看完整回答
反对 回复 2022-05-24
  • 2 回答
  • 0 关注
  • 200 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信