Проблемы с объединением двух QPixmaps - PullRequest
1 голос
/ 25 апреля 2019

Я работаю над живописным приложением. Идея состоит в том, чтобы иметь два растровых изображения. Первый содержит исходное изображение, загруженное пользователем, а второй содержит весь чертеж и имеет прозрачный фон. Чтобы показать результат растровые изображения должны быть объединены и показаны в QLabel Это сделано так:

  1. Загрузка и изображение и создание прозрачного растрового изображения с одинаковым размером

        void ImageViewer::on_openAct_triggered()
        {
                QString fileName = QFileDialog::getOpenFileName(this,
                                                 tr("Open File"), QDir::currentPath());
                if (!fileName.isEmpty()) {
                     QImage image(fileName);
                     if (image.isNull()) {
                         QMessageBox::information(this, tr("Image Viewer"),
                                                  tr("Cannot load %1.").arg(fileName));
                         return;
                     }
                     imageLabel->setPixmap(QPixmap::fromImage(image));
                     scaleFactor = 1.0;
    
                     objectpix.scaled(QSize(imageLabel->size()), Qt::KeepAspectRatio, Qt::FastTransformation);
                     objectpix.fill(Qt::transparent);
    
                    /.../
                }
    
        }
    
  2. Получение координат мыши, рисование на втором растровом изображении и объединение первого и второго

           mFirstX =  e->x()/scaleFactor+ scrollArea->horizontalScrollBar()->value()/scaleFactor;
           mFirstY = (e->y() - 31)/scaleFactor+ scrollArea->verticalScrollBar()->value()/scaleFactor;
    
       /.../
    
    
        QPainter paint(&objectpix);
    
        QPen PointPen (Qt::red);
        PointPen.setWidth(5);
        QBrush PointBrush (Qt::red,Qt::SolidPattern);
    
        QPoint p1 = QPoint(mFirstX,mFirstY);
    
        paint.setPen(PointPen);
        paint.setBrush(PointBrush);
        paint.drawEllipse(p1,2,2);
    
        QPixmap p(*imageLabel->pixmap());
        QPainter painter(&p);
        painter.drawPixmap(imageLabel->rect(),objectpix,objectpix.rect());\
        painter.end();
        imageLabel->setPixmap(p);
    

Но ничего не показано таким образом. Если я показываю только второе растровое изображение (которое должно содержать все рисунки и иметь прозрачный фон), оно показывает только прозрачное растровое изображение, т.е. я вижу фон моего приложения. Что я делаю неправильно? Любая помощь приветствуется.

Ответы [ 2 ]

2 голосов
/ 25 апреля 2019

Каким-то образом у меня возникло ощущение, что ОП действительно должен быть возможен ...

... и попробовал сам.

Вот что я получил (testQPixmapCombine.cc):

#include <QtWidgets>

class Label: public QLabel {

  private:
    QPixmap _qPixmap;

  public:
    Label(QWidget *pQParent = nullptr):
      QLabel(pQParent)
    { }

    virtual ~Label() = default;

    Label(const Label&) = delete;
    Label& operator=(const Label&) = delete;

    void setPixmap(const QPixmap &qPixmap)
    {
      _qPixmap = qPixmap;
      QLabel::setPixmap(_qPixmap = qPixmap);
    }

  protected:

    virtual void mousePressEvent(QMouseEvent *pQEvent) override;
};

void Label::mousePressEvent(QMouseEvent *pQEvent)
{
  // clear overlay
  QPixmap qPixmapDraw(_qPixmap.size());
  qPixmapDraw.fill(QColor(0, 0, 0, 0));
  // draw red circle at mouse coordinates
  { QPainter qPainter(&qPixmapDraw);
    qPainter.setPen(QPen(Qt::red, 2));
    qPainter.drawEllipse(pQEvent->pos(), 20, 20);
  }
  // combine pixmaps
  QPixmap qPixmapComp = _qPixmap;
  { QPainter qPainter(&qPixmapComp);
    qPainter.drawPixmap(0, 0, qPixmapDraw);
  }
  QLabel::setPixmap(qPixmapComp);
  pQEvent->accept();
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // load image file
  const QImage qImg("cat.png");
  QPixmap qPixmap;
  qPixmap.convertFromImage(qImg);
  // setup UI
  Label qWin;
  qWin.setWindowTitle(QString::fromUtf8("Combine Pixmaps"));
  qWin.setPixmap(qPixmap);
  qWin.show();
  // runtime loop
  return app.exec();
}

и соответствующий проект Qt (testQPixmapCombine.pro):

SOURCES = testQPixmapCombine.cc

QT += widgets

Я скомпилировал и протестировал в cygwin64 :

$ qmake-qt5 testQPixmapCombine.pro

$ make && ./testQPixmapCombine
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQPixmapCombine.o testQPixmapCombine.cc
g++  -o testQPixmapCombine.exe testQPixmapCombine.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 
Qt Version: 5.9.4

Snapshot of testQPixmapCombine

Внизу изображения есть маленький красный кружок, который появился после того, как я нажал на засов.

Должен признаться, что касается моего кода, мне даже не потребовались дополнительные QPixmap. (Я хотел продемонстрировать, что рисование с прозрачным растровым изображением работает, как и ожидалось, - в соответствии с вопросом OP.)

Эта альтернативная реализация Label::mousePressEvent() произвела бы такой же эффект:

void Label::mousePressEvent(QMouseEvent *pQEvent)
{
  QPixmap qPixmapDraw(_qPixmap);
  // draw red circle at mouse coordinates
  { QPainter qPainter(&qPixmapDraw);
    qPainter.setPen(QPen(Qt::red, 2));
    qPainter.drawEllipse(pQEvent->pos(), 20, 20);
  }
  QLabel::setPixmap(qPixmapDraw);
  pQEvent->accept();
}

Обратите внимание, что я рассмотрел то, что было затронуто как потенциальную проблему в Ответе Kerndog73 : Обозначив QPainter qPainter дополнительной парой фигурных скобок, я достиг того же эффекта, что отмечен в документе. из QPainter::end():

Заканчивается покраска. Любые ресурсы, используемые во время рисования, освобождаются. Обычно вам не нужно вызывать это, поскольку он вызывается деструктором.

(Подчеркните - мое.)

1 голос
/ 25 апреля 2019

Вы должны завершить рисование на objectpix, прежде чем сможете использовать его с другим художником. Позвоните paint.end() после рисования эллипса. Растровое изображение не будет изменено до тех пор, пока вы не уничтожите рисовальщика или явно не завершите рисование с помощью end().

...