[ fromfile: commandpattern.xml id: undoimagemanip ]
The following example demonstrates the use of QUndoCommand.
This program makes use of image manipulation operations.[51]
we derive a couple of typical image manipulation operations from QUndoCommand.
The first operation adjusts the color of each pixel by applying double
multipliers to its red, green, and blue components.
The second operation replaces half of the image by the mirror image of its other half, either horizontally or vertically, depending on the user-supplied argument.
Example 10.11. src/undo-demo/image-manip.h
[ . . . . ] class AdjustColors : public QUndoCommand { public: AdjustColors(QImage& img, double radj, double gadj, double badj) : m_Image(img), m_Saved(img.size(), img.format()), m_RedAdj(radj), m_GreenAdj(gadj), m_BlueAdj(badj) {setText("adjust colors"); } virtual void undo(); virtual void redo(); private: QImage& m_Image; QImage m_Saved; double m_RedAdj, m_GreenAdj, m_BlueAdj; void adjust(double radj, double gadj, double badj); }; class MirrorPixels : public QUndoCommand { public: virtual void undo(); virtual void redo(); [ . . . . ]
Each of the two operations makes a copy of the original image before changing any of its pixels.
Example 10.12 shows the implementation of one of the operation classes, AdjustColors
.
pixel()
returns the color as an ARGB quad, an unsigned, 8-byte int
in the format AARRGGBB, where each pair of bytes represents a component of the color.
It then replaces the pixel with adjusted values for red, green, and blue.
The undo()
method reverts to the saved copy of the image.
The redo()
method calls the pixel-changing function.
Example 10.12. src/undo-demo/image-manip.cpp
[ . . . . ] void AdjustColors::adjust(double radj, double gadj, double badj) { int h(m_Image.height()), w(m_Image.width()); int r, g, b; QRgb oldpix, newpix; m_Saved = m_Image.copy(QRect()); // save a copy of entire image for(int y = 0; y < h; ++y) { for(int x = 0; x < w; ++x) { oldpix = m_Image.pixel(x,y); r = qRed(oldpix) * radj; g = qGreen(oldpix) * gadj; b = qBlue(oldpix) * badj; newpix = qRgb(r,g,b); m_Image.setPixel(x,y,newpix); } } } void AdjustColors::redo() { qDebug() << "AdjustColors::redo()"; adjust(m_RedAdj, m_GreenAdj, m_BlueAdj); } void AdjustColors::undo() { qDebug() << "AdjustColors::undo()"; m_Image = m_Saved.copy(QRect()); }
The UndoMainWin
class is derived from QMainWindow and makes use of QUndoStack.
In Example 10.13, the private slots started out as stubs that QtCreator generated when we employed the feature on widgets and actions from Designer.
Example 10.13. src/undo-demo/undomainwin.h
#ifndef UNDOMAINWIN_H #define UNDOMAINWIN_H #include <QMainWindow> #include <QUndoStack> class QWidget; class QLabel; class QImage; class QEvent; namespace Ui { class UndoMainWin; } class UndoMainWin : public QMainWindow { Q_OBJECT public: explicit UndoMainWin(QWidget* parent = 0); ~UndoMainWin(); public slots: void displayImage(const QImage& img); private: Ui::UndoMainWin* ui; QLabel* m_ImageDisplay; QImage m_Image; QUndoStack m_Stack; private slots: void on_redoButton_clicked(); void on_openButton_clicked(); void on_actionAdjust_Color_triggered(); void on_actionUndo_The_Last_Action_triggered(); void on_actionHorizontal_Mirror_triggered(); void on_actionVertical_Mirror_triggered(); void on_actionQuit_triggered(); void on_actionSave_triggered(); void on_actionClose_triggered(); void on_saveButton_clicked(); void on_quitButton_clicked(); void on_adjustColorButton_clicked(); void on_undoButton_clicked(); void on_verticalMirrorButton_clicked(); void on_horizontalMirrorButton_clicked(); void on_actionOpen_triggered(); }; #endif // UNDOMAINWIN_H
Example 10.14. src/undo-demo/undomainwin.cpp
[ . . . . ] #include "image-manip.h" #include "ui_undomainwin.h" #include "undomainwin.h" UndoMainWin::UndoMainWin(QWidget *parent) : QMainWindow(parent), ui(new Ui::UndoMainWin), m_ImageDisplay(new QLabel(this)), m_Image(QImage()) { ui->setupUi(this); m_ImageDisplay->setMinimumSize(640,480); } UndoMainWin::~UndoMainWin() { delete ui; } void UndoMainWin::displayImage(const QImage &img) { m_ImageDisplay->setPixmap(QPixmap::fromImage(img)); } void UndoMainWin::on_actionOpen_triggered() { m_Image.load(QFileDialog::getOpenFileName()); displayImage(m_Image); } void UndoMainWin::on_horizontalMirrorButton_clicked() { MirrorPixels* mp = new MirrorPixels(m_Image, true); m_Stack.push(mp); displayImage(m_Image); } void UndoMainWin::on_adjustColorButton_clicked() { double radj(ui->redSpin->value()), gadj(ui->greenSpin->value()), badj(ui->blueSpin->value()); AdjustColors* ac = new AdjustColors(m_Image, radj, gadj, badj); m_Stack.push(ac); displayImage(m_Image); } [ . . . . ]
Neither a QObject nor a child, it must be deleted explicitly. |
[51] This example was inspired by the work of Guzdial and Ericson [Guzdial07] and their MediaComp project.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |