2016-05-10 38 views
1

私はQAbstractScrollAreaの詳細を正しく取得するのに多くの問題を抱えています。これはviewportEventの私の現在の実装である: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の


最小作業例:Qtのバグとして提出

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

は:https://bugreports.qt.io/browse/QTBUG-53269

+0

Qtが 'QAbstractScrollArea'をどのように実装しているかを理解する必要があるようです。 'viewportEvent()'は、1)イベントをビューポートに伝播させたくない場合、2)ビューポートに到達する前にイベントを変更したい場合、3)イベントを捕捉したい場合のみ再実装する必要があります。あなたのスクロールエリアで何か他のことをしてください。 –

+0

@JonHarperもしそれが本当であれば、なぜ私は明示的にペイントイベントを転送しない限り、中央のウィジェットはペイントしないのですか? –

+0

@JonHarperそして、私はQtの仕組みを刷新するだけではありません。これをどうすればよいか分かっていれば、答えを自由に追加してください:) –

答えて

1

私の前の回答は絶対に間違っていました。彼の調査のためにOPへの功績。ドキュメント毎の

QAbstractScrollAreaを継承すると、次の操作を行う必要があります。

  • はその範囲、値、ページのステップを設定し、その動きを追跡することによって、スクロールバーをコントロール。

  • スクロールバーの値に従って、ビューポート内の領域の内容を描画します。

  • viewportEvent()のビューポートが受け取ったイベント、特にサイズ変更イベントを処理します。

  • すべてのペイント操作がビューポート上で行われるため、viewport-> update()を使用してupdate()ではなく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) 

私のスクリューアップのお詫び。これが参考になることを願っています。

+0

謝罪する必要はありません!ご協力いただきありがとうございます。 –

関連する問題