c++代码实现qtreewidget支持撤销重做
时间: 2023-09-09 18:07:55 浏览: 135
C++ 撤销重做功能
实现Qt的QTreeWidget支持撤销重做,可以通过继承QTreeWidget实现自定义的树控件,并在其中添加撤销和重做操作。
具体实现步骤如下:
1. 定义一个结构体用于表示撤销/重做的操作,包含操作类型(如插入、删除、修改等)以及操作前后的节点信息。
```
struct TreeOperation {
enum Type { Insert, Remove, Move, Update };
Type type;
QTreeWidgetItem *parent;
int index;
QTreeWidgetItem *node;
QString text;
QVariant data;
};
```
2. 在自定义的树控件中定义一个QStack用于存储操作记录,以及两个指针用于记录当前的撤销和重做操作。
```
class UndoableTreeWidget : public QTreeWidget {
Q_OBJECT
public:
UndoableTreeWidget(QWidget *parent = nullptr);
~UndoableTreeWidget();
public slots:
void undo();
void redo();
protected:
void keyPressEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private:
void pushOperation(const TreeOperation &op);
void performOperation(const TreeOperation &op);
void removeNode(QTreeWidgetItem *node);
void insertNode(QTreeWidgetItem *parent, int index, QTreeWidgetItem *node);
void moveNode(QTreeWidgetItem *parent, int from, int to);
void updateNode(QTreeWidgetItem *node, const QString &text, const QVariant &data);
QStack<TreeOperation> m_undoStack;
QStack<TreeOperation> m_redoStack;
TreeOperation *m_currentOp;
};
```
3. 在自定义的树控件的构造函数中,连接撤销和重做操作的信号和槽。
```
UndoableTreeWidget::UndoableTreeWidget(QWidget *parent) : QTreeWidget(parent) {
m_currentOp = nullptr;
connect(this, &QTreeWidget::itemChanged, [this](QTreeWidgetItem *item, int column) {
if (m_currentOp == nullptr) {
pushOperation({ TreeOperation::Update, item->parent(), indexOfTopLevelItem(item->parent()), item, item->text(column), item->data(column) });
}
});
QAction *undoAction = new QAction(tr("&Undo"), this);
undoAction->setShortcuts(QKeySequence::Undo);
connect(undoAction, &QAction::triggered, this, &UndoableTreeWidget::undo);
addAction(undoAction);
QAction *redoAction = new QAction(tr("&Redo"), this);
redoAction->setShortcuts(QKeySequence::Redo);
connect(redoAction, &QAction::triggered, this, &UndoableTreeWidget::redo);
addAction(redoAction);
}
```
4. 实现撤销和重做操作的槽函数。在撤销操作中,将当前操作记录到重做栈中,然后执行撤销操作;在重做操作中,将当前操作记录到撤销栈中,然后执行重做操作。
```
void UndoableTreeWidget::undo() {
if (!m_undoStack.isEmpty()) {
TreeOperation op = m_undoStack.pop();
m_currentOp = &op;
m_redoStack.push(op);
performOperation(op);
m_currentOp = nullptr;
}
}
void UndoableTreeWidget::redo() {
if (!m_redoStack.isEmpty()) {
TreeOperation op = m_redoStack.pop();
m_currentOp = &op;
m_undoStack.push(op);
performOperation(op);
m_currentOp = nullptr;
}
}
```
5. 实现各种操作的函数。在每个操作函数中,记录操作类型和节点信息,并将操作记录添加到撤销栈中。
```
void UndoableTreeWidget::removeNode(QTreeWidgetItem *node) {
TreeOperation op = { TreeOperation::Remove, node->parent(), indexOfTopLevelItem(node->parent()), node, node->text(0), node->data(0) };
pushOperation(op);
delete node;
}
void UndoableTreeWidget::insertNode(QTreeWidgetItem *parent, int index, QTreeWidgetItem *node) {
TreeOperation op = { TreeOperation::Insert, parent, index, node, "", QVariant() };
pushOperation(op);
parent->insertChild(index, node);
}
void UndoableTreeWidget::moveNode(QTreeWidgetItem *parent, int from, int to) {
TreeOperation op = { TreeOperation::Move, parent, to, parent->child(from), "", QVariant() };
pushOperation(op);
parent->insertChild(to, parent->takeChild(from));
}
void UndoableTreeWidget::updateNode(QTreeWidgetItem *node, const QString &text, const QVariant &data) {
TreeOperation op = { TreeOperation::Update, node->parent(), indexOfTopLevelItem(node->parent()), node, node->text(0), node->data(0) };
pushOperation(op);
node->setText(0, text);
node->setData(0, Qt::UserRole, data);
}
```
6. 实现处理操作记录的函数。在每个操作函数中,根据操作类型执行相应的操作,并将操作记录添加到重做栈中。
```
void UndoableTreeWidget::performOperation(const TreeOperation &op) {
switch (op.type) {
case TreeOperation::Insert:
removeNode(op.node);
break;
case TreeOperation::Remove:
insertNode(op.parent, op.index, op.node);
break;
case TreeOperation::Move:
moveNode(op.parent, op.index, indexOfTopLevelItem(op.node));
break;
case TreeOperation::Update:
updateNode(op.node, op.text, op.data);
break;
}
m_redoStack.clear();
}
void UndoableTreeWidget::pushOperation(const TreeOperation &op) {
if (m_currentOp == nullptr || m_currentOp->node != op.node) {
m_undoStack.push(op);
m_redoStack.clear();
}
}
```
7. 重载QTreeWidget的键盘和鼠标事件处理函数,以便在用户进行新增、删除和移动节点操作时记录操作记录。
```
void UndoableTreeWidget::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Delete) {
QList<QTreeWidgetItem *> selectedItems = selectedItems();
for (QTreeWidgetItem *item : selectedItems) {
removeNode(item);
}
}
QTreeWidget::keyPressEvent(event);
}
void UndoableTreeWidget::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton) {
QTreeWidgetItem *item = itemAt(event->pos());
if (item) {
setItemSelected(item, true);
}
}
QTreeWidget::mousePressEvent(event);
}
```
以上就是实现Qt的QTreeWidget支持撤销重做的步骤和代码。
阅读全文