Михаиллл
Михаиллл11 июня 2019 г. 3:01

Как в QGraphicsScene стирать старый рисунок при рисовании нового рисунка поверх старого рисунка

QGraphicsScene

Добрый день.
При рисовании в QGraphicsScene непрозрачным цветом, я рисую поверх старого рисунка. При рисовании прозрачным цветом, прозрачный цвет не виден, он остается под старым рисунком(наверно). Как при рисовании стирать старый рисунок и показывать новый?
Рисую как в статье: Qt/C++ - Урок 021. Рисование мышью в Qt

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

17
Evgenii Legotckoi
  • 11 июня 2019 г. 4:22

Добрый день.

Давайте для начала определимся, что значит рисовать прозрачным цветом? Если вы рисуете каким-то цветом и он прозрачный, то это одно. А если вы стираете, или думаете что стираете картинку, то это совершенно другое. Это другой инструмент. Там нужно реализовывать логику для удаления части изображения.

    Evgenii Legotckoi
    • 11 июня 2019 г. 4:23

    И зачем вы тему добавили в PyQt5 раздел, если вопрос чисто по Qt/C++

      Михаиллл
      • 11 июня 2019 г. 4:43

      Извините, с разделом ошибся.
      Сначало я нарисовал сцен этим QPen

          myPen.setWidth(20);
          myPen.setColor(Qt::green);
          myPen.setCapStyle(Qt::RoundCap);
          myPen.setStyle(Qt::SolidLine);
      

      Потом рисую этим QPen

          myPen.setWidth(20);
          myPen.setColor(Qt::green);
          //myPen.setColor(QColor(255, 0, 0, 10));
          myPen.setCapStyle(Qt::RoundCap);
          myPen.setStyle(Qt::SolidLine);
      

      Там , где я не рисовал сплошным цветом, виден цвет QColor(255, 0, 0, 10), но там где рисовал Qt::green, там не виден QColor(255, 0, 0, 10).
      И если много раз провести на одном месте QColor(255, 0, 0, 10), то прозрачность меняется в сторону уменьшения прозрачности, видимо цвета накладываются друг на друга.
      Мне нужно удолять старый рисунок под QPen и рисовать новый. Скажите пожалуйста, как это сделать.

        Evgenii Legotckoi
        • 11 июня 2019 г. 5:13
        • (ред.)
        • Ответ был помечен как решение.

        Это значительно сложнее будет. Я могу вам подсказать направление.

        1. Все объекты, которые вы добавляете на графическую сцену, хорошо было бы помещать также в pool объектов. У меня есть пример подобного пула в статье о написании игры . Там пул объектов яблок. Это позволит держать список объектов изображений например.
        2. Вам нужно добавить инструмент ластик (его нужно будет написать самостоятельно), который будет рисовать линию, а после завершения рисования, нарисованная линия должна будет создать полигон пересечения с изображением и удалить часть изображения. Нужно будет линию преобразовать в QPolygon, потом взять изображение, создать из него QPolygon области изображения, и с помощью метода QPolygon QPolygon::intersected(const QPolygon &r) const найти вырезаемую часть, которую нужно будет отнять от изображения.
        3. Отнять от изображения полигон. С этим уже сложнее, нужно поискать информацию по запросу crop image polygon. Вариантов там может быть несколько, либо через shape показывать только определённую часть изображения в QGraphicsPixmapItem, нужно будет от него наследоваться и написать свой класс для работы с изображением. Либо создать новой изображение с отрезанной частью и заменить им существующее изображение.

        По поводу создания инструментов, типо карандаш, ластик, линия или ещё что-то можете посмотреть статью о векторном редакторе . Там есть пара инструментов - линии и квадраты, можете посмотреть идеологию, как это там сделано. В качестве абстрактного примера.

          Михаиллл
          • 11 июня 2019 г. 5:45
          • (ред.)

          Не получится разбить на много объектов, так как при загрузке загружаетсяо дним объектом.
          Но 2 и 3 реализуемы, хоть и с трудом.

          А если рисовать с помощью QPainter , новый цвет пиксля будет заменять старый цвет?

            Михаиллл
            • 11 июня 2019 г. 5:51

            Или может быть можно рисовать попиксельно на QGraphicsScene? И потом эти пиксели земенять новыми?

              Evgenii Legotckoi
              • 11 июня 2019 г. 5:55

              1,2,3 - это не возможные варианты, а пошаговое решение. То есть я вам предложил всего один вариант, как это можно сделать, который совмещает всю эту работу из трёх основных составляющих частей. Ну а если вы загружаете два рисунка одним объектом... что мне до конца непонятно... То тогда вам придётся разделить на два самостоятельных объекта оба рисунка и работать с ними отдельно. В общем задачка интересная сама по себе. Но вопрос реализации довольно обширный. Думаю, что пару тысяч строк кода потянет.

              Хотя, конечно, можете попробовать и пискели заменять, но тоже вопрос, как вы будете определять откуда и куда заменять эти пиксели. Но это явно нехорошее решение, ведь вы потом захотите ещё и передвигать изображения, вот тогда то вам и выйдет боком это передвижение пикселей.

                Михаиллл
                • 11 июня 2019 г. 6:15

                Я ограничусь только рисованием пикселей, поэтому не дойду то момента, когда мне выйдет боком.
                Если рисовать пикселями, то по идее, ластик будет легко реализыем просто прозрачным цветом.
                Скажите пожалуйста как заменить эти векторы на пиксели:

                void paintScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
                {
                    // При нажатии кнопки мыши отрисовываем эллипс
                    addEllipse(event->scenePos().x() -  myPen.width()/2,
                               event->scenePos().y() -  myPen.width()/2,
                               myPen.width(),
                                myPen.width(),
                               QPen(Qt::NoPen),
                               QBrush(myPen.color()));
                    // Сохраняем координаты точки нажатия
                    previousPoint = event->scenePos();
                    buttonIsPressed = true;
                }
                
                void paintScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
                {
                    if (buttonIsPressed)
                    {
                        // Отрисовываем линии с использованием предыдущей координаты
                        addLine(previousPoint.x(),
                                previousPoint.y(),
                                event->scenePos().x(),
                                event->scenePos().y(),
                                myPen);
                        // Обновляем данные о предыдущей координате
                        previousPoint = event->scenePos();
                    }
                }
                
                  Михаиллл
                  • 11 июня 2019 г. 6:45
                  • (ред.)

                  Попробовал сделать так , но получаю ошибку : QPainter::drawPoints: Painter not active. Скажите пожалуйста как это исправить

                  void paintScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
                  {
                      myPainter.setPen(myPen);
                      myPainter.drawPoint(event->scenePos().x(),event->scenePos().y());
                  
                  }
                  
                    Михаиллл
                    • 11 июня 2019 г. 9:00
                    • (ред.)

                    Сделал так, но рисунок не рисуется.

                    void paintScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
                    {
                        x = event->scenePos().x();    
                        y = event->scenePos().x();
                    }
                    
                    void paintScene::paintEvent(QPaintEvent *event)
                    {
                        QPainter myPainter; 
                        myPainter.setPen(myPen);
                        myPainter.drawPoint(x,y);
                    }
                    

                    void paintScene::paintEvent(QPaintEvent *event) не срабатывает.

                      Михаиллл
                      • 11 июня 2019 г. 9:43

                      а если прописываю void paintEvent(QPaintEvent *event); к главном классе, то оно автоматом срабатывает 1 раз при загрузке приложения, 1 раз при нажатии левой кнопки мыши и больше не работает.

                        Михаиллл
                        • 11 июня 2019 г. 13:04
                        • (ред.)

                        Попробовал для этого сделать класс наследуемый от QWidget. Но событие не вызывается при нажатии и не понятно как получать координаты
                        .h

                        #ifndef WIDGETFORPAINTER_H
                        #define WIDGETFORPAINTER_H
                        
                        #include "QWidget"
                        #include "QPainter"
                        #include "QPen"
                        #include "QDebug"
                        
                        class widgetForPainter: public QWidget
                        {
                        public:
                            widgetForPainter();
                            ~widgetForPainter() {;};
                            QPen myPen;
                            int x,y;
                        
                        
                            private slots:
                            void paintEvent(QPaintEvent *event);
                        
                        public slots:
                            void paintPoint(int x1,int y1);
                        
                        };
                        
                        #endif // WIDGETFORPAINTER_H
                        

                        .cpp

                        #include "widgetforpainter.h"
                        
                        widgetForPainter::widgetForPainter()
                        {
                            //Pen
                            myPen.setWidth(20);
                            myPen.setColor(Qt::green);
                            //myPen.setColor(QColor(255, 0, 0, 10));
                            myPen.setCapStyle(Qt::RoundCap);
                            myPen.setStyle(Qt::SolidLine);
                        }
                        
                        void widgetForPainter::paintEvent(QPaintEvent *event)
                        {
                            Q_UNUSED(event);
                            QPainter myPainter; // Создаём объект отрисовщика
                            myPainter.setPen(myPen);
                            myPainter.drawPoint(x,y);
                            myPainter.drawEllipse(x, y, x+50, x+50);
                            qDebug()<<x<<y;
                        }
                        
                        void widgetForPainter::paintPoint(int x1, int y1)
                        {
                            QPainter myPainter; // Создаём объект отрисовщика
                            myPainter.setPen(myPen);
                            myPainter.drawPoint(x1,y1);
                            myPainter.drawEllipse(x1, y1, x+50, x+50);
                            qDebug()<<x1<<y1;
                        }
                        

                        В конструкторе главной функции написал так:

                        newGraphicsView =  new graphicsView();
                            newGraphicsView->setScene(scene);    
                        
                            ui->verticalLayout->addWidget(newGraphicsView);
                        
                        
                            widgetForPainter *myWidgetForPainter = new widgetForPainter();
                            ui->verticalLayout->addWidget(myWidgetForPainter);
                        

                        Наверное в void paintScene::mousePressEvent(QGraphicsSceneMouseEvent *event) нужно добавить void widgetForPainter::paintPoint(int x1, int y1), но как это сделать?

                          Михаиллл
                          • 11 июня 2019 г. 14:16

                          В этом примере рисует пиксельно на QWidget и так же пиксельно стирает. Не могли бы вы мне помочь выделить нужный код, который можно добавить в свой проект?

                            Михаиллл
                            • 12 июня 2019 г. 2:05

                            Нашел такой класс, он нормально рисует. Можно ли его сделать не главным классом?
                            .h

                            #ifndef WIDGET_H
                            #define WIDGET_H
                            
                            #include <QWidget>
                            #include <QPainter>
                            #include <QMouseEvent>
                            #include <QEvent>
                            #include <QFileDialog>
                            #include <QImage>
                            #include <QPixmap>
                            
                            namespace Ui {
                            class Widget;
                            }
                            
                            class Widget : public QWidget
                            {
                                Q_OBJECT
                            public:
                                explicit Widget(QWidget *parent = 0);
                                ~Widget();
                                bool eventFilter(QObject *obj, QEvent *event);
                            
                            private slots:
                                void on_open_clicked();
                            
                                void on_save_clicked();
                            
                                void on_R_valueChanged(int value);
                            
                                void on_G_valueChanged(int value);
                            
                                void on_B_valueChanged(int value);
                            
                                void on_pen_dial_valueChanged(int value);
                            
                                void on_pushButton_8_clicked();
                            
                            private:
                                QPen pen;
                                QPen pen2;
                                QPixmap pixmap;
                                QPixmap pixman;
                                QPoint lastPoint;
                                int r;
                                int g;
                                int b;
                                Ui::Widget *ui;
                            };
                            
                            #endif // WIDGET_H
                            
                            

                            .cpp

                            #include "widget.h"
                            #include "ui_widget.h"
                            
                            
                            Widget::Widget(QWidget *parent) :
                                QWidget(parent),
                                ui(new Ui::Widget)
                            {
                                ui->setupUi(this);
                                pixmap = QPixmap(ui->label->width(),ui->label->height());
                                pixmap.fill();
                                pen = QPen( QBrush( Qt::black), 5.0f );
                                r = 0;
                                g = 0;
                                b = 0;
                            
                                ui->label->setPixmap(pixmap);
                            
                                ui->label->installEventFilter(this);
                                ui->red_color->installEventFilter(this);
                                ui->orange_color->installEventFilter(this);
                                ui->yellow_color->installEventFilter(this);
                                ui->green_color->installEventFilter(this);
                                ui->blue_color->installEventFilter(this);
                                ui->purple_color->installEventFilter(this);
                                ui->pushButton_8->installEventFilter(this);
                                ui->R->installEventFilter(this);
                                ui->G->installEventFilter(this);
                                ui->B->installEventFilter(this);
                                ui->setcolor->installEventFilter(this);
                                ui->pen_dial->installEventFilter(this);
                                ui->clear_pixmap->installEventFilter(this);
                            
                            
                                ui->red_color->setStyleSheet("Background-color: red;");
                                ui->orange_color->setStyleSheet("Background-color: #ffa500");
                                ui->yellow_color->setStyleSheet("Background-color: yellow");
                                ui->green_color->setStyleSheet("Background-color: green");
                                ui->blue_color->setStyleSheet("Background-color: blue");
                                ui->purple_color->setStyleSheet("Background-color: #C400AB");
                            
                                pen2 = QPen(QBrush(Qt::black), 61.0f);
                                QBrush st(QColor(Qt::black),Qt::Dense7Pattern);
                                pixman = QPixmap(ui->label_3->width(),ui->label_3->height());
                                pixman.fill();
                                QPainter p2(&pixman);
                                p2.setPen(Qt::SolidLine);
                                p2.setBrush(st);
                                p2.drawRect(0,0,ui->label_3->width(),ui->label_3->height());
                                p2.end();
                                ui->label_3->setPixmap(pixman);
                            
                                //this->setFixedSize(this->width(), this->height());
                            }
                            
                            Widget::~Widget()
                            {
                                delete ui;
                            }
                            
                            bool Widget::eventFilter(QObject *obj, QEvent *event)
                            {
                                if(obj == ui->label and event->type() == QEvent::MouseButtonPress)
                                {
                                    QMouseEvent *mous = (QMouseEvent*)event;
                                    QPainter p(&pixmap);
                                    p.setPen(pen);
                                    p.drawPoint(mous->pos());
                                    p.end();
                                    lastPoint = mous->pos();
                                    ui->label->setPixmap(pixmap);
                                }
                                if(obj == ui->label and event->type() == QEvent::MouseMove)
                                {
                                    QMouseEvent *mous = (QMouseEvent*)event;
                                    QPainter p(&pixmap);
                                    p.setPen(pen);
                                    p.drawLine(lastPoint,mous->pos());
                                    p.end();
                                    lastPoint = mous->pos();
                                    ui->label->setPixmap(pixmap);
                                }
                                if(obj == ui->red_color and event->type() == QEvent::MouseButtonPress) pen.setColor(Qt::red);
                                if(obj == ui->orange_color and event->type() == QEvent::MouseButtonPress) pen.setColor(QColor(255, 128, 0));
                                if(obj == ui->yellow_color and event->type() == QEvent::MouseButtonPress) pen.setColor(Qt::yellow);
                                if(obj == ui->green_color and event->type() == QEvent::MouseButtonPress) pen.setColor(Qt::green);
                                if(obj == ui->blue_color and event->type() == QEvent::MouseButtonPress) pen.setColor(Qt::blue);
                                if(obj == ui->purple_color and event->type() == QEvent::MouseButtonPress) pen.setColor(QColor(196, 0, 171));
                                if(obj == ui->setcolor and event->type() == QEvent::MouseButtonPress)
                                {
                                    bool ok = true;
                                    r = ui->lineEdit->text().toInt(&ok,10);
                                    g = ui->lineEdit_2->text().toInt(&ok,10);
                                    b = ui->lineEdit_3->text().toInt(&ok,10);
                                    if((r <= 255 or g <= 255 or b <= 255)) pen.setColor(QColor(r,g,b));
                                    else ui->info->text() = "Введены неверные значения";
                                }
                                if(obj == ui->pen_dial and event->type() == QEvent::MouseButtonPress and QEvent::MouseMove)
                                {
                                }
                                if(obj == ui->clear_pixmap and event->type() == QEvent::MouseButtonPress)
                                {
                                    pixmap.fill(QColor(Qt::white));
                                    ui->label->setPixmap(pixmap);
                                }
                                if(obj == ui->label_3 and event->type() == QEvent::MouseButtonPress)
                                {
                                    pen.setBrush(Qt::Dense5Pattern);
                                    ui->label->setPixmap(pixmap);
                                }
                            }
                            
                            void Widget::on_open_clicked()
                            {
                                QString file;
                                file = QFileDialog::getOpenFileName(this,tr("Открыть файл"),tr("Картинка.jpg"),tr("JPG (*.jpg)"));
                                pixmap.load(file);
                            }
                            
                            void Widget::on_save_clicked()
                            {
                                QString file;
                                file = QFileDialog::getSaveFileName(this,tr("Сохранить файл"),tr("Картинка.jpg"),tr("JPG (*.jpg"));
                                pixmap.save(file);
                            }
                            
                            void Widget::on_R_valueChanged(int value)
                            {
                                pen.setColor(QColor(value,ui->B->value(),ui->G->value()));
                                ui->Value_1->setNum(value);
                            }
                            
                            void Widget::on_G_valueChanged(int value)
                            {
                                pen.setColor(QColor(ui->R->value(),value,ui->G->value()));
                                ui->Value_2->setNum(value);
                            }
                            
                            void Widget::on_B_valueChanged(int value)
                            {
                                pen.setColor(QColor(ui->R->value(),ui->B->value(),value));
                                ui->Value_3->setNum(value);
                            }
                            
                            void Widget::on_pen_dial_valueChanged(int value)
                            {
                                pen.setWidthF(value);
                                ui->label_2->setNum(value);
                            }
                            
                            void Widget::on_pushButton_8_clicked()
                            {
                            
                            }
                            
                            
                              Михаиллл
                              • 12 июня 2019 г. 6:10
                              • (ред.)

                              ,

                                Михаиллл
                                • 12 июня 2019 г. 8:35

                                Перенес этот класс в свой код. Теперь нужно разбираться с прозрачностью.

                                  Evgenii Legotckoi
                                  • 16 июня 2019 г. 16:26

                                  У класса QColor в конструкторе есть установка прозрачности. Это альфа канал.

                                  QColor(int r, int g, int b, int a = ...)

                                  Либо через

                                  setAlpha()

                                    Комментарии

                                    Только авторизованные пользователи могут публиковать комментарии.
                                    Пожалуйста, авторизуйтесь или зарегистрируйтесь
                                    SH
                                    • Sak Hax
                                    • 25 апреля 2024 г. 23:00

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

                                    • Результат:33баллов,
                                    • Очки рейтинга-10
                                    г
                                    • ги
                                    • 24 апреля 2024 г. 0:51

                                    C++ - Тест 005. Структуры и Классы

                                    • Результат:41баллов,
                                    • Очки рейтинга-8
                                    l
                                    • laei
                                    • 23 апреля 2024 г. 18:19

                                    C++ - Тест 004. Указатели, Массивы и Циклы

                                    • Результат:10баллов,
                                    • Очки рейтинга-10
                                    Последние комментарии
                                    k
                                    kmssr9 февраля 2024 г. 4:43
                                    Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                    АК
                                    Анатолий Кононенко5 февраля 2024 г. 11:50
                                    Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                    EVA
                                    EVA25 декабря 2023 г. 20:30
                                    Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                    J
                                    JonnyJo25 декабря 2023 г. 18:38
                                    Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                    G
                                    Gvozdik19 декабря 2023 г. 7:01
                                    Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                    Сейчас обсуждают на форуме
                                    G
                                    Gar22 апреля 2024 г. 14:46
                                    Clipboard Как скопировать окно целиком в clipb?
                                    DA
                                    Dr Gangil Academics20 апреля 2024 г. 16:45
                                    Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
                                    a
                                    a_vlasov14 апреля 2024 г. 15:41
                                    Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
                                    Павел Дорофеев
                                    Павел Дорофеев14 апреля 2024 г. 11:35
                                    QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
                                    f
                                    fastrex4 апреля 2024 г. 13:47
                                    Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

                                    Следите за нами в социальных сетях