2013-12-17 4 views
3

This is what i mean that happens, first tried a circle, then on the right a square 다른 임의의 그림을 그립니다. 그래픽 뷰에서 마우스를 클릭하면 그리기가 시작되고 마우스를 클릭하지 않으면 끝납니다. 그러나 그래픽 뷰의 다른 지점에서 시작하여 새 도면을 만들거나 이전 도면에서 계속 진행하면 첫 번째 도면의 마지막 마우스 좌표에서 두 번째 도면의 첫 번째 좌표까지 선이 그려집니다. 도면은 반드시 다른 도면 일 필요는 없지만 도면에 대한 조정 일 수도 있습니다. 이것은 내 코드입니다.Qt : 선이 두 개의 도면을 연결합니다.

#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' 마우스 이벤트가 아니라 부모 – dvvrd

+1

은 또한,'setMouseTracking은 (참)'생성자에 한 번 호출 할 필요가 사람을 widget's. 또한 마우스 버튼을 누르지 않고 마우스 움직임을 추적하려는 경우에만 필요합니다. –

+0

아니, 내가 원하는 연결을 내 문제는 연결하지만,이 문제를 해결하는 방법을 모릅니다 .. 모든 도면을 한 이동으로 만들 필요가있다, 문제는 예를 들어 사각형을 그릴 때 처음부터 왼쪽에서 오른쪽으로 그립니다. , 오른쪽에서 위로, 그리고 나서 마우스 단추를 놓고 왼쪽 하단에서 다시 한 번 클릭하여 줄을 그리려면 예를 들어, 오른쪽 상단에서 왼쪽 아래로도 그려집니다. – user3110781

답변

1

맞춤형 MouseDrawQGraphicsItem에서 파생 된 클래스가 필요하지 않습니다. 모든 것을 정확하게 처리하는 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

다른 접근법을 사용했습니다. 그것은 또한 작동하지만,이 doesnt는 그들을 연결하지 않고 별도의 그림을 그릴 수 있습니다. 나는 또한 당신의 접근법을 시도했지만 나는 그것을 작동시키지 못한다. 당신이 연결되지 않고 여러 가지 firgures를 그릴 수있는 것처럼 보인다. 나는 또한 내 펜의 색을 바꿀 수 없다. – user3110781

+0

나는 이것에 대해 한 가지 더 질문이 있습니다. 어떻게이 버튼을 사용할 수 있습니까? 일반적으로 디자인에 가서 버튼을 드래그 앤 드롭 한 다음 연결합니다. 그러나 작동하지 않는이 설치로? – user3110781

+0

@ user3110781 : 무슨 뜻인지 모르겠다. .ui 파일로 설계된 위젯/대화 상자에'Window'를 통합하는 방법을 의미합니까? –

0

신호 및 슬롯을 원하면 QGraphicsItem 또는 QGraphicsObject에서 상속 된 클래스를 만듭니다.

QPainterPath를 클래스의 멤버로 저장하십시오. 마우스 버튼을 눌렀을 때 좌표를 제공하는 painter path moveTo() 함수를 호출하십시오. 마우스 이동 이벤트를 받으면 좌표를 사용하여 painter 경로 lineTo() 함수를 호출하십시오.

boundingRect 함수를 오버로드하여 페인터 경로의 rect를 반환하고 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); 

주 오브젝트는 장면에 한 번만 추가되고 동적으로 작성됩니다.

관련 문제