在 Qt 中单击图像时尝试立即显示用户编辑操作的结果
Trying to display instantly the result of a user editing action when clicking an image in Qt
我正在尝试使用 Qt 图像 classes 中不存在的一些自定义图像编辑工具来实现图像编辑器。当用户点击图像场景执行某些操作时,我希望图像在 GUI 应用程序中立即更新,向用户实时显示变化(绘制像素、缩放...)。问题是单击时编辑图像的操作只能在单独的 class 中完成(至少据我所知)(在我下面显示的示例中,这样的 class 称为 GraphicsScene),因此我不知道如何将编辑后的图像传输到 MainWindow class.
简而言之,我想在用户执行编辑图像的操作后立即将编辑图像从GraphicsScene class class class class ,然后使后一个执行代码以在每次用户对图像执行操作后实时更新屏幕。
为了清楚起见,我接下来展示我目前拥有的代码方案。
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.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
mainwindow.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);
}
为了能够在点击时跟踪坐标,并根据网上的一些建议,我创建了一个名为 GraphicsScene 的 QGraphicsScene 的子class,其头文件为:
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);
我会高度评价任何想法。
因为你想点击包含像素图的项目,所以没有必要覆盖 QGraphicsScene mousePressEvent 方法,因为你可以点击图像外部,所以最好覆盖 QGraphicsPixmapItem 中的那个方法。
而不是使用extern来访问图像,在Qt中是更好的信号和槽,但是只有从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 的插槽连接起来。
mainwindow.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
mainwindow.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
我正在尝试使用 Qt 图像 classes 中不存在的一些自定义图像编辑工具来实现图像编辑器。当用户点击图像场景执行某些操作时,我希望图像在 GUI 应用程序中立即更新,向用户实时显示变化(绘制像素、缩放...)。问题是单击时编辑图像的操作只能在单独的 class 中完成(至少据我所知)(在我下面显示的示例中,这样的 class 称为 GraphicsScene),因此我不知道如何将编辑后的图像传输到 MainWindow class.
简而言之,我想在用户执行编辑图像的操作后立即将编辑图像从GraphicsScene class class class class ,然后使后一个执行代码以在每次用户对图像执行操作后实时更新屏幕。
为了清楚起见,我接下来展示我目前拥有的代码方案。
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.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
mainwindow.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);
}
为了能够在点击时跟踪坐标,并根据网上的一些建议,我创建了一个名为 GraphicsScene 的 QGraphicsScene 的子class,其头文件为:
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);
我会高度评价任何想法。
因为你想点击包含像素图的项目,所以没有必要覆盖 QGraphicsScene mousePressEvent 方法,因为你可以点击图像外部,所以最好覆盖 QGraphicsPixmapItem 中的那个方法。
而不是使用extern来访问图像,在Qt中是更好的信号和槽,但是只有从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 的插槽连接起来。
mainwindow.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
mainwindow.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