如何在QAbstractScrollArea中实现viewportEvent?

时间:2016-05-10 01:43:54

标签: qt pyqt qt5 pyqt5

我在为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)

这个想法是通过键盘和鼠标按下来传递(到视口小部件)。调整大小事件需要传递并发送到抽象滚动区域本身?滚动条的大小怎么样?不应该更改resize事件的大小。如果我没有传递绘制事件,则视口窗口小部件不会绘制。

使用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_())

归档为Qt错误:https://bugreports.qt.io/browse/QTBUG-53269

1 个答案:

答案 0 :(得分:1)

我之前的回答是绝对错误的。感谢OP的调查。

根据文档:

  

继承QAbstractScrollArea时,您需要执行以下操作:

     
      
  • 通过设置其范围,值,页面步长以及跟踪其移动来控制滚动条。

  •   
  • 根据滚动条的值绘制视口中区域的内容。

  •   
  • 处理viewportEvent()中视口收到的事件 - 特别是调整事件大小。

  •   
  • 使用viewport-> update()更新视口的内容而不是update(),因为所有绘制操作都在视口上进行。

  •   

除非您需要进行其他事件管理,否则您的MCVE中的viewportEvent()非常短正确Take a look at the code(比我更好看)你会发现大多数事件(包括绘画事件)都没有传递给视口。奇怪的是,代码确实例外地适当调整QOpenGLWidget的大小。

我现在意识到默认情况下绘画背后的逻辑是允许您仅更新当前可见的视口区域

简而言之,以下是好的。我建议检查以确保paint事件仅包含当前可见的rect(在paint事件中检查rect()的值),否则您将绘制当前在视口中不可见的区域。

def viewportEvent(self, event):
    # Uncommenting this breaks painting.
    if event.type() == QEvent.Paint:
        self.my_viewport.paintEvent(event)
    return super().viewportEvent(event)

为我的搞砸而道歉。我希望这有用。