QT开发中文网

Qt C++ 实现QTableView窗口中数据修改过后的undo和redo函数,使用QList进行存储操作记录,点击工具栏上的Undo按钮、redo按钮实现单击第n次undo撤回第n条和单击第n次redo重做第n条

思路:

  1. 在QList中存储每次操作的记录,包括修改前的数据、修改后的数据和对应的行列信息。

  2. 实现undo函数,将当前状态恢复到上一个状态,即将最后一次操作的记录取出来,然后根据其中保存的行列信息和修改前的数据更新表格中对应位置的数据。

  3. 实现redo函数,将当前状态恢复到下一个状态(如果有),即将下一个操作记录取出来,然后根据其中保存的行列信息和修改后的数据更新表格中对应位置的数据。

  4. 为工具栏上的Undo按钮和redo按钮分别绑定单击事件,实现单击第n次undo撤回第n条和单击第n次redo重做第n条功能。

代码实现:

  1. 定义操作记录结构体Record:
struct Record {
    QModelIndex index; // 行列信息
    QVariant oldValue; // 修改前的值
    QVariant newValue; // 修改后的值
};
  1. 在窗口类中定义QList类型变量m_records,并在构造函数中初始化为空列表:
class MyTableView : public QTableView {
    ...
private:
    QList<Record> m_records;
public:
    MyTableView(QWidget *parent = nullptr) : QTableView(parent), m_records() {}
};
  1. 在窗口类中实现record函数用于记录每次操作:
void MyTableView::record(const QModelIndex &index, const QVariant &oldValue, const QVariant &newValue)
{
    if (oldValue != newValue) { // 只记录值改变的操作
        m_records.append({index, oldValue, newValue}); // 将操作记录添加到列表中
    }
}
  1. 重写dataChanged函数,用于在数据修改时调用record函数记录操作:
void MyTableView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
    for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
        for (int col = topLeft.column(); col <= bottomRight.column(); ++col) {
            QModelIndex index = model()->index(row, col);
            QVariant oldValue = model()->data(index, Qt::EditRole);
            QVariant newValue = model()->data(index, Qt::DisplayRole);
            record(index, oldValue, newValue); // 记录每次修改操作
        }
    }
    QTableView::dataChanged(topLeft, bottomRight, roles); // 调用基类函数更新表格显示
}
  1. 实现undo函数和redo函数,将最后一条或下一条操作记录取出来,根据其中保存的行列信息和值更新表格中对应位置的数据:
void MyTableView::undo()
{
    if (!m_records.isEmpty()) { // 如果有操作记录才执行撤回操作
        Record lastRecord = m_records.takeLast();
        QStandardItemModel *model = static_cast<QStandardItemModel*>(this->model());
        model->setData(lastRecord.index, lastRecord.oldValue, Qt::EditRole); // 恢复修改前的值
    }
}

void MyTableView::redo()
{
    if (!m_redoRecords.isEmpty()) { // 如果有重做记录才执行重做操作
        Record nextRecord = m_redoRecords.takeLast();
        QStandardItemModel *model = static_cast<QStandardItemModel*>(this->model());
        model->setData(nextRecord.index, nextRecord.newValue, Qt::EditRole); // 恢复修改后的值
    }
}
  1. 重写keyPressEvent函数,为Ctrl+Z和Ctrl+Y绑定undo和redo功能:
void MyTableView::keyPressEvent(QKeyEvent *event)
{
    if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Z) {
        undo(); // Ctrl+Z执行撤回操作
    } else if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_Y) {
        redo(); // Ctrl+Y执行重做操作
    } else {
        QTableView::keyPressEvent(event);
    }
}
  1. 在窗口类中定义两个计数器变量m_undoCount和m_redoCount,并在构造函数中初始化为0。将Undo按钮和redo按钮分别绑定单击事件,实现单击第n次undo撤回第n条和单击第n次redo重做第n条功能:
class MyTableView : public QTableView {
    ...
private:
    QList<Record> m_records;
    QList<Record> m_redoRecords;
    int m_undoCount;
    int m_redoCount;
public:
    MyTableView(QWidget *parent = nullptr) : QTableView(parent), m_records(), m_redoRecords(), 
        m_undoCount(0), m_redoCount(0)
    {
        QAction *undoAction = new QAction(QIcon(":/images/undo.png"), tr("Undo"), this);
        connect(undoAction, &QAction::triggered, this, &MyTableView::undo);
        QAction *redoAction = new QAction(QIcon(":/images/redo.png"), tr("Redo"), this);
        connect(redoAction, &QAction::triggered, this, &MyTableView::redo);

        QToolBar *toolBar = new QToolBar(this);
        toolBar->addAction(undoAction);
        toolBar->addAction(redoAction);

        setCornerButtonEnabled(true); // 显示左上角的按钮
        setHorizontalHeaderVisible(true); // 显示水平表头
        setVerticalHeaderVisible(true); // 显示垂直表头
    }
private slots:
    void undo()
    {
        if (!m_records.isEmpty()) { // 如果有操作记录才执行撤回操作
            Record lastRecord = m_records.takeLast();
            QStandardItemModel *model = static_cast<QStandardItemModel*>(this->model());
            model->setData(lastRecord.index, lastRecord.oldValue, Qt::EditRole); // 恢复修改前的值
            ++m_undoCount;
            m_redoCount = 0;
        }
    }

    void redo()
    {
        if (!m_redoRecords.isEmpty()) { // 如果有重做记录才执行重做操作
            Record nextRecord = m_redoRecords.takeLast();
            QStandardItemModel *model = static_cast<QStandardItemModel*>(this->model());
            model->setData(nextRecord.index, nextRecord.newValue, Qt::EditRole); // 恢复修改后的值
            ++m_redoCount;
            m_undoCount = 0;
        }
    }
};

完整代码:

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://qt.0voice.com/?id=2393

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?