Qt - 解决插槽上的两个连续调用并仅执行一次操作
Qt - resolve two sequential calls on a slot and perform action only once
我有一个 CodeEditor
class 继承自 QPlainTextEdit
。 class 必须在 textCursor()
的位置或选择发生变化时发出请求。问题是,当同时发出 cursorPositionChanged
和 selectionChanged
时,我不想两次调用 assembleIntellisenseRequest
和 pickListSortRequest
信号。我通过将 bool update_
成员添加到 CodeEditor
来解决这个问题,它在构造函数中设置为 true
。 500 毫秒延迟只是为了清楚起见。
void CodeEditor::makeConnections()
{
auto updateRequest = [this]()
{
if(update_ && !textCursor().hasSelection())
{
update_ = false;
QTimer::singleShot(500, [this]() { update_ = true; });
emit assembleIntellisenseRequest(textCursor().blockNumber());
emit pickListSortRequest(textCursor().positionInBlock());
}
};
connect(this, &CodeEditor::cursorPositionChanged, updateRequest);
connect(this, &CodeEditor::selectionChanged, updateRequest);
}
有没有更好的方法来完成这个?另外,为什么在这种情况下,当 lambda 通过引用捕获时 this1:
打印输出不等于 this:
?沉默了,我才知道,update_
还是false
。
auto updateRequest = [this]()
{
cout << "this: " << this << endl;
if(update_ && !textCursor().hasSelection())
{
update_ = false;
QTimer::singleShot(500, [&]()
{
cout << "this1: " << this << endl;
update_ = true;
});
emit assembleIntellisenseRequest(textCursor().blockNumber());
emit pickListSortRequest(textCursor().positionInBlock());
}
};
提前谢谢你。
您可以将下一个模式应用于您的代码:
class MyClass : public QObject
{
private slots:
void updateRequest();
private:
QTimer *_timer;
CodeEditor *_editor;
};
MyClass::MyClass()
{
// Init members
// ...
_timer->setSingleShot( true );
_timer->setInterval( 0 );
connect( _editor, &CodeEditor:: cursorPositionChanged, _timer, &QTimer::start);
connect( _editor, &CodeEditor:: selectionChanged, _timer, &QTimer::start);
connect( _timer, &QTimer::timeout, this, &MyClass::updateRequest );
}
在此解决方案中,定时器是 "proxy for signals"。每次发出信号时,计时器都会立即启动(当流 return 进入事件循环时)。每次发出信号都会调用 QTimer::start
插槽。但是 start
的所有调用只会将 timeout
信号的一个调用放置到事件队列中。因此,当控制流 return 进入事件循环时,即使发出了很多信号,您的 updateRequest
插槽也只会被调用一次。
QTimer
是一个 "Qt way" 来替换您的 update_
变量,没有任何超时。
我有一个 CodeEditor
class 继承自 QPlainTextEdit
。 class 必须在 textCursor()
的位置或选择发生变化时发出请求。问题是,当同时发出 cursorPositionChanged
和 selectionChanged
时,我不想两次调用 assembleIntellisenseRequest
和 pickListSortRequest
信号。我通过将 bool update_
成员添加到 CodeEditor
来解决这个问题,它在构造函数中设置为 true
。 500 毫秒延迟只是为了清楚起见。
void CodeEditor::makeConnections()
{
auto updateRequest = [this]()
{
if(update_ && !textCursor().hasSelection())
{
update_ = false;
QTimer::singleShot(500, [this]() { update_ = true; });
emit assembleIntellisenseRequest(textCursor().blockNumber());
emit pickListSortRequest(textCursor().positionInBlock());
}
};
connect(this, &CodeEditor::cursorPositionChanged, updateRequest);
connect(this, &CodeEditor::selectionChanged, updateRequest);
}
有没有更好的方法来完成这个?另外,为什么在这种情况下,当 lambda 通过引用捕获时 this1:
打印输出不等于 this:
?沉默了,我才知道,update_
还是false
。
auto updateRequest = [this]()
{
cout << "this: " << this << endl;
if(update_ && !textCursor().hasSelection())
{
update_ = false;
QTimer::singleShot(500, [&]()
{
cout << "this1: " << this << endl;
update_ = true;
});
emit assembleIntellisenseRequest(textCursor().blockNumber());
emit pickListSortRequest(textCursor().positionInBlock());
}
};
提前谢谢你。
您可以将下一个模式应用于您的代码:
class MyClass : public QObject
{
private slots:
void updateRequest();
private:
QTimer *_timer;
CodeEditor *_editor;
};
MyClass::MyClass()
{
// Init members
// ...
_timer->setSingleShot( true );
_timer->setInterval( 0 );
connect( _editor, &CodeEditor:: cursorPositionChanged, _timer, &QTimer::start);
connect( _editor, &CodeEditor:: selectionChanged, _timer, &QTimer::start);
connect( _timer, &QTimer::timeout, this, &MyClass::updateRequest );
}
在此解决方案中,定时器是 "proxy for signals"。每次发出信号时,计时器都会立即启动(当流 return 进入事件循环时)。每次发出信号都会调用 QTimer::start
插槽。但是 start
的所有调用只会将 timeout
信号的一个调用放置到事件队列中。因此,当控制流 return 进入事件循环时,即使发出了很多信号,您的 updateRequest
插槽也只会被调用一次。
QTimer
是一个 "Qt way" 来替换您的 update_
变量,没有任何超时。