c++ - 撤消历史记录的问题(QUndoStack、QUndoView 和其他)

标签 c++ qt qt5 undo-redo

我有两个独立的线程。 第一个线程用于 GUI,第二个线程用于应用程序数据。

最初,我想使用 QUndoStack 和 QUndoView。

但是有一个问题——这个 View 直接与堆栈一起工作:

https://code.woboq.org/qt5/qtbase/src/widgets/util/qundoview.cpp.html#_ZN10QUndoModel20setStackCurrentIndexERK11QModelIndex

在这种情况下,我遇到了竞争条件。

为了解决这个问题,我使用 QListView 和 QAbstractListModel 编写了自定义 myUndoView。 现在我所有的插槽都使用排队连接,并且我在自定义 View 模型中存储了“真实”撤消堆栈的轻量级拷贝。 这与“真实”撤消堆栈元素的大小和顺序相同。 轻量级元素仅包含撤消命令的类型和文本。

现在我有另一个问题。这不怪我 ))

我有一个 QLineEdit,当我单击 Enter 键或失去焦点时,它会在值发生变化时发出信号。 该值依次发送到具有“真实”撤消堆栈的对象(应用程序模型)。它有效。

但是当我也与撤消 View 交互时,这不起作用。 重复一遍,这不怪我。 QUndoView 具有相同的行为。

一步一步:

  1. 关注 QLineEdit。
  2. 不断变化的值(value),仍然是焦点。
  3. 在撤消 View 中单击鼠标。

Oops.. currentIndexChanged() 撤消 View 的信号可以先发送, 或者可以先发送来自 QLineEdit 的信号。

它总是不同的..

如果先发送来自 QLineEdit 的信号 - 它工作正常。 变化的历史不会丢失。

我想让 enter/blur 和其他更改(不在历史 View 中)始终首先调用。可能我可以使用 QTimer::singleShot() 来延迟发出撤消 View 信号。但不是 curentIndexChanged(),因为此信号随用户交互以及撤消堆栈以编程方式更新时发出。我们无法确定谁进行更改 - 用户还是应用程序。

我试过什么?

拦截鼠标点击:

myUndoView::mousePressEvent(QMouseEvent *event)
{
    event->ignore();
    qDebug() << "catched!";
}

但有时它会丢失点击次数。 列表项底部(字母下方)是一个区域,可将点击传递给该项目。 这可能是一个 Qt 错误,在我的环境中发现:Debian、Mate、GTK+ Qt 风格。

我想,我可以在列表上放置另一个透明小部件,并获取点击的坐标并使用它:

http://doc.qt.io/qt-5/qabstractitemview.html#indexAt

获取选定的索引。

还是我都弄错了? 也许有更简单的方法?

如何做到正确?

最佳答案

我会尝试 blocking the list model signals当行编辑被聚焦时。

让我们有一个这样的事件过滤器:

class EventFilter : public QObject
{
    Q_OBJECT
public:
    EventFilter(QObject * model) : _model(model){}
    bool eventFilter(QObject *watched, QEvent *event);
private:
    QObject * _model;
};

它保留对列表模型的私有(private)引用作为指向 QObject 的指针,在构造函数参数中传递。

过滤器实现:

bool EventFilter::eventFilter(QObject *watched, QEvent *event)
{
    if(event->type() == QEvent::FocusIn)
    {
        _model->blockSignals(true);
    }
    return false;
}

在窗口类(Form,在我的示例中)中保留对过滤器实例的引用,以及列表模型实例引用:

private:
   EventFilter * filter;
   QAbstractListModel * model;

过滤器必须在 Form 构造函数中的行编辑中实例化和安装(不要忘记在析构函数中删除它):

filter = new EventFilter(model); //the model is passed to the filter in construction
ui->lineEdit->installEventFilter(filter);

此时,当行编辑获得焦点时,模型事件将被阻止。要解锁它们,请使用行编辑 editingFinished 插槽:

void Form::on_lineEdit_editingFinished()
{
    model->blockSignals(false);
}

关于c++ - 撤消历史记录的问题(QUndoStack、QUndoView 和其他),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48622510/

相关文章:

c++ - exe文件图标变化。取自 SHELL32.dll 的图标

c++ - 为 QWidget 派生 move 赋值运算符?

c++ - 将exe文件复制到Qt构建目录

qt - 将 ListModel 的特定项目绑定(bind)到组件

c++ - 如何在 Qt 中放大/缩小图像的选定部分?

javascript - QWebEngine - 获取当前最大滚动值

c++ - mutable boost::mutex 是否可以将锁定和等待功能分开?

c++ - SendInput 鼠标时间

c++ - 如何检查类中传递的参数是否正确

c++ - 如何设置Qt工具提示宽度