2010-03-15 92 views
11

這一直在竊聽我兩天以上,所以我想我應該問。我在Win7上使用Qt 4.5.3(使用VC2008編譯)。QGraphicsView和eventFilter

我有MyGraphicsView(繼承QGraphicsView)和MyFilter(繼承QObject)類。

當我安裝MyFilter對象作爲事件過濾器MyGraphicsView,鼠標事件他們交付給MyGraphicsView而關鍵事件被傳遞到MyFilter 他們交付給MyGraphicsView之前後交付給MyFilter

在第二種情況下,我安裝MyFilter對象作爲事件過濾器MyGraphicsView->視口()(其是非標準QGLWidget來繪圖),鼠標事件它們被輸送到MyGraphicsView之前遞送到MyFilter ,而關鍵活動僅發送到 MyGraphicsView。

事件應該在事件過濾器傳遞到實際對象之前傳遞給事件過濾器,那麼爲什麼會發生這種情況?我應該怎麼做才能確保這個訂單?

在此先感謝。 最好的問候。

+1

由於ordet似乎是這個問題,可能是你的代碼片段將是有用的。 – gregseth 2010-03-19 07:55:56

+0

好男人,這裏是鏈接到最小的代碼,再現問題。 http://rapidshare.com/files/363574158/QGVEF.rar – erelender 2010-03-22 07:25:28

回答

12

的QGraphicsView是QAbstractScrollArea的子類,是這些行爲的原因。

在第一種情況下,當調用setViewport()時,QAbstractScrollArea將其自身作爲事件過濾器添加到MyGraphicsView。 QAbstractScrollArea的事件過濾器捕獲鼠標事件,首先通過viewportEvent()將其發送,然後發送到傳播給MyGraphicsView鼠標事件處理程序的QWidget事件處理。只有在這之後,QAbstractScrollArea的事件過濾器才能完成,MyFilter才能運行。

在第二種情況下,關鍵事件僅傳遞給MyGraphicsView,因爲在setViewport()中,QAbstractScrollArea將自己設置爲焦點代理。如果使用以下代碼重置焦點代理,則將傳遞關鍵事件。

w.viewport()->setFocusProxy(0); 

一種替代方法是從另一方的一個對象和鼠標事件在兩個圖形視圖,其視口安裝事件過濾器,但修改濾波器僅過程中的關鍵事件。

變化MyFilter.h

QObject *keyObj; 
    QObject *mouseObj; 

public: 
    MyFilter(QObject *keyObj, QObject *mouseObj, QObject *parent = NULL); 

變化MyFilter.cpp

MyFilter::MyFilter(QObject *keyObj, QObject *mouseObj, QObject *parent /*= NULL*/) : QObject(parent), keyObj(keyObj), mouseObj(mouseObj) 

if (obj == keyObj && e->type() == QEvent::KeyPress) 
{ 
    qDebug()<<"Key Event recieved by MyFilter"; 
} 
else if (obj == mouseObj && e->type() == QEvent::MouseButtonPress) 
{ 
    qDebug()<<"Mouse Event recieved by MyFilter"; 
} 

變化的main.cpp

MyFilter *filter = new MyFilter(&w, w.viewport(), &w); 

// Use this line to install to the viewport 
w.viewport()->installEventFilter(filter); 

//Use this line to install to MyGraphicsView 
w.installEventFilter(filter); 
+0

其實,這就是我現在正在做的,但我認爲它更像是一種解決方法,而不是解決方案。我的事件過濾器來自插件,我不認爲處理基於對象的事件過濾應該是他們關心的問題。儘管如此,感謝解釋爲什麼會發生這種情況。 – erelender 2010-03-24 08:08:42

+0

儘管我認爲我以前的解釋總體上是正確的,但我認爲這是一個更好的解釋。如果您不關心滾動區域的關鍵事件處理(向上翻頁,向下翻頁等),那麼在視口上安裝事件過濾器並清除其焦點代理是更簡單的解決方案。否則,在MyGraphicsView和viewport上安裝事件過濾器可能會更好。 – baysmith 2010-03-24 08:30:11

+0

你是對的,你以前的解決方案可能更適合一般用途。在我的情況下,我試圖用Qt和OSG做一些奇特的東西,這就是爲什麼我的大部分問題都沒有解決的原因:)。這個解決方案像我的手套一樣適合我的情況,謝謝。但爲了將來的參考,您可以將您的舊解決方案作爲另一個答案發布,以便其他人可以看到它嗎?它可以通過「編輯:...之前」鏈接訪問。 – erelender 2010-03-24 09:59:30

-2

如何儘量不使用過濾器,但需要重新實現QEvent的處理器在MyGraphicsView喜歡這裏:

void MyGraphicsView::mousePressEvent(QMouseEvent* pe) 
{ 
if (pe->buttons() & Qt::LeftButton) 
{ 
    this->setCursor(Qt::CrossCursor); 
    zoomOrigin = pe->pos(); 
    rubberBand = new QRubberBand(QRubberBand::Rectangle, this); 
    rubberBand->setGeometry(QRect(zoomOrigin, QSize(0,0))); 
    rubberBand->show(); 
} 
if (pe->buttons() & Qt::MidButton) 
{ 
    panOrigin = pe->pos(); 
     this->setCursor(Qt::ClosedHandCursor); 
} 
} 
+0

我已經這樣做了。但是,對於我而言,子類化和事件過濾是出於不同目的和不可互換的。 – erelender 2010-03-19 14:44:26

+1

好的,如果你真的需要事件過濾,可能會有eventFilter()方法返回的true/false-value不正確的問題,請確保它不是你的情況。此外,我將測試項目上傳到http://uploading.com/files/7c7adam5/graphicsview.zip/,該項目按照假定的方式處理事件。它已經在Slackware Linux上用當前git版本的Qt進行了編譯。所以如果這個測試項目不能與你的Qt版本(4.5.3)一起工作,這可能是Qt的一個問題,已經被修復了,但對我來說並不是這樣。也可以是平臺相關的「功能」。祝你好運! – 2010-03-19 18:56:14

+0

你的例子也適用於Qt 4.5.3,因爲它與我的不一樣。在你的例子中,graphicsview的子類是QWidget,而不是QGraphicsView。另外,事件過濾器安裝在graphicsview(QWidget的子類)上,而不是QGraphicsView上,我發佈了重現問題的示例代碼。如果你看看它,你會更好地理解我的問題。 – erelender 2010-03-22 07:30:01