Skip to content

Commit 3feb8d2

Browse files
fix(editor): enhance cursor update handling and performance
- Introduced deferred cursor update mechanism to optimize performance during text insertion and deletion. - Added methods to manage cursor updates more efficiently, reducing unnecessary updates when typing. - Improved left area widget refresh logic to only update when the number of lines changes. bug: https://pms.uniontech.com/bug-view-368159.html Log: 优化光标更新处理,提升编辑器性能和响应速度。
1 parent d03911a commit 3feb8d2

2 files changed

Lines changed: 132 additions & 10 deletions

File tree

src/editor/dtextedit.cpp

Lines changed: 120 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,16 @@ TextEdit::TextEdit(QWidget *parent)
109109
// Init widgets.
110110
//左边栏控件 滑动条滚动跟新行号 折叠标记
111111
connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &TextEdit::slotValueChanged);
112-
connect(this, &QPlainTextEdit::textChanged, this, &TextEdit::updateLeftAreaWidget);
113112
connect(this, &QPlainTextEdit::textChanged, this, [this]() {
114-
if (this->m_wrapper)
115-
this->m_wrapper->UpdateBottomBarWordCnt(this->characterCount());
113+
if (m_wrapper) {
114+
m_wrapper->UpdateBottomBarWordCnt(characterCount());
115+
}
116+
// 仅行数变化时全量刷新左侧栏;同行编辑由 cursorPositionChanged 局部 update 负责
117+
const int blockCountNow = blockCount();
118+
if (blockCountNow != m_lastLeftAreaBlockCount) {
119+
m_lastLeftAreaBlockCount = blockCountNow;
120+
updateLeftAreaWidget();
121+
}
116122
});
117123

118124
connect(this, &QPlainTextEdit::cursorPositionChanged, this, &TextEdit::cursorPositionChanged);
@@ -164,6 +170,11 @@ TextEdit::TextEdit(QWidget *parent)
164170
m_scrollAnimation->setEasingCurve(QEasingCurve::InOutExpo);
165171
m_scrollAnimation->setDuration(300);
166172

173+
m_typingBurstFlushTimer = new QTimer(this);
174+
m_typingBurstFlushTimer->setSingleShot(true);
175+
m_typingBurstFlushTimer->setInterval(120);
176+
connect(m_typingBurstFlushTimer, &QTimer::timeout, this, &TextEdit::flushDeferredCursorUpdate);
177+
167178
m_cursorMode = Insert;
168179

169180
connect(m_scrollAnimation, &QPropertyAnimation::finished, this, &TextEdit::handleScrollFinish, Qt::QueuedConnection);
@@ -298,6 +309,7 @@ void TextEdit::deleteSelectTextEx(QTextCursor cursor, QString text, bool currLin
298309
void TextEdit::deleteTextEx(QTextCursor cursor)
299310
{
300311
qDebug() << "Deleting text at position:" << cursor.position();
312+
flushDeferredCursorUpdate();
301313
QUndoCommand *pDeleteStack = new DeleteTextUndoCommand(cursor, this);
302314
m_pUndoStack->push(pDeleteStack);
303315
qDebug() << "Text deleted successfully";
@@ -328,15 +340,32 @@ void TextEdit::deleteMultiTextEx(const QList<QTextCursor> &multiText)
328340
void TextEdit::insertSelectTextEx(QTextCursor cursor, QString text)
329341
{
330342
qDebug() << "Inserting selected text at position:" << cursor.position() << "Length:" << text.length();
343+
344+
const bool deferHeavyUpdate = shouldDeferCursorHeavyUpdate(cursor, text);
345+
if (!deferHeavyUpdate) {
346+
flushDeferredCursorUpdate();
347+
} else {
348+
const int line = cursor.blockNumber();
349+
if (m_deferCursorHeavyUpdate && line != m_deferCursorLastLine) {
350+
flushDeferredCursorUpdate();
351+
}
352+
m_deferCursorHeavyUpdate = true;
353+
m_deferCursorLastLine = line;
354+
}
355+
331356
QUndoCommand *pInsertStack = new InsertTextUndoCommand(cursor, text, this);
332357
m_pUndoStack->push(pInsertStack);
333358
ensureCursorVisible();
359+
if (deferHeavyUpdate) {
360+
scheduleDeferredCursorUpdateBurst();
361+
}
334362
qDebug() << "Selected text inserted successfully";
335363
}
336364

337365
void TextEdit::insertColumnEditTextEx(QString text)
338366
{
339367
qDebug() << "Inserting column text";
368+
flushDeferredCursorUpdate();
340369
if (m_isSelectAll) {
341370
QPlainTextEdit::selectAll();
342371
}
@@ -2987,7 +3016,63 @@ bool TextEdit::setCursorKeywordSeletoin(int position, bool findNext)
29873016
return false;
29883017
}
29893018

2990-
void TextEdit::cursorPositionChanged()
3019+
bool TextEdit::shouldDeferCursorHeavyUpdate(const QTextCursor &cursor, const QString &text) const
3020+
{
3021+
if (m_cursorMode != Insert
3022+
|| m_bIsAltMod
3023+
|| m_readOnlyMode
3024+
|| m_bReadOnlyPermission
3025+
|| m_bIsFileOpen
3026+
|| m_isPreeditBefore
3027+
|| m_bIsInputMethod) {
3028+
return false;
3029+
}
3030+
3031+
if (cursor.anchor() != cursor.position()) {
3032+
return false;
3033+
}
3034+
3035+
for (const QChar ch : text) {
3036+
if (ch == QLatin1Char('\n') || ch == QLatin1Char('\t') || ch == QChar::ParagraphSeparator) {
3037+
return false;
3038+
}
3039+
}
3040+
3041+
return true;
3042+
}
3043+
3044+
void TextEdit::scheduleDeferredCursorUpdateBurst()
3045+
{
3046+
m_deferCursorHeavyUpdate = true;
3047+
m_deferCursorLastLine = textCursor().blockNumber();
3048+
m_typingBurstFlushTimer->start();
3049+
}
3050+
3051+
void TextEdit::flushDeferredCursorUpdate()
3052+
{
3053+
if (m_typingBurstFlushTimer != nullptr) {
3054+
m_typingBurstFlushTimer->stop();
3055+
}
3056+
3057+
if (!m_deferCursorHeavyUpdate) {
3058+
return;
3059+
}
3060+
3061+
m_deferCursorHeavyUpdate = false;
3062+
m_deferCursorLastLine = -1;
3063+
applyCursorHeavyUpdate();
3064+
}
3065+
3066+
void TextEdit::updateCursorPositionStatusLightweight()
3067+
{
3068+
QTextCursor cursor = textCursor();
3069+
if (m_wrapper) {
3070+
m_wrapper->bottomBar()->updatePosition(cursor.blockNumber() + 1,
3071+
cursor.positionInBlock() + 1);
3072+
}
3073+
}
3074+
3075+
void TextEdit::applyCursorHeavyUpdate()
29913076
{
29923077
qDebug() << "Cursor position changed";
29933078
// 以赋值形式,清空 Bracket 括号的selection
@@ -3001,19 +3086,30 @@ void TextEdit::cursorPositionChanged()
30013086
updateHighlightBrackets('[', ']');
30023087
renderAllSelections();
30033088

3004-
QTextCursor cursor = textCursor();
3005-
if (m_wrapper) {
3006-
qDebug() << "Cursor position changed with wrapper";
3007-
m_wrapper->bottomBar()->updatePosition(cursor.blockNumber() + 1,
3008-
cursor.positionInBlock() + 1);
3009-
}
3089+
updateCursorPositionStatusLightweight();
30103090

30113091
m_pLeftAreaWidget->m_pLineNumberArea->update();
30123092
m_pLeftAreaWidget->m_pBookMarkArea->update();
30133093
m_pLeftAreaWidget->m_pFlodArea->update();
30143094
qDebug() << "Cursor position changed completed";
30153095
}
30163096

3097+
void TextEdit::cursorPositionChanged()
3098+
{
3099+
if (m_deferCursorHeavyUpdate) {
3100+
const int line = textCursor().blockNumber();
3101+
if (line != m_deferCursorLastLine) {
3102+
flushDeferredCursorUpdate();
3103+
return;
3104+
}
3105+
3106+
updateCursorPositionStatusLightweight();
3107+
return;
3108+
}
3109+
3110+
applyCursorHeavyUpdate();
3111+
}
3112+
30173113
/**
30183114
* @brief 剪切光标选中的文本
30193115
* @param ignoreCheck 是否忽略权限判断(外部已进行),默认false
@@ -3539,6 +3635,7 @@ void TextEdit::slotRedoAvailable(bool redoIsAvailable)
35393635
void TextEdit::redo_()
35403636
{
35413637
qDebug() << "Starting redo operation";
3638+
flushDeferredCursorUpdate();
35423639
if (!m_pUndoStack->canRedo()) {
35433640
qDebug() << "Redo operation skipped - nothing to redo";
35443641
return;
@@ -3570,6 +3667,7 @@ void TextEdit::undo_()
35703667
{
35713668
qDebug() << "Starting undo operation";
35723669
qDebug() << "Starting undo operation";
3670+
flushDeferredCursorUpdate();
35733671
if (!m_pUndoStack->canUndo()) {
35743672
qDebug() << "Undo operation skipped - nothing to undo";
35753673
return;
@@ -5495,6 +5593,7 @@ void TextEdit::setTextFinished()
54955593
qDebug() << "Set text finished";
54965594
m_bIsFileOpen = false;
54975595
m_nLines = blockCount();
5596+
m_lastLeftAreaBlockCount = m_nLines;
54985597

54995598
if (!m_listBookmark.isEmpty()) {
55005599
qDebug() << "Set text finished, m_listBookmark is not empty";
@@ -6563,6 +6662,13 @@ void TextEdit::updateMark(int from, int charsRemoved, int charsAdded)
65636662
return;
65646663
}
65656664

6665+
// 无任何颜色/关键字标记时无需处理;渲染由 cursorPositionChanged 统一负责
6666+
if (m_wordMarkSelections.isEmpty()
6667+
&& m_mapKeywordMarkSelections.isEmpty()
6668+
&& m_mapWordMarkSelections.isEmpty()) {
6669+
return;
6670+
}
6671+
65666672
qDebug() << "updateMark, charsRemoved" << charsRemoved << "charsAdded" << charsAdded;
65676673
//更新标记
65686674
int nStartPos = 0,///< 标记的起始位置
@@ -7604,6 +7710,7 @@ void TextEdit::dropEvent(QDropEvent *event)
76047710

76057711
void TextEdit::inputMethodEvent(QInputMethodEvent *e)
76067712
{
7713+
flushDeferredCursorUpdate();
76077714
m_bIsInputMethod = true;
76087715

76097716
if (m_isSelectAll)
@@ -7674,6 +7781,7 @@ void TextEdit::inputMethodEvent(QInputMethodEvent *e)
76747781

76757782
void TextEdit::mousePressEvent(QMouseEvent *e)
76767783
{
7784+
flushDeferredCursorUpdate();
76777785
if (m_bIsFindClose)
76787786
{
76797787
m_bIsFindClose = false;
@@ -8193,6 +8301,7 @@ void TextEdit::keyPressEvent(QKeyEvent *e)
81938301

81948302
//列编辑 删除撤销重做
81958303
if (modifiers == Qt::NoModifier && (e->key() == Qt::Key_Backspace)) {
8304+
flushDeferredCursorUpdate();
81968305
if (m_isSelectAll)
81978306
QPlainTextEdit::selectAll();
81988307

@@ -8216,6 +8325,7 @@ void TextEdit::keyPressEvent(QKeyEvent *e)
82168325

82178326
//列编辑 向后删除撤销重做
82188327
if (modifiers == Qt::NoModifier && (e->key() == Qt::Key_Delete)) {
8328+
flushDeferredCursorUpdate();
82198329
if (m_isSelectAll)
82208330
QPlainTextEdit::selectAll();
82218331

src/editor/dtextedit.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <DPlainTextEdit>
2828
#include <QLineEdit>
2929
#include <QPropertyAnimation>
30+
#include <QTimer>
3031
#include <QFont>
3132
#include <DGuiApplicationHelper>
3233
#include <QtDBus>
@@ -510,6 +511,9 @@ public slots:
510511
void onSelectionArea();
511512
void fingerZoom(QString name, QString direction, int fingers);
512513
void cursorPositionChanged();
514+
void flushDeferredCursorUpdate();
515+
void applyCursorHeavyUpdate();
516+
void updateCursorPositionStatusLightweight();
513517

514518
//剪切槽函数
515519
void cut(bool ignoreCheck = false);
@@ -784,6 +788,7 @@ private slots:
784788
QList<int> m_listBookmark;///< 存储书签的list
785789
int m_nBookMarkHoverLine;///< 悬浮效果书签所在的行
786790
int m_nLines;///< 文本总行数
791+
int m_lastLeftAreaBlockCount = 0;///< 上次刷新左侧栏时的文档行数
787792
bool m_bIsFileOpen;///< 是否在读取文件(导致文本变化)
788793
bool m_bIsShortCut;///< 是否在使用书签快捷键
789794

@@ -872,6 +877,13 @@ private slots:
872877
bool m_isPreeditBefore = false; // 上一个输入法时间是否是 preedit
873878
int m_preeditLengthBefore = 0;
874879

880+
bool shouldDeferCursorHeavyUpdate(const QTextCursor &cursor, const QString &text) const;
881+
void scheduleDeferredCursorUpdateBurst();
882+
883+
bool m_deferCursorHeavyUpdate = false;
884+
int m_deferCursorLastLine = -1;
885+
QTimer *m_typingBurstFlushTimer = nullptr;
886+
875887
Qt::CaseSensitivity defaultCaseSensitive = Qt::CaseInsensitive; // 查找匹配时默认不区分大小写
876888
};
877889
#endif

0 commit comments

Comments
 (0)