在Qt中单击图像时尝试立即显示用户编辑操作的结果

Posted

技术标签:

【中文标题】在Qt中单击图像时尝试立即显示用户编辑操作的结果【英文标题】:Trying to display instantly the result of a user editing action when clicking an image in Qt 【发布时间】:2017-06-26 17:35:26 【问题描述】:

我正在尝试使用 Qt 图像类中不存在的一些自定义图像编辑工具来实现图像编辑器。当用户单击图像场景执行某些操作时,我希望图像在 GUI 应用程序中立即更新,向用户实时显示更改(绘制像素、缩放......)。问题是单击时编辑图像的操作只能在一个单独的类中完成(至少据我所知)(在下面显示的示例中,此类称为 GraphicsScene),因此我不知道如何将编辑后的图像传输到 MainWindow 类。

简而言之,我想在用户执行编辑图像的操作后立即将编辑后的图像从 GraphicsScene 类“发送”到 MainWindow 类,然后让后者执行代码以更新屏幕用户对图像执行每个操作后的实时时间。

为了清楚起见,我接下来展示我现在拥有的代码方案。

ma​​in.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();

ma​​inwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui 
class MainWindow;


class MainWindow : public QMainWindow

    Q_OBJECT

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

private slots:

private:

;

#endif // MAINWINDOW_H

ma​​inwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QApplication>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
#include "graphicsscene.h"

extern QImage Image_original, Image_modified;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)

    ui->setupUi(this);


MainWindow::~MainWindow()

    delete ui;


void MainWindow::on_actionOpen_Image_triggered()

    QDir dir;

    QString filename=QFileDialog::getOpenFileName(this,
                                                  tr("Open Background"),
                                                  path,
                                                  tr("Images (*.png *.bmp *.jpg *.jpeg);;All files (*.*)"));

    Image_original.load(filename);
    GraphicsScene * img = new GraphicsScene( this );
    img->addPixmap(QPixmap::fromImage(Image_original));
    ui->preview->setScene(img);

为了能够在点击的时候跟踪坐标,参考网上的一些建议,我创建了QGraphicsScene的一个子类,叫做GraphicsScene,头文件是:

graphicsscene.h

#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H

#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPointF>
#include <QList>

class GraphicsScene : public QGraphicsScene

    Q_OBJECT
public:
    explicit GraphicsScene(QObject *parent = 0);
    virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
signals:

public slots:

private:
    int x, y;
;

#endif // GRAPHICSSCENE_H

最后,要执行图像编辑,相关的源文件是:

graphicsscene.cpp

#include "graphicsscene.h"
#include <iostream>

using namespace std;

extern QImage Image_original, Image_modified;

GraphicsScene::GraphicsScene(QObject *parent) :
    QGraphicsScene(parent)

    this->setBackgroundBrush(Qt::gray);


void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)

    QGraphicsScene::mousePressEvent(mouseEvent);
    if (mouseEvent->button()==Qt::LeftButton)
    
        x=mouseEvent->scenePos().x();
        y=mouseEvent->scenePos().y();
    
    Image_modified=some_custom_image_editing_code(Image_original, x, y);

理想情况下,我想在执行 mousePressEvent 后在 MainWindow 中执行以下操作:

img->addPixmap(QPixmap::fromImage(Image_modified));
ui->preview->setScene(img);

我会高度感谢任何想法。

【问题讨论】:

请更好地解释你自己,你没有必要在互联网搜索中花费很多行,因为它们偏离了你想要解释的内容。 我不明白这部分:“我想实现一个动作,包括复制缩放,使图像根据单击的坐标居中,但通过相应地裁剪图像来保持其分辨率”。缩放缩放 QGraphicsview,因此会改变 QGraphicsPixmapItem 的改变方式,但不会改变 QPixmap。或者,也许您想使图像居中? 假设屏幕尺寸为 400x200(例如)。您还加载了 400x200 图像。如果您单击像素 (200, 50),则新图像将包括水平从 101 到 300 和垂直从 1 到 100 的像素,然后将其缩放以使新大小为再次 400x200。但是,根据要求,我想要的是,无论对图像进行什么更改,都需要一种方法来将这些信息从类 GraphicsScene“发送”到类 MainWindow,以便在场景中绘制图像完成后,“img”会显示新的更改。 您希望缩放操作返回与原始大小相同但带有裁剪数据的图像 总之如果你有w*h的图片,那么点击P(x1, y1)点,以P为中心缩放w/2*h/2的剪切图片,一定要缩放aw * h和将其发送到主窗口。如果您只是想获得不需要缩放的 QPixmap,而是如果您希望在需要缩放时显示剪切,您想要这两个选项中的哪一个? 【参考方案1】:

由于您要单击包含像素图的项目,因此无需覆盖 QGraphicsScene mousePressEvent 方法,因为您可以单击图像外部,所以最好在 QGraphicsPixmapItem 中覆盖该方法。

在Qt中不是使用extern来访问图片,而是更好的signals和slot,但是只有继承自QObject的类才能有这些属性,可惜QGraphicsPixmapItem没有继承自这个,但是我们可以把它作为接口使用。

graphicspixmapitem.h

#ifndef GRAPHICSPIXMAPITEM_H
#define GRAPHICSPIXMAPITEM_H

#include <QGraphicsPixmapItem>
#include <QObject>

class GraphicsPixmapItem : public QObject, public QGraphicsPixmapItem

    Q_OBJECT
public:
    explicit GraphicsPixmapItem(QObject *parent=0);

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent * event);

signals:
    void newPixmap(const QPixmap p);
;

#endif // GRAPHICSPIXMAPITEM_H

graphicspixmapitem.cpp

#include "graphicspixmapitem.h"

#include <QGraphicsSceneMouseEvent>

GraphicsPixmapItem::GraphicsPixmapItem(QObject * parent):QObject(parent)




void GraphicsPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)

    QPoint p = QPoint(event->pos().x(), event->pos().y());
    QPixmap pix = pixmap();
    if(!pix.isNull())
        QRect rect(QPoint(), pix.rect().size()/2);
        rect.moveCenter(p);
        QPixmap modified = pix.copy(rect);
        modified = modified.scaled(pix.rect().size(), Qt::KeepAspectRatioByExpanding);
        emit newPixmap(modified);
    
    QGraphicsPixmapItem::mousePressEvent(event);

在前面的代码中,我们创建了信号 newPixmap,这将它与 MainWindow 中名为 onNewPixmap 的插槽连接起来。

ma​​inwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "graphicsscene.h"
#include "graphicspixmapitem.h"

namespace Ui 
class MainWindow;


class MainWindow : public QMainWindow

    Q_OBJECT

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

private slots:
    void on_actionOpen_triggered();
    void onNewPixmap(const QPixmap pixmap);

private:
    Ui::MainWindow *ui;

    GraphicsPixmapItem *item;
    GraphicsScene *scene;

    QPixmap original_pixmap;
    QPixmap new_pixmap;
;

#endif // MAINWINDOW_H

ma​​inwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QGraphicsView>
#include <QFileDialog>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)

    ui->setupUi(this);
    scene = new GraphicsScene(this);
    ui->preview->setScene(scene);
    item = new GraphicsPixmapItem;
    /*ui->preview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    ui->preview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);*/
    scene->addItem(item);
    connect(item, &GraphicsPixmapItem::newPixmap, this, &MainWindow::onNewPixmap);


MainWindow::~MainWindow()

    delete ui;


void MainWindow::on_actionOpen_triggered()


    QString path = QDir::homePath();
    QString filename=QFileDialog::getOpenFileName(this,
                                                  tr("Open Background"),
                                                  path,

                                                  tr("Images (*.png *.bmp *.jpg *.jpeg);;All files (*.*)"));

    original_pixmap = QPixmap(filename);
    item->setPixmap(original_pixmap);


void MainWindow::onNewPixmap(const QPixmap pixmap)


    new_pixmap = pixmap;
    QFile file("new_file.png");
    file.open(QIODevice::WriteOnly);
    new_pixmap.save(&file, "PNG");

在该插槽中作为测试,我将图像保存在生成​​可执行文件的文件夹中。

在您的代码中,我看到您使用 QImage,如果您想继续使用它,您可以将 QPixmap 转换为 QImage:

new_pixmap.toImage()

完整示例见here

【讨论】:

有效!非常感谢您的精彩解释!对未来的读者来说只是一个小小的说明。为了使其按要求工作(每次单击后更新屏幕),只需将 void MainWindow::onNewPixmap(const QPixmap pixmap) 的内部代码替换为以下行: item->setPixmap(pixmap);跨度> 你没有说你希望它显示,至少在你最初的问题中。请编辑您的问题并添加该评论。 在您的第一条消息指出需要更好地解释之后,我正在编辑问题。请告诉我你现在是否觉得它写得更恰当。 那部分不重要,我觉得很容易推导出来。 不要过分关注报告失败的搜索,专注于你的问题,因为你会偏离并经常厌倦阅读这些内容。

以上是关于在Qt中单击图像时尝试立即显示用户编辑操作的结果的主要内容,如果未能解决你的问题,请参考以下文章

QPixmap 在 Qt 中加载许多图像

某些图像无法立即绘制

用于在 Java 中拖动组件的 Swing 库

在 Qt GUI 中加载和显示图像

ImageView 上的透明背景 EditText 不会显示光标

performselectorinBackground 不工作