【问题标题】:How to Draw a point in a QPixmap Image?如何在 QPixmap 图像中绘制一个点?
【发布时间】:2016-08-11 20:14:10
【问题描述】:

我有一个项目,我想在 QPixmap 内的图像中绘制一个点。该点将通过鼠标单击 QLabel 来绘制。我创建了一个eventFilter(),它对应于鼠标点击。当我用鼠标单击时,会调用这些 eventFilter 并在图像中绘制一个点,但我的代码不起作用。我尝试了许多其他选项,例如子类化 QLabel,但也没有用。

有时我的编译器会显示以下错误消息:

QPainter::begin: Paint device returned engine == 0, type: 2
QPainter::setPen: Painter not active
QPainter::drawPoints: Painter not active
QPainter::end: Painter not active, aborted

但我不明白,因为 Qt 文档说允许在paintEvent 之外使用 QPainter,仅与 QPixmap 一起使用。

下面是我的代码以及启动 QPainter 的方法。

bool mainwindow::eventFilter(QObject* watched, QEvent* event) {
if ( watched != ui->labelScreen )
    return false;
if ( event->type() != QEvent::MouseButtonPress )
    return false;
const QMouseEvent* const me = static_cast<const QMouseEvent*>( event );
//might want to check the buttons here
const QPoint p = me->pos(); //...or ->globalPos();

ui->label_Xget->setNum(this->xReal);
ui->label_Yget->setNum(this->yReal);

///////////////////////////////////

QPixmap pix;
pix.fromImage(QImage::fromData("C:/Users/Syn/Pictures/imagem137.jpg"));

QPainter *painter = new QPainter(&pix);

painter->setPen(Qt::red);
painter->drawPoint(p.x(), p.y());
ui->labelScreen->setPixmap(pix);
painter->end();

///////////////////////////////////


return false;
}

有人可以帮我解决这个问题吗?谢谢。

【问题讨论】:

    标签: c++ image qt user-interface qtgui


    【解决方案1】:

    错误消息不是来自您的编译器,它们发生在运行时,您无法确定上面引用的代码是否是它们的原因。

    有几个问题:

    1. QPixmap::fromImage 是一个返回像素图的静态方法。你忽略了它的返回值。正确的使用方法是:

      // C++11
      auto pix = QPixmap::fromImage(QImage{"filename"});
      // C++98
      QPixmap pix(QPixmap::fromImage(QImage("filename")));
      
    2. 您可以将文件名直接传递给QPixmap构造函数:

      // C++11
      QPixmap pix{"filename"};
      // C++98
      QPixmap pix("filename");
      
    3. 您正在泄漏 Painter 实例。除非您确实需要,否则您应该避免任何动态内存分配。另外,按价值存储ui - 这样更便宜。

    4. 在事件处理程序中执行任何阻塞 I/O(例如读取文件)是一个非常糟糕的主意。预加载像素图并将其存储为MainWindow 类的成员。

    因此(在 C++11 中):

    界面

    template <class F>
    class MainWindow : public QMainWindow {
      QPixmap m_clickPixmap;
      Ui::MainWindow ui;
      bool eventFilter(QObject*, QEvent*) override;
    public:
      MainWindow(QWidget * parent = nullptr);
    };
    

    实施

    void loadImage(const QString & fileName, QObject * context, F && functor) {
      QtConcurrent::run([=]{
        QImage img{fileName};
        if (img.isNull()) return;
        QTimer::singleShot(0, context, functor, img);
      });
    }
    
    MainWindow::MainWindow(QWidget * parent) :
      QMainWindow{parent}
    {
      loadImage("C:/Users/Syn/Pictures/imagem137.jpg", this, [this](const QImage & img){
        m_clickPixmap = QPixmap::fromImage(img);
      });
      ui.setupUi(this);
    }
    
    bool MainWindow::eventFilter(QObject* watched, QEvent* event) {
      if ( watched != ui.labelScreen )
        return false;
      if ( event->type() != QEvent::MouseButtonPress )
        return false;
      auto const me = static_cast<const QMouseEvent*>(event);
      auto const p = me->pos(); //...or ->globalPos();       
      ui.label_Xget->setNum(this->xReal);
      ui.label_Yget->setNum(this->yReal);
    
      auto pix{m_clickPixmap};
      QPainter painter(&pix);
      painter.setPen(Qt::red);
      painter.drawPoint(p.x(), p.y());
      painter.end(); // probably not needed
      ui.labelScreen->setPixmap(pix);
      return false;
    }
    

    【讨论】:

    • 感谢您的回答。我尝试了您的建议,但仍然显示相同的错误消息。并且在 labelScreen 中设置了一个空像素图,​​并且在标签上不显示任何内容。 ://
    • 你确定这段代码有什么问题吗?禁用代码,看看是否还有问题。这段代码应该可以正常工作。
    • 您确定要使用 static_cast 而不是 dynamic_cast?
    • 我发现了错误信息问题。 QPixmap pix 未加载 QImage 输入。使用 pix.load() 图像可以很好地加载到 pix 中。但我需要在我的项目中使用来自 QImage 的文件。你知道我该如何解决这个问题吗?感谢所有的答案。
    • @JosephMalicke 是的,它应该是静态转换:此时,事件的类型是已知的。 QEvent 有自己的类型 id 机制。
    猜你喜欢
    • 2012-10-30
    • 2012-04-20
    • 2014-08-03
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多