Qt中的撤销/重做功能

作为一个例子,本例只实现了在列表控件“添加项”和“修改项名称”的2个操作。界面上显示一个列表框,列表框需要在界面设计器中设为IconMode,这样就会是图标在上文本在下的显示样式。“添加”按钮用来在列表框中加一个项。点击图标下面的文本可以修改文本名称。程序测试环境是VS2017和Qt5.9,测试结果功能正常,运行效果如下:

头文件:

class QListWidget;

class MAddImage : public QUndoCommand
{
public:
    MAddImage(const QString &text, QListWidget* isrc, QUndoCommand *parent = Q_NULLPTR);
    ~MAddImage() override = default;
    void setActionInfo(const QPixmap& image, int where);
    void undo() override;
    void redo() override;

private:
    QListWidget* src;
    QPixmap pixmap;
    int pos;
};

class MChangeName : public QUndoCommand
{
public:
    MChangeName(const QString &text, QListWidget* isrc, QUndoCommand *parent = Q_NULLPTR);
    ~MChangeName() override = default;
    void setActionInfo(const QString& oldName, const QString& newName, int where);
    void undo() override;
    void redo() override;

private:
    QListWidget* src;
    QString newText;
    QString oldText;
    int pos;
};

CPP文件:

MAddImage::MAddImage(const QString &text, QListWidget* isrc, QUndoCommand *parent) :
    QUndoCommand(text, parent)
{
    src = isrc;
}

void MAddImage::setActionInfo(const QPixmap& image, int where)
{
    pixmap = image;
    pos = where;
}

void MAddImage::undo()
{
    delete src->takeItem(pos);
}

void MAddImage::redo()
{
    QListWidgetItem* item = new QListWidgetItem(QIcon(pixmap), QString(u8"未命名"));
    item->setFlags(Qt::ItemIsEditable | item->flags());
    src->insertItem(pos, item);
}

MChangeName::MChangeName(const QString &text, QListWidget* isrc, QUndoCommand *parent) : 
    QUndoCommand(text, parent)
{
    src = isrc;
}

void MChangeName::setActionInfo(const QString& oldName, const QString& newName, int where)
{
    oldText = oldName;
    newText = newName;
    pos = where;
}

void MChangeName::undo()
{
    src->blockSignals(true);
    QListWidgetItem* item = src->item(pos);
    item->setText(oldText);
    src->blockSignals(false);
}

void MChangeName::redo()
{
    src->blockSignals(true);
    QListWidgetItem* item = src->item(pos);
    item->setText(newText);
    src->blockSignals(false);
}

在主窗口类中有几个槽函数需要实现以响应用户的操作。下面的代码中QtTest是主窗口类;ui.lwList是列表控件;(ui.)pbAdd是“添加”按钮;(ui.)pbUndo是“撤销”按钮;(ui.)pbRedo是“重做”按钮。operas是QtTest类成员变量,定义是 QUndoStack operas; ,它是Qt封装好的用于管理撤销/重做命令的类,详情可以查阅Qt帮助文档。

void QtTest::on_lwList_currentRowChanged(int row)
{
    QListWidgetItem* it = ui.lwList->item(row);
    currEditText = it->text();
}

void QtTest::on_lwList_itemChanged(QListWidgetItem *item)
{
    MChangeName* changeAct = new MChangeName(u8"修改名称", ui.lwList);
    changeAct->setActionInfo(currEditText, item->text(), ui.lwList->row(item));
    operas.push(changeAct); /* 由于push(...)自动触发redo()操作,因此这里重命名两次 */
}

void QtTest::on_pbAdd_clicked()
{
    QPixmap pixmap(100, 80);
    pixmap.fill(QColor(qrand() % 255, qrand() % 255, qrand() % 255));
    MAddImage* addAct = new MAddImage(u8"添加图片", ui.lwList);
    addAct->setActionInfo(pixmap, ui.lwList->count());
    operas.push(addAct);
}

void QtTest::on_pbUndo_clicked()
{
    operas.undo();
}

void QtTest::on_pbRedo_clicked()
{
    operas.redo();
}

 

posted @ 2024-04-02 11:57  兜尼完  阅读(267)  评论(0编辑  收藏  举报