2013-12-17 100 views
3

This is what i mean that happens, first tried a circle, then on the right a square我想繪製不同的任意數字。繪圖在圖形視圖中單擊鼠標並在停止單擊鼠標時結束。但是,從圖形視圖的不同點開始製作新圖形或繼續上一張圖形時,會從第一個圖形的最後一個鼠標座標繪製到第二個圖形的第一個座標。圖紙不一定需要是不同的圖紙,但也可以只是對圖紙進行調整。這是我的代碼。Qt:Line連接2個獨立的圖紙

#include "mousedraw.h" 
#include <QDebug> 

MouseDraw::MouseDraw() 
{ 
    setFlag(ItemIsMovable); 
} 

QRectF MouseDraw::boundingRect() const 
{ 
    return QRectF(0,0,300,300); 
} 

void MouseDraw::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,  QWidget *widget) 
{ 
    QPainterPath path; 
    path.addPolygon(polyPoints2); 
    painter->setPen(QPen(QColor(qrand() % 256, qrand() % 256, qrand() % 256),3)); 
    painter->drawPath(path); 
} 

void MouseDraw::mouseMoveEvent(QGraphicsSceneMouseEvent *event) 
{ 
    QPointF point = event->pos(); 
    if (boundingRect().contains(point)) { 
     array1 = point.x(); 
     array2 = point.y(); 
     polyPoints2 << QPoint(array1,array2); 
     update(); 
    } 
} 
+1

必須重新定義'QGraphicsScene'或'QGraphicsView'鼠標事件,而不是父母widget's那些 – dvvrd

+1

另外'setMouseTracking(真)'應一次在構造函數中調用。只有在不按鼠標按鈕的情況下追蹤鼠標移動時才需要它。 –

+0

不,我不想連接,連接是我的問題,但我不知道如何解決這個問題..所有的圖紙都需要在一個步驟中完成,問題是當例如繪製一個正方形時,首先從左向右繪製,然後從右到頂,如果你然後釋放鼠標按鈕並在左下方再次單擊它來繪製一條線,例如,一條線也從右上到左下繪製 – user3110781

回答

1

擁有自QGraphicsItem派生的自定義MouseDraw類是不必要的。有一個QGraphicsPathItem,正確地爲你處理這一切。

在創建的項目內處理鼠標交互在概念上是不正確的 - 您的大邊界矩形是它需要的黑客工作,但這是錯誤的方法。您不希望項目與鼠標進行交互。您希望場景與鼠標交互並即時創建項目。只有當編輯一個現有的項目,你想有鼠標交互,但即使如此,最好創建一個單獨的編輯器項目覆蓋被編輯的項目上,以處理編輯交互。

用鼠標右鍵單擊窗口以獲得一個上下文菜單,其中包含清除圖片的操作。您也可以切換後續路徑是否加入前一個路徑。這個代碼是用Qt 4.8.5和5.2測試的。

當場景小於視圖時,視圖堅持居中(使用alignment屬性)。使用EmptyItem作爲此「特徵」的解決方法,以在場景小於視圖時(包括場景爲「空」時)約束場景內場景的位置。

該代碼爲每個不相交的路徑創建一個單獨的項目 - QGraphicsScene通常會對多個不重疊的項目執行最佳操作。您當然可以保留一個項目,並在每次按下鼠標時不斷添加新的細分,但這最終會對性能產生影響 - 尤其是在您放大場景的情況下,您希望性能會變得更好被顯示。

screenshot

// https://github.com/KubaO/stackoverflown/tree/master/questions/gscene-paint-20632209 
#include <QtGui> 
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) 
#include <QtWidgets> 
#endif 

class EmptyItem : public QGraphicsItem 
{ 
public: 
    EmptyItem(QGraphicsItem * parent = nullptr) : QGraphicsItem{parent} {} 
    QRectF boundingRect() const override { return {0, 0, 1, 1}; } 
    void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {} 
}; 

class Scene : public QGraphicsScene 
{ 
    Q_OBJECT 
    Q_PROPERTY(bool joinFigures READ joinFigures WRITE setJoinFigures) 
    bool m_joinFigures = false; 
    QGraphicsPathItem * m_item = nullptr; 
    QPainterPath m_path; 

    void newItem() { 
     addItem(m_item = new QGraphicsPathItem); 
     m_item->setPen(QPen{{qrand() % 256, qrand() % 256, qrand() % 256}}); 
     m_path = QPainterPath{}; // using std::swap; swap(m_path, QPainterPath()); 
    } 
    void newPoint(const QPointF& pt) { 
     if (! m_item) { 
      newItem(); 
      m_path.moveTo(pt); 
     } else { 
      m_path.lineTo(pt); 
      m_item->setPath(m_path); 
     } 
    } 
    void mousePressEvent(QGraphicsSceneMouseEvent * ev) override { 
     if (ev->buttons() != Qt::LeftButton) return; 
     if (! m_joinFigures) m_item = nullptr; 
     newPoint(ev->scenePos()); 
    } 
    void mouseMoveEvent(QGraphicsSceneMouseEvent *ev) override { 
     if (ev->buttons() != Qt::LeftButton) return; 
     newPoint(ev->scenePos()); 
    } 
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *) override { 
     if (! m_path.isEmpty()) return; 
     delete m_item; // Empty items are useless 
     m_item = nullptr; 
    } 
public: 
    Scene(QObject *parent = nullptr) : QGraphicsScene{parent} 
    { 
     addItem(new EmptyItem{}); 
    } 
    Q_SLOT void setJoinFigures(bool j) { m_joinFigures = j; } 
    bool joinFigures() const { return m_joinFigures; } 
}; 

class Window : public QWidget 
{ 
    Q_OBJECT 
    QGridLayout m_layout{this}; 
    QGraphicsView m_view; 
    QCheckBox m_join{"Join Figures (toggle with Spacebar)"}; 
    QAction m_toggleJoin{this}; 
public: 
    Window(QWidget * parent = 0) : QWidget{parent} 
    { 
     m_layout.addWidget(&m_view); 
     m_layout.addWidget(&m_join); 
     m_view.setAlignment(Qt::AlignLeft | Qt::AlignTop); 

     m_toggleJoin.setShortcut(QKeySequence(Qt::Key_Space)); 
     connect(&m_toggleJoin, SIGNAL(triggered()), &m_join, SLOT(toggle())); 
     addAction(&m_toggleJoin); 

     m_view.addAction(new QAction{"Clear", this}); 
     m_view.setContextMenuPolicy(Qt::ActionsContextMenu); 
     connect(m_view.actions().at(0), SIGNAL(triggered()), SLOT(newScene())); 

     // Create a new scene instead of clear()-ing it, since scenes can only grow their 
     // sceneRect(). 
     newScene(); 
    } 
    Q_SLOT void newScene() { 
     if (m_view.scene()) m_view.scene()->deleteLater(); 
     m_view.setScene(new Scene); 
     m_view.scene()->connect(&m_join, SIGNAL(toggled(bool)), SLOT(setJoinFigures(bool))); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication a{argc, argv}; 
    Window w; 
    w.show(); 
    return a.exec(); 
} 

#include "main.moc" 
+0

我使用了不同的方法,這也是有效的,但是這不允許在沒有連接它們的情況下繪製單獨的數字。我也嘗試過你的方法,但我無法得到它的工作,它看起來像你可以繪製幾個firgures沒有他們連接。我也無法改變我的筆的顏色。 – user3110781

+0

我還有一個關於這個的問題,這個按鈕是如何工作的?通常我會去設計並拖放按鈕然後連接它們。但是這種設置似乎並不奏效? – user3110781

+0

@ user3110781:​​我不知道你的意思。你的意思是如何將'Window'集成到一個被設計成.ui文件的小部件/對話框中? –

0

創建一個從QGraphicsItem或QGraphicsObject繼承的類,如果您需要信號和插槽。

將QPainterPath存儲爲類的成員。當您檢測到按下鼠標按鈕時,調用畫筆路徑moveTo()函數,提供座標。在接收到鼠標移動事件時,使用座標調用畫家路徑lineTo()函數。

重載boundingRect函數以返回畫家路徑的矩形,並重載shape()函數以返回碰撞的正確形狀。

最後在類的繪畫函數中繪製畫家路徑。這是一個你可以使用的骨架類。

class MouseDraw : public QGraphicsItem 
{ 
    public: 
     QRectF boundingRect() const 
     { 
      return m_painterpath.boundingRect(); 
     } 

     QPainterPath shape() const 
     { 
      return m_painterpath; 
     } 

     void QGraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) 
     { 
      // setup pen and brush 
      // .... 
      // draw the path 

      painter->drawPath(m_painterpath); 
     } 

    private: 
     QPainterPath m_painterpath; 
}; 

處理好mousePress,的mouseMove和mouseRelease事件所需的點添加到畫家路徑,然後實例化類的一個對象,並將其添加到場景: -

MouseDraw* mouseDraw = new MouseDraw; 
scene->addItem(mouseDraw); 

注意,對象僅添加一次到場景中並動態創建。