2 回答
TA贡献1712条经验 获得超3个赞
给出的答案很好,但我想补充一些关于您为什么面临这个问题以及“幕后”发生的事情的见解。
首先,在您的代码中,您尝试在将任何对象添加到场景之前设置滚动条的值。
那时,您刚刚创建了视图和场景。视图小部件尚未显示(因此它还不“知道”它的实际大小),并且场景是空的,这意味着它sceneRect
是null,如 0 宽度和 0 高度:在这种情况下,滚动条有最大值为 0,设置任何值都不会产生任何结果。
注意:要记住一个非常重要的方面:除非显式声明或请求,否则
sceneRect
QGraphicsScene 的 始终为空,直到视图显示它。我所说的“请求”是指即使只是调用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.
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_())
添加回答
举报