每当我尝试在 QTextCursor 选择上调用 QTextCharFormat 时,父函数就会终止
Parent function terminates whenever I try to call QTextCharFormat on QTextCursor selection
我最近 运行 遇到一个奇怪的问题,每当调用 QTextCursor::mergeCharFormat/setCharFormat/setBlockCharFormat
时,我的 QPlainTextEdit::selectionChanged
处理函数就会过早终止。此外,终止后它会再次调用并遇到相同的问题,从而导致无限循环。
我正在尝试复制许多文本编辑器(例如 Notepad++)中存在的功能,在该功能中选择一个词后,整个文档中的所有相似词都会突出显示。我的 TextEditor
class 是从 QPlainTextEdit
.
超载的
最小的可重现示例如下:
main.cpp:
#include "mainWindow.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
mainWindow w;
w.show();
return a.exec();
}
MainWindow.h:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_mainWindow.h"
#include "TextEditor.h"
class mainWindow : public QMainWindow
{
Q_OBJECT
public:
mainWindow(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
{
ui.setupUi(this);
auto textEdit = new TextEditor(this);
textEdit->setPlainText("test lorem ipsum test\n dolor sit test");
ui.tabWidget->addTab(textEdit, "Editor"); //Or any other way of adding the widget to the window
}
private:
Ui::mainWindowClass ui;
};
TextEditor.h:
正则表达式荧光笔部分基于this SO answer。
#pragma once
#include <QPlainTextEdit>
class TextEditor : public QPlainTextEdit
{
Q_OBJECT
public:
TextEditor(QWidget* parent) : QPlainTextEdit(parent)
{
connect(this, &QPlainTextEdit::selectionChanged, this, &TextEditor::selectChangeHandler);
}
private:
void selectChangeHandler()
{
//Ignore empty selections
if (textCursor().selectionStart() >= textCursor().selectionEnd())
return;
//We only care about fully selected words (nonalphanumerical characters on either side of selection)
auto plaintext = toPlainText();
auto prevChar = plaintext.mid(textCursor().selectionStart() - 1, 1).toStdString()[0];
auto nextChar = plaintext.mid(textCursor().selectionEnd(), 1).toStdString()[0];
if (isalnum(prevChar) || isalnum(nextChar))
return;
auto qselection = textCursor().selectedText();
auto selection = qselection.toStdString();
//We also only care about selections that do not themselves contain nonalphanumerical characters
if (std::find_if(selection.begin(), selection.end(), [](char c) { return !isalnum(c); }) != selection.end())
return;
//Prepare text format
QTextCharFormat format;
format.setBackground(Qt::green);
//Find all words in our document that match the selected word and apply the background format to them
size_t pos = 0;
auto reg = QRegExp(qselection);
auto cur = textCursor();
auto index = reg.indexIn(plaintext, pos);
while (index >= 0)
{
//Select matched text and apply format
cur.setPosition(index);
cur.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor, 1);
cur.mergeCharFormat(format); //This causes the selectChangeHandler function to terminate and then execute again, causing an infinite loop leading to a stack overflow
//Move to next match
pos = index + (size_t)reg.matchedLength();
index = reg.indexIn(plaintext, pos);
}
}
};
我怀疑格式由于某种原因无法应用,可能导致在 Qt 中捕获并终止父函数的异常。我尝试在有问题的区域周围添加我自己的 try-catch 处理程序,但它什么也没做(如预期的那样)。
我不确定这是我的错还是 Qt 中的错误。有人知道我做错了什么或如何解决这个问题吗?
正在生成无限循环,因为获取文本更改似乎也会更改选择。一种可能的解决方案是使用 QSignalBlocker 来阻止信号:
void selectChangeHandler()
{
const QSignalBlocker blocker(this); // <--- this line
//Ignore empty selections
if (textCursor().selectionStart() >= textCursor().selectionEnd())
return;
// ...
我最近 运行 遇到一个奇怪的问题,每当调用 QTextCursor::mergeCharFormat/setCharFormat/setBlockCharFormat
时,我的 QPlainTextEdit::selectionChanged
处理函数就会过早终止。此外,终止后它会再次调用并遇到相同的问题,从而导致无限循环。
我正在尝试复制许多文本编辑器(例如 Notepad++)中存在的功能,在该功能中选择一个词后,整个文档中的所有相似词都会突出显示。我的 TextEditor
class 是从 QPlainTextEdit
.
最小的可重现示例如下:
main.cpp:
#include "mainWindow.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
mainWindow w;
w.show();
return a.exec();
}
MainWindow.h:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_mainWindow.h"
#include "TextEditor.h"
class mainWindow : public QMainWindow
{
Q_OBJECT
public:
mainWindow(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
{
ui.setupUi(this);
auto textEdit = new TextEditor(this);
textEdit->setPlainText("test lorem ipsum test\n dolor sit test");
ui.tabWidget->addTab(textEdit, "Editor"); //Or any other way of adding the widget to the window
}
private:
Ui::mainWindowClass ui;
};
TextEditor.h:
正则表达式荧光笔部分基于this SO answer。
#pragma once
#include <QPlainTextEdit>
class TextEditor : public QPlainTextEdit
{
Q_OBJECT
public:
TextEditor(QWidget* parent) : QPlainTextEdit(parent)
{
connect(this, &QPlainTextEdit::selectionChanged, this, &TextEditor::selectChangeHandler);
}
private:
void selectChangeHandler()
{
//Ignore empty selections
if (textCursor().selectionStart() >= textCursor().selectionEnd())
return;
//We only care about fully selected words (nonalphanumerical characters on either side of selection)
auto plaintext = toPlainText();
auto prevChar = plaintext.mid(textCursor().selectionStart() - 1, 1).toStdString()[0];
auto nextChar = plaintext.mid(textCursor().selectionEnd(), 1).toStdString()[0];
if (isalnum(prevChar) || isalnum(nextChar))
return;
auto qselection = textCursor().selectedText();
auto selection = qselection.toStdString();
//We also only care about selections that do not themselves contain nonalphanumerical characters
if (std::find_if(selection.begin(), selection.end(), [](char c) { return !isalnum(c); }) != selection.end())
return;
//Prepare text format
QTextCharFormat format;
format.setBackground(Qt::green);
//Find all words in our document that match the selected word and apply the background format to them
size_t pos = 0;
auto reg = QRegExp(qselection);
auto cur = textCursor();
auto index = reg.indexIn(plaintext, pos);
while (index >= 0)
{
//Select matched text and apply format
cur.setPosition(index);
cur.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor, 1);
cur.mergeCharFormat(format); //This causes the selectChangeHandler function to terminate and then execute again, causing an infinite loop leading to a stack overflow
//Move to next match
pos = index + (size_t)reg.matchedLength();
index = reg.indexIn(plaintext, pos);
}
}
};
我怀疑格式由于某种原因无法应用,可能导致在 Qt 中捕获并终止父函数的异常。我尝试在有问题的区域周围添加我自己的 try-catch 处理程序,但它什么也没做(如预期的那样)。
我不确定这是我的错还是 Qt 中的错误。有人知道我做错了什么或如何解决这个问题吗?
正在生成无限循环,因为获取文本更改似乎也会更改选择。一种可能的解决方案是使用 QSignalBlocker 来阻止信号:
void selectChangeHandler()
{
const QSignalBlocker blocker(this); // <--- this line
//Ignore empty selections
if (textCursor().selectionStart() >= textCursor().selectionEnd())
return;
// ...