2011-01-15 50 views
4

創建長十字線光標(與視口一樣長)的簡單方法是創建一條交叉線graphicsItem,當鼠標移動時,設置項目的pos屬性。 但是當場景很複雜時,這種方式會很慢,因爲它應該更新整個視口來更新光標的pos在Qt GraphicsView中創建長線(或十字線)光標的最佳方法

另一個簡單的方法是setCursor(QCursor(..)),使用一個QPixmap來定義長十字線,這種方式會非常快,但光標將超過視口矩形。

是否有另一種快速顯示長十字線光標的方法?

非常感謝!

+1

關於setCursor的問題又是什麼?你可以在QWidget上設置光標,這樣你就可以將光標設置到由QGraphicsView :: viewport()返回的小部件上。 –

+0

感謝您的建議,setCursor函數不會將光標剪輯到窗口小部件,所以光標(長行)將超過視口,在桌面上繪製等。 – jnblue

回答

10

如果我理解正確,您想繪製水平線和垂直線,在光標位置交叉,並且與視口一樣大。

一個可行的解決方案是重新實現QGraphicsScene::drawForeground()與畫家畫兩條線。

問題是,場景不知道鼠標的位置。這意味着視圖必須跟蹤它並在鼠標位置發生變化時通知場景。

要做到這一點,您必須創建自己的GraphicsScene(繼承QGraphicsScene)和您自己的GraphicsView(繼承QGraphicsView)。

在您的GraphicsView構造函數中,您必須開始鼠標跟蹤。這將使您會收到一個mouseMoveEvent每個視圖內的鼠標移動時間:

GraphicsViewTrack::GraphicsViewTrack(QWidget* parent) : QGraphicsView(parent) { 
    setMouseTracking(true); 
} 

void GraphicsViewTrack::mouseMoveEvent(QMouseEvent* pEvent) { 
    QPointF MousePos = this->mapToScene(pEvent->pos()); 
    emit mousePosChanged(MousePos.toPoint()); 
} 

正如可以在上面的代碼段看到,該視圖發射的信號(mousePosChanged)的場景將被連接到。該信號包含鼠標位置,轉換爲場景的座標。現在

,在場邊,你必須添加一個當鼠標位置變更後,將被稱爲插槽,存儲在一個成員變量的新鼠標位置並重新實現QGraphicsScene::drawForeground()

void GraphicsSceneCross::drawForeground(QPainter* painter, const QRectF& rect) { 
    QRectF SceneRect = this->sceneRect(); 

    painter->setPen(QPen(Qt::black, 1)); 
    painter->drawLine(SceneRect.left(), m_MousePos.y(), SceneRect.right(), m_MousePos.y()); 
    painter->drawLine(m_MousePos.x(), SceneRect.top(), m_MousePos.x(), SceneRect.bottom()); 
} 

void GraphicsSceneCross::onMouseChanged(QPoint NewMousePos) { 
    m_MousePos = NewMousePos; // Store the mouse position in a member variable 
    invalidate(); // Tells the scene it should be redrawn 
} 

的最後一件事要做的就是將GraphicsView的信號連接到GraphicsScene插槽。

我會讓你檢查這個解決方案是否可以接受性能。

+0

非常感謝! – jnblue

+0

如果我的答案對您有幫助,請將其標記爲已接受並投票! –

+0

你的解決方案只比我的第一個方法快一點,因爲drawforeground()不需要重新創建所有項目的BSPIndex,但麻煩是invalidate(),此方法將調用update(),因此所有項目視口將被重繪。 – jnblue

0

我找到了一種方法來做到這一點! 我是在Windows系統下開發的,所以可以使用較低的GDI api跳出Qt的繪製系統。 細節是獲得QGraphicsView的viewPort的HDC。然後在QGraphicsView的QMouseEvent中使用「MoveToEx」和「LineTo」在視口上畫兩條線,然後我應該做的是擦除「舊」光標,使用「setROP2(HDC dc,R2_NOT)」很容易做到這一點,然後再次繪製舊的光標。 此方法不會進入QPainter系統,因此光標下的GraphicsItems不會被重新繪製。

爲了解決鼠標移動速度快的問題,我不使用「雙緩衝區」。我使用QTimer在CPU空閒時更新光標。詳細信息在QMouseEvent中,不要在時間更新光標,但將位置存儲到列表中,當CPU空閒時,在位置列表上繪製光標

我希望這可以幫助滿足相同問題的其他人跟我。 謝謝Jérôme,他給了我QGraphicsScene的有用提示。

1

基於傑羅姆的答案,使用python我在QGraphicsScene子創造了這個代碼:

def drawForeground(self, painter, rect): 
    if self.guidesEnabled: 
     painter.setClipRect(rect) 
     painter.setPen(self.guidePen) 
     painter.drawLine(self.coords.x(), rect.top(), self.coords.x(), rect.bottom()) 
     painter.drawLine(rect.left(), self.coords.y(), rect.right(), self.coords.y()) 

def mouseMoveEvent(self, event): 
    self.coords = event.scenePos() 
    self.invalidate() 

它應該是簡單明瞭爲你寫的appropiate C++代碼。請注意,我利用Qt Api框架傳遞的參數rect,並將畫家剪輯到該區域,因爲它是可見區域。

我也緩存筆對象,因爲我在其他實驗中意識到在繪畫時創建對象會損害性能並執行此操作,因此您還可以給用戶在程序選項中設置自定義筆的機會。

相關問題