From 941ab59d445237580e12df6d110f10aff21f4148 Mon Sep 17 00:00:00 2001 From: xiepengfei Date: Mon, 20 Apr 2026 17:17:31 +0800 Subject: [PATCH] fix(annotation): use text layout positions for ruled lines in note editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use QTextDocument's actual layout (QTextBlock/QTextLine) instead of fixed font metrics height to draw ruled lines, preventing accumulated drift that causes text/line overlap after 10+ lines. 使用QTextDocument实际布局信息绘制注释编辑框横线, 替代固定字体度量的等差递增方式,修复多行文字与行线重叠问题。 Log: 修复注释编辑框多行文字与横线重叠 PMS: BUG-338065 Influence: 注释编辑框输入超过10行时,横线与文字不再错位重叠。 --- reader/widgets/TransparentTextEdit.cpp | 79 ++++++++++++++------------ 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/reader/widgets/TransparentTextEdit.cpp b/reader/widgets/TransparentTextEdit.cpp index 4b8c2983c..0ea20380f 100644 --- a/reader/widgets/TransparentTextEdit.cpp +++ b/reader/widgets/TransparentTextEdit.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd. +// Copyright (C) 2019 ~ 2026 Uniontech Software Technology Co.,Ltd. // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -78,52 +78,61 @@ void TransparentTextEdit::slotTextEditMaxContantNum() void TransparentTextEdit::paintEvent(QPaintEvent *event) { - // qCDebug(appLog) << "TransparentTextEdit::paintEvent start"; QTextEdit::paintEvent(event); QPainter painter(this->viewport()); - painter.setRenderHints(QPainter::Antialiasing); - - int maxLineHeight = 2; - - int totalheight = this->viewport()->height() - maxLineHeight; - - const QFontMetricsF &fontmetricsf = QFontMetricsF(this->font()); - - qreal lineheight = fontmetricsf.height(); - painter.setBrush(Qt::NoBrush); - QPen pen(QColor(219, 189, 119), maxLineHeight); - - painter.setPen(pen); - - int startLine = static_cast(this->document()->documentMargin() - this->verticalScrollBar()->value()); + const qreal topLineHeight = 2.0; + const qreal normalLineHeight = 1.0; + const qreal leftMargin = 2.0; + const qreal rightMargin = 4.0; + const qreal viewWidth = this->viewport()->width() * 1.0; - painter.drawLine(2, startLine, this->viewport()->width() - 4, startLine); - - pen.setWidth(1); + qreal scrollY = this->verticalScrollBar()->value(); + qreal docMargin = this->document()->documentMargin(); + qreal viewportHeight = this->viewport()->height(); + // Top line (thicker, at document margin) + qreal topY = docMargin - scrollY; + QPen pen(QColor(219, 189, 119), topLineHeight); painter.setPen(pen); + painter.drawLine(QPointF(leftMargin, topY), QPointF(viewWidth - rightMargin, topY)); - qreal curh; - - for (curh = startLine + lineheight; curh <= totalheight; curh += lineheight) { - painter.drawLine(QPointF(2.0, curh), QPointF(this->viewport()->width() * 1.0 - 4.0, curh)); - } - - if (this->verticalScrollBar()->maximum() - this->verticalScrollBar()->value() < maxLineHeight) { - // qCDebug(appLog) << "Drawing bottom line"; - pen.setWidth(maxLineHeight); - - painter.setPen(pen); - - curh -= lineheight; + // Draw ruled lines aligned with actual text layout + pen.setWidth(normalLineHeight); + painter.setPen(pen); - painter.drawLine(QPointF(2.0, curh), QPointF(this->viewport()->width() * 1.0 - 4.0, curh)); + bool atBottom = (this->verticalScrollBar()->maximum() - this->verticalScrollBar()->value()) < topLineHeight; + + QTextDocument *doc = this->document(); + QTextBlock block = doc->begin(); + while (block.isValid()) { + QTextLayout *layout = block.layout(); + if (layout) { + QPointF blockPos = layout->position(); + for (int i = 0; i < layout->lineCount(); ++i) { + QTextLine textLine = layout->lineAt(i); + qreal lineY = blockPos.y() + textLine.position().y() + textLine.height() - scrollY; + if (lineY < topY) + continue; + if (lineY > viewportHeight) + break; + // Last visible line gets thicker bottom stroke + if (atBottom && lineY + textLine.height() > viewportHeight) { + pen.setWidth(topLineHeight); + painter.setPen(pen); + } + painter.drawLine(QPointF(leftMargin, lineY), QPointF(viewWidth - rightMargin, lineY)); + if (pen.widthF() != normalLineHeight) { + pen.setWidth(normalLineHeight); + painter.setPen(pen); + } + } + } + block = block.next(); } - // qCDebug(appLog) << "TransparentTextEdit::paintEvent end"; } void TransparentTextEdit::insertFromMimeData(const QMimeData *source)