Номера строк / высота строки для Qml TextArea - PullRequest
2 голосов
/ 04 июля 2019

Мы хотим внедрить встроенный редактор кода в наше приложение на базе QtQuick.Для выделения мы используем QSyntaxHighlighter на основе KSyntaxHighlighting.Мы не нашли способа определить высоту строки и межстрочный интервал, которые позволили бы нам отображать номера строк рядом с кодом.Поддержка динамического переноса строк также была бы отличным дополнением.

    Flickable {
            id: flickable
            flickableDirection: Flickable.VerticalFlick
            Layout.preferredWidth: parent.width
            Layout.maximumWidth: parent.width
            Layout.minimumHeight: 200
            Layout.fillHeight: true
            Layout.fillWidth: true

            boundsBehavior: Flickable.StopAtBounds
            clip: true
            ScrollBar.vertical: ScrollBar {
                width: 15
                active: true
                policy: ScrollBar.AlwaysOn
            }

            property int rowHeight: textArea.font.pixelSize+3
            property int marginsTop: 10
            property int marginsLeft: 4
            property int lineCountWidth: 40

            Column {
                id: lineNumbers
                anchors.left: parent.left
                anchors.leftMargin: flickable.marginsLeft
                anchors.topMargin:   flickable.marginsTop
                y:  flickable.marginsTop
                width: flickable.lineCountWidth

                function range(start, end) {
                    var rangeArray = new Array(end-start);
                    for(var i = 0; i < rangeArray.length; i++){
                        rangeArray[i] = start+i;
                    }
                    return rangeArray;
                }

                Repeater {
                    model: textArea.lineCount
                    delegate:
                    Label {
                        color: (!visualization.urdfPreviewIsOK && (index+1) === visualization.urdfPreviewErrorLine) ? "white" :  "#666"
                        font: textArea.font
                        width: parent.width
                        horizontalAlignment: Text.AlignRight
                        verticalAlignment: Text.AlignVCenter
                        height: flickable.rowHeight
                        renderType: Text.NativeRendering
                        text: index+1
                        background: Rectangle {
                            color: (!visualization.urdfPreviewIsOK && (index+1) === visualization.urdfPreviewErrorLine) ? "red" : "white"
                        }
                    }
                }
            }
            Rectangle {
                y: 4
                height: parent.height
                anchors.left: parent.left
                anchors.leftMargin: flickable.lineCountWidth + flickable.marginsLeft
                width: 1
                color: "#ddd"
            }

        TextArea.flickable: TextArea {
                id: textArea

                property bool differentFromSavedState: fileManager.textDifferentFromSaved

                text: fileManager.textTmpState
                textFormat: Qt.PlainText
                //dont wrap to allow for easy line annotation wrapMode: TextArea.Wrap
                focus: false
                selectByMouse: true
                leftPadding: flickable.marginsLeft+flickable.lineCountWidth
                rightPadding: flickable.marginsLeft
                topPadding: flickable.marginsTop
                bottomPadding: flickable.marginsTop

                background: Rectangle {
                    color: "white"
                    border.color: "green"
                    border.width: 1.5
                }

                Component.onCompleted: {
                    fileManager.textEdit = textArea.textDocument
                }

                onTextChanged: {
                    fileManager.textTmpState = text
                }

                function update()
                {
                    text = fileManager.textTmpState
                }
            }
        }

Как вы можете видеть, мы используем property int rowHeight: textArea.font.pixelSize+3, чтобы угадать высоту строки и межстрочный интервал, но это, конечно, нарушается, как только DPI или другие свойстваизменения системы.

1 Ответ

1 голос
/ 05 июля 2019

Тип TextArea имеет два свойства contentWidth и contentHeight, которые содержат размер текстового содержимого.

Итак, если вы поделите высоту на количество строк (которое вы можете получить с помощью свойства lineCount), вы получите высоту строки:

property int rowHeight: textArea.contentHeight / textArea.lineCount

Но, если вы планируете иметь несколько межстрочных интервалов в одном документе, вам придется обрабатывать каждую строку, манипулируя QTextDocument:

class LineManager: public QObject
{
    Q_OBJECT
    Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged)
public:
    LineManager(): QObject(), document(nullptr)
    {}
    Q_INVOKABLE void setDocument(QQuickTextDocument* qdoc)
    {
        document = qdoc->textDocument();
        connect(document, &QTextDocument::blockCountChanged, this, &LineManager::lineCountChanged);
    }

    Q_INVOKABLE int lineCount() const
    {
        if (!document)
            return 0;
        return document->blockCount();
    }

    Q_INVOKABLE int height(int lineNumber) const
    {
        return int(document->documentLayout()->blockBoundingRect(document->findBlockByNumber(lineNumber)).height());
    }
signals:
    void lineCountChanged();
private:
    QTextDocument* document;
};
    LineManager* mgr = new LineManager();
    QQuickView *view = new QQuickView;
    view->rootContext()->setContextProperty("lineCounter", mgr);
    view->setSource(QUrl("qrc:/main.qml"));
    view->show();
Repeater {
    model: lineCounter.lineCount
    delegate:
        Label {
            color: "#666"
            font: textArea.font
            width: parent.width
            height: lineCounter.height(index)
            horizontalAlignment: Text.AlignRight
            verticalAlignment: Text.AlignVCenter
            renderType: Text.NativeRendering
            text: index+1
            background: Rectangle {
                border.color: "black"
            }
    }
}
...