viewportEvent 应该如何在 QAbstractScrollArea 中实现?
How should viewportEvent be implemented in a QAbstractScrollArea?
我在获取适合 QAbstractScrollArea
的详细信息时遇到了很多问题。这是我当前实现的 viewportEvent
:
def viewportEvent(self, event):
if event.type() in [QEvent.MouseButtonPress,
QEvent.MouseMove,
QEvent.MouseButtonRelease,
QEvent.ContextMenu,
QEvent.KeyPress,
QEvent.KeyRelease]:
return self.my_viewport.event(event)
if event.type() == QEvent.Resize:
self.my_viewport.resizeEvent(event)
return super().viewportEvent(event)
if event.type() in [QEvent.UpdateLater,
QEvent.UpdateRequest]:
self.my_viewport.event(event)
if event.type() == QEvent.Paint:
self.my_viewport.paintEvent(event)
return super().viewportEvent(event)
这个想法是通过(到视口小部件)按键和鼠标按下之类的东西。调整大小事件需要传递并发送到抽象滚动区域本身?滚动条的大小如何?不应更改调整大小事件的大小。如果我不传递绘制事件,则视口小部件不会绘制。
带有 QAbstractScrollArea 的损坏的 QOpenGLWidget 的最小工作示例:
import sys
from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import (QAbstractScrollArea, QApplication, QMainWindow,
QOpenGLWidget)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.scope_view_widget = ScrollingScopeView()
self.setCentralWidget(self.scope_view_widget)
class ScopeView(QOpenGLWidget):
def paintGL(self):
super().paintGL()
print("Painting")
class ScrollingScopeView(QAbstractScrollArea):
def __init__(self):
super().__init__()
self.set_my_viewport(ScopeView())
def set_my_viewport(self, new_viewport):
self.my_viewport = new_viewport
self.setViewport(self.my_viewport)
def viewportEvent(self, event):
# Uncommenting this breaks painting.
if event.type() == QEvent.Paint:
self.my_viewport.paintEvent(event)
return super().viewportEvent(event)
application = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(application.exec_())
我之前的回答完全错了。感谢 OP 的调查。
根据文档:
When inheriting QAbstractScrollArea, you need to do the following:
Control the scroll bars by setting their range, value, page step, and tracking their movements.
Draw the contents of the area in the viewport according to the values of the scroll bars.
Handle events received by the viewport in viewportEvent() - notably resize events.
Use viewport->update() to update the contents of the viewport instead of update() as all painting operations take place on the viewport.
除非您需要进行其他事件管理,否则您的 MCVE 中非常短的 viewportEvent()
是 正确的 。 Take a look at the code(比我做的更好看)你会看到大多数事件(包括绘画事件)没有传递到视口。奇怪的是,代码确实异常调整大小 QOpenGLWidget
.
我现在意识到 不 默认绘制背后的逻辑是允许您 仅更新当前可见的视口区域 。
总之,下面的就可以了。我建议检查以确保绘画事件仅包括当前可见的矩形(检查绘画事件中 rect()
的值),否则您将绘制当前在视口中不可见的区域。
def viewportEvent(self, event):
# Uncommenting this breaks painting.
if event.type() == QEvent.Paint:
self.my_viewport.paintEvent(event)
return super().viewportEvent(event)
为我的失误道歉。希望对您有所帮助。
我在获取适合 QAbstractScrollArea
的详细信息时遇到了很多问题。这是我当前实现的 viewportEvent
:
def viewportEvent(self, event):
if event.type() in [QEvent.MouseButtonPress,
QEvent.MouseMove,
QEvent.MouseButtonRelease,
QEvent.ContextMenu,
QEvent.KeyPress,
QEvent.KeyRelease]:
return self.my_viewport.event(event)
if event.type() == QEvent.Resize:
self.my_viewport.resizeEvent(event)
return super().viewportEvent(event)
if event.type() in [QEvent.UpdateLater,
QEvent.UpdateRequest]:
self.my_viewport.event(event)
if event.type() == QEvent.Paint:
self.my_viewport.paintEvent(event)
return super().viewportEvent(event)
这个想法是通过(到视口小部件)按键和鼠标按下之类的东西。调整大小事件需要传递并发送到抽象滚动区域本身?滚动条的大小如何?不应更改调整大小事件的大小。如果我不传递绘制事件,则视口小部件不会绘制。
带有 QAbstractScrollArea 的损坏的 QOpenGLWidget 的最小工作示例:
import sys
from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import (QAbstractScrollArea, QApplication, QMainWindow,
QOpenGLWidget)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.scope_view_widget = ScrollingScopeView()
self.setCentralWidget(self.scope_view_widget)
class ScopeView(QOpenGLWidget):
def paintGL(self):
super().paintGL()
print("Painting")
class ScrollingScopeView(QAbstractScrollArea):
def __init__(self):
super().__init__()
self.set_my_viewport(ScopeView())
def set_my_viewport(self, new_viewport):
self.my_viewport = new_viewport
self.setViewport(self.my_viewport)
def viewportEvent(self, event):
# Uncommenting this breaks painting.
if event.type() == QEvent.Paint:
self.my_viewport.paintEvent(event)
return super().viewportEvent(event)
application = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(application.exec_())
我之前的回答完全错了。感谢 OP 的调查。
根据文档:
When inheriting QAbstractScrollArea, you need to do the following:
Control the scroll bars by setting their range, value, page step, and tracking their movements.
Draw the contents of the area in the viewport according to the values of the scroll bars.
Handle events received by the viewport in viewportEvent() - notably resize events.
Use viewport->update() to update the contents of the viewport instead of update() as all painting operations take place on the viewport.
除非您需要进行其他事件管理,否则您的 MCVE 中非常短的 viewportEvent()
是 正确的 。 Take a look at the code(比我做的更好看)你会看到大多数事件(包括绘画事件)没有传递到视口。奇怪的是,代码确实异常调整大小 QOpenGLWidget
.
我现在意识到 不 默认绘制背后的逻辑是允许您 仅更新当前可见的视口区域 。
总之,下面的就可以了。我建议检查以确保绘画事件仅包括当前可见的矩形(检查绘画事件中 rect()
的值),否则您将绘制当前在视口中不可见的区域。
def viewportEvent(self, event):
# Uncommenting this breaks painting.
if event.type() == QEvent.Paint:
self.my_viewport.paintEvent(event)
return super().viewportEvent(event)
为我的失误道歉。希望对您有所帮助。