QTextLayout / QTextLine поддерживает группировку из нескольких символов, поэтому он действует как один символ для курсора

#qt

Вопрос:

Возможно ли, чтобы QTextLayout отображал несколько символов, но обрабатывал/обрабатывал их как один символ. Например, отображение кодовой точки, такой как: [U 202e], и при перемещении курсора/вычислении позиций она обрабатывается как один символ.

Отредактированный:

Пожалуйста, проверьте эту следующую проблему, если я объясню, что я пытаюсь сделать. Это для компонента Qt edbee. Он использует QTextLayout для линейного рендеринга.

https://github.com/edbee/edbee-lib/issues/127

Возможно, это невозможно с QTextLayout, документация довольно ограничена.

Комментарии:

1. Я реализовал решение/обходной путь. Я завернул QTextLayout в свой собственный класс TextLayout, который выполняет вычисления виртуального курсора… (Для получения более подробной информации: github.com/edbee/edbee-lib/issues/128 )

Ответ №1:

Согласно документам Qt:

«Класс имеет довольно низкоуровневый API, и если вы не собираетесь реализовывать собственный рендеринг текста для какого — либо специализированного виджета, вам, вероятно, не потребуется использовать его напрямую». — https://doc.qt.io/qt-5/qtextlayout.html#details

Вероятно, вам следует использовать QLineEdit или QTextEdit (у каждого есть вызываемый метод setReadOnly(bool) ).

Прежде чем ответить на вопрос, я отмечу, что CursorMode перечисление (https://doc.qt.io/qt-5/qtextlayout.html#CursorMode-enum) кажется очень многообещающим для этой проблемы, но, на мой взгляд, в документации неясно, как его использовать или настроить.

Теперь, чтобы ответить на ваш вопрос относительно QLineEdit или QTextEdit, это немного сложно, но это то же самое для QLineEdit и QTextEdit, поэтому давайте посмотрим на QTextEdit.

Во-первых, щелчки мыши: у QTextEdit есть вызванный сигнал cursorPositionChanged() , который будет полезен здесь. Вы захотите подключить его к пользовательскому слоту, который может использовать эту функцию moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor) (https://doc.qt.io/qt-5/qtextedit.html#moveCursor). Обратите внимание, что здесь, в QTextCursor::MoveOperation, для вас есть очень полезные значения перечисления, касающиеся перехода по словам (https://doc.qt.io/qt-5/qtextcursor.html#MoveOperation-enum). Как нам собрать все это воедино? Что ж, вероятно, правильный способ сделать это-определить ширину символов слева от положения курсора и ширину символов справа от положения курсора при подаче cursorPositionChanged() сигнала и перейти к стороне слова, которая имеет меньшую ширину. Однако я не уверен, как это сделать. На этом этапе я бы ограничился проверкой количества символов слева и справа и переходом в сторону с меньшим количеством.

Во-вторых, нажатия на клавиатуре: это немного выходит за рамки моих знаний, но почти все, что можно рисовать и выполнять, наследуется от QWidget. Взгляните на https://doc.qt.io/qt-5/qwidget.html#keyPressEvent и вполне возможно, что наиглавнейшее, что в вашей собственной реализации QTextEdit и надо чтобы стрелка влево и Стрелка вправо нажатий клавиш, чтобы перейти слов (как только вы получите, что это довольно просто, достаточно использовать одну и ту же функцию, как и в прошлом разделе, для перемещения курсора, или, в случае QLineEdit, cursorWordForward() / cursorWordBackward() ).

Все это, как говорится, я до сих пор предполагал, что вы ничего не удаляете и ничего не выбираете. Выбор может быть настоящей проблемой в зависимости от того, разрешаете ли вы несколько вариантов выбора, но в документации есть все функции для реализации этих вещей.

Пример внедрения щелчка мыши:

myclass.ГЭС

 #include <QTextEdit>
#include <QTextCursor>
#include <QObject>
#include <QString>

int distance_to_word_beginning_or_end(const QString amp;str, int index, bool beginning);

class MyClass {
    MyClass();
    ~MyClass();

private:
    QTextEdit *text_edit;

public slots:
    void text_edit_changed_cursor_location();
};
 

myclass.cpp

 #include "myclass.hpp"

int distance_to_word_beginning_or_end(const QString amp;str, int index, bool beginning)
{
    // return the distance from the beginning or end of the word from the index given
    int inc_or_dec = (beginning) ? -1 : 1;
    int distance = 0;
    while (index >= 0 amp;amp; index < str.length())
    {
        if (str.at(index) == ' ' || str.at(index) == 'n' || str.at(index) == 't')
        {
            return distance;
        }
        distance  ;
        index  = inc_or_dec;
    }
    return --distance;
}

MyClass::MyClass()
{
    text_edit = new QTextEdit();
    QObject::connect(text_edit, amp;QTextEdit::cursorPositionChanged, this, amp;MyClass::text_edit_changed_cursor_location);
}

MyClass::~MyClass()
{
    delete text_edit;
}

void MyClass::text_edit_changed_cursor_location()
{
    QString text_edit_string = text_edit->text();
    QTextCursor text_edit_cursor = text_edit->textCursor();
    auto current_position = text_edit_cursor.position();
    QTextCursor new_text_cursor;
    int distance_to_beginning = distance_to_word_beginning_or_end(text_edit_string, current_position, true);
    int distance_to_end = distance_to_word_beginning_or_end(text_edit_string, current_position, false);
    auto movement_type;
    if (distance_to_beginning > distance_to_end)
    {
        new_text_cursor.setPosition(current_position   distance_to_end);
    } else {
        new_text_cursor.setPosition(current_position - distance_to_beginning);
    }
    text_edit->setTextCursor(new_text_cursor);
}
 

Комментарии:

1. Было бы неплохо привести пример кода предлагаемого вами решения.

2. Ладно, я сделал это ради того, что, как я знал, сработало. Я его не компилировал, так что, если вы найдете в нем ошибки, не стесняйтесь их исправлять. Должно быть несколько понятно, что делает каждая часть

3. Где вы рассматриваете два символа как один?

4. @Catcow, спасибо за ваш подробный комментарий. Я немного расширил вопрос, чтобы стало ясно, что я действительно использую QTextLayout для специализированного виджета github.com/edbee/edbee-lib

5. Эй, извини, что это заняло некоторое время, и у меня не так много времени, чтобы разобраться во всем, но зацени это doc.qt.io/qt-5/qtextlayout.html#isValidCursorPosition это кажется очень похожим на то, что вы пытаетесь сделать здесь. Я буду продолжать искать ответы до тех пор, пока у меня будет время этим вечером