2013-12-17 29 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); 

注意,对象仅添加一次到场景中并动态创建。