m
mihenzeҚаз. 12, 2017, 2:15 Т.Қ.

Рисуем линию QGraphicsItem за мышью

Здравствуйте. Два дня пытался сделать отрисовку линии объявленной как QGraphicsItem в сцене. Хочу чтобы при зажатой кнопке прямая линия отрисовывалась за мышью. Но что-то не выходит. Прочитал данный топик https://evileg.com/forum/topic/218/ , но он как раз про простой способ рисования, когда методы мыши реализованы в сцене(это получилось). Но когда я хочу чтобы сам Item отвечал за отрисовку, выходит нечто странное.  Вообщем зашел в тупик и не знаю что делать. Вот мой исходный код:

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "myscene.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    MyScene *pScene = new MyScene(this);
    ui->centralWidget->setScene(pScene);

    connect(ui->actionRect, SIGNAL(triggered(bool)), ui->centralWidget->scene(), SLOT(mySlotLine()));
}

MainWindow::~MainWindow()
{
    delete ui;
}
myscene.h
#ifndef MYSCENE_H
#define MYSCENE_H

#include<QObject>
#include<QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include<QColor>
#include<QString>
#include"myline.h"

class MyScene : public QGraphicsScene
{
    Q_OBJECT
public:
    MyScene(QObject *parent =0);

protected:
    virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent);

private:
    MyLine *line;
    bool isDrawLine = false;
    void addMyLine(QPointF p);


public slots:
    void mySlotLine();

};

#endif // MYSCENE_H
myscene.cpp
#include "myscene.h"

MyScene::MyScene(QObject *parent) : QGraphicsScene(parent)
{

    setSceneRect(0,0,500,500);

    setFocus();

}

void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if ((mouseEvent->button() == Qt::LeftButton)&&(isDrawLine))
    {
        isDrawLine = false;
        addMyLine(mouseEvent->scenePos());
    }
    line->mousePressEvent(mouseEvent);

}

void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    line->mouseMoveEvent(mouseEvent);
}

void MyScene::mySlotLine()
{
    line = new MyLine(this);
    isDrawLine = true;
}

void MyScene::addMyLine(QPointF p)
{

    line->setPoint(p, p);
    line->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
    addItem(line);
}
myline.h
#ifndef MYLINE_H
#define MYLINE_H

#include <QObject>
#include <QGraphicsItem>
#include <QRectF>
#include <QGraphicsSceneMouseEvent>
#include <QPen>
#include <QPainter>

class MyLine : public QObject , public QGraphicsItem
{
    Q_OBJECT
public:
    MyLine(QObject *parent = 0);
    ~MyLine();

    void setPoint(QPointF beginP, QPointF endP);

    virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

protected:
    virtual QRectF boundingRect() const;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

private:
    QPointF p1;
    QPointF p2;


};

#endif // MYLINE_H
myline.cpp
#include "myline.h"

MyLine::MyLine(QObject *parent): QObject(parent), QGraphicsItem()
{

}

MyLine::~MyLine()
{

}

void MyLine::setPoint(QPointF beginP, QPointF endP)
{
    p1 = beginP;
    p2 = endP;
}

void MyLine::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mousePressEvent(event);
}

void MyLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    p2 = event->scenePos();
    this->setPoint(p1, p2);
    QGraphicsItem::mouseMoveEvent(event);
}

void MyLine::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mouseReleaseEvent(event);
}

QRectF MyLine::boundingRect() const
{
    return QRectF(p1,p2).normalized();
}

void MyLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QPen pen;

    pen.setWidth(5);
    pen.setBrush(Qt::black);

    painter->setPen(pen);

    if (p1 == p2)
    {
        painter->drawPoint(p1);
    }
    else
    {
        painter->drawLine(p1,p2);
    }
}
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

4
Evgenii Legotckoi
  • Қаз. 13, 2017, 3:14 Т.Ж.

Добрый день!

Фух, надо будет у себя повторить ваш код, да посмотреть, как у вас работает, если имеете возможность, то прикрепите в сообщении архив проекта. Я вечером после работы гляну его.
    m
    • Қаз. 13, 2017, 3:32 Т.Ж.

    Файлы проекта

      Evgenii Legotckoi
      • Қаз. 14, 2017, 8:29 Т.Ж.
      • (өңделген)

      Я поправил немного Ваш код.

      Смотрите какие здесб будут моменты:
      Не нужно передавать mouseEvent в метод mouseMoveEvent(), лучше сделать отдельный методв для установки конечной точки линии и вызывать метод перерисовки.
      void MyLine::setEndPoint(QPointF endPoint)
      {
          p2 = endPoint;
          update();
      }
      Также, неправильная реализация методы boundingRect(), там нужно следить за правильностью использования точек topLeft и rightBottom, поскольку точки p1 и p2 могут им несоответсвуовать в линии.
      QRectF MyLine::boundingRect() const
      {
          QPointF topLeft = QPointF(p1.x() < p2.x() ? p1.x() : p2.x(),
                                    p1.y() < p2.y() ? p1.y() : p2.y());
          QPointF rightBootom = QPointF(p1.x() > p2.x() ? p1.x() : p2.x(),
                                        p1.y() > p2.y() ? p1.y() : p2.y());
          return QRectF(topLeft, rightBootom);
      }
      Метода mouse event`ов в линии не потребуются в данном случае, я их удалил.
      Также несколько поправил методы перемещения мыши в графической сцене.
      void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
      {
          if ((mouseEvent->button() == Qt::LeftButton)&&(isDrawLine))
          {
              isDrawLine = false;
              addMyLine(mouseEvent->scenePos());
          }
      }
      
      void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
      {
          line->setEndPoint(mouseEvent->scenePos());
          update();
      }
      Весь проект во вложении.
        m
        • Қаз. 15, 2017, 11:30 Т.Ж.

        Большое спасибо!

          Пікірлер

          Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
          Кіріңіз немесе Тіркеліңіз
          Г

          C++ - Тест 001. Первая программа и типы данных

          • Нәтиже:66ұпай,
          • Бағалау ұпайлары-1
          t

          C++ - Тест 001. Первая программа и типы данных

          • Нәтиже:33ұпай,
          • Бағалау ұпайлары-10
          t

          Qt - Тест 001. Сигналы и слоты

          • Нәтиже:52ұпай,
          • Бағалау ұпайлары-4
          Соңғы пікірлер
          G
          GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
          Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
          d
          dblas5Шілде 5, 2024, 11:02 Т.Ж.
          QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
          k
          kmssrАқп. 8, 2024, 6:43 Т.Қ.
          Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
          АК
          Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
          Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
          Енді форумда талқылаңыз
          Evgenii Legotckoi
          Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
          добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
          F
          FynjyШілде 22, 2024, 4:15 Т.Ж.
          при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
          BlinCT
          BlinCTМаусым 25, 2024, 1 Т.Ж.
          Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
          BlinCT
          BlinCTМамыр 5, 2024, 5:46 Т.Ж.
          Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
          Evgenii Legotckoi
          Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
          Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

          Бізді әлеуметтік желілерде бақылаңыз