在 QPlainTextEdit 的第 80 列中画一条线

Draw a line in column 80 of QPlainTextEdit

本文关键字:一条 QPlainTextEdit 的第      更新时间:2023-10-16

我正在编写一个文本编辑器并将Qt用于GUI。我是Qt的菜鸟,我很难做到这一点。

我需要在QPlainTextEdit的第80列中画一条线,但我真的不知道怎么做。我正在使用QPainter,但我就是无法正确处理,有什么帮助吗?

这是我的做法。诚然,这并不完全是微不足道的。确定第 80 列位置的输入是:

  1. 浮点平均字符宽度的 80 倍。使用整数值会将舍入误差放大 80 倍。因此使用QFontMetricsF.

  2. 滚动条引起的偏移量来自 contentOffset() .使用horizontalScrollbar()->value()会很糟糕.后者目前有效,但依赖于特定于实现的细节。QPlainTextEdit碰巧将滚动条值映射到像素 - 谁知道明天它是否会改变。它没有记录,因此属于未指定的行为。

  3. QTextDocument实现自己的保证金,可通过documentMargin() .

另一个陷阱是:你必须在任何源自QAbstractScrollArea的类的viewport()上绘画——QPlainTextEdit这样做了。如果你不这样做,你的paintEvent就变成了禁区。它有文档记录,但您必须足够聪明才能实际查看文档。我认为这是 API 的一个糟糕的极端情况,它做了一些意想不到的事情。在所有其他paintEvent中,您只需创建QPainter pQPainter p(this)即可工作。

注意:这是经过测试的可编译代码。

//main.cpp
#include <cmath>
#include <QtWidgets>
class Edit : public QPlainTextEdit
{
public:
    Edit(QWidget * parent = 0) : QPlainTextEdit(parent) {}
protected:
    void paintEvent(QPaintEvent * ev)
    {
        QPlainTextEdit::paintEvent(ev);
        const QRect rect = ev->rect();
        const QFont font = currentCharFormat().font();
        int x80 = round(QFontMetricsF(font).averageCharWidth() * 80.0)
                + contentOffset().x()
                + document()->documentMargin();
        QPainter p(viewport());
        p.setPen(QPen("gray"));
        p.drawLine(x80, rect.top(), x80, rect.bottom());
        qDebug() << x80 << contentOffset() << document()->documentMargin() << font << endl;
    }
};
static QString filler()
{
    QString str;
    for (char c = '0'; c < '9'; ++ c) {
        str.append(QString(10, c));
    }
    return str;
}
int main(int argc, char ** argv)
{
    QApplication app(argc, argv);
    Edit ed;
    QTextCharFormat fmt = ed.currentCharFormat();
    fmt.setFontFamily("courier");
    fmt.setFontFixedPitch(true);
    ed.setCurrentCharFormat(fmt);
    ed.setLineWrapMode(QPlainTextEdit::NoWrap);
    qDebug() << fmt.font() << endl;
    ed.setPlainText(filler());
    ed.show();
    app.exec();
}
#include "main.moc"