2014-01-07 4 views
1

Я изменяю пример терминала Qt 5 и использую окно QTextEdit в качестве терминальной консоли. Я столкнулся с несколькими проблемами.QTextEdit и взаимодействие с курсором

  1. Qt делает странное толкование возврата каретки ('\ г') в входящих строк. Внезапно, после отправки 3-7, он интерпретирует ('\ r') как новую строку ('\ n'), наиболее раздражающую. Когда я наконец узнал, я решил отфильтровать все «\ r» из входящих данных. Возможно ли это из-за некоторых настроек?

  2. Правильное взаимодействие курсора - это немного проблематично. Я хочу, чтобы консоль имела возможность выбора автоскарта с помощью флажка. Я также хочу, чтобы можно было выбирать текст всякий раз, когда консоль запускается, не теряя при выборе новых данных.

Вот моя текущая функция prinout, то есть слот подключен к сигналу, как только какие-либо данные прибыл:

void MainWindow::printSerialString(QString& toPrint) 
{ 
    static int cursPos=0; 

    //Set the cursorpos to the position from last printout 
    QTextCursor c = ui->textEdit_console->textCursor(); 
    c.setPosition(cursPos); 
    ui->textEdit_console->setTextCursor(c); 

    ui->textEdit_console->insertPlainText(toPrint); 
    qDebug()<<"Cursor: " << ui->textEdit_console->textCursor().position(); 

    //Save the old cursorposition, so the user doesn't change it 
    cursPos= ui->textEdit_console->textCursor().position(); 

    toPrint.clear(); 
} 

У меня была проблема, что если пользователь нажал вокруг в консоль, курсор изменит положение, и следующие входящие данные окажутся в неправильном месте. Вопросы:

  • Если раздел отмечен пользователем, маркировка потеряется при поступлении новых данных.

  • Когда «форсировать» такой указатель, он получает довольно уродливое поведение автопрокрутки, которое невозможно отключить.

  • Если курсор изменен другой частью программы между распечатками, мне также необходимо записать это как-то.

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

    • Я не нашел ни одной установки относительно этого, но должен быть один? Установка QTextEdit на «readOnly» не отключает взаимодействие курсора.

3.An Идея заключается в том, чтобы иметь два курсора в консоли. Один невидимый, который используется для распечаток и который вообще не может манипулировать для пользователя, и один видимый, который позволяет пользователю выбирать текст. Но, как это сделать, меня бьют :) Любой связанный пример, FAQ или руководство очень оценены.

ответ

0

Как правило, использование QTextEdit для многофункционального виджета терминала кажется плохой идеей. Вам нужно будет правильно обрабатывать escape-последовательности, такие как перемещения курсора и настройки цветового режима, каким-то образом вставлять правки в верхний левый угол текущей «страницы» терминала и т. Д. Лучшим решением может быть наследование QScrollArea и реализация всех необходимых Функция рисования-выбора-прокрутки.

В качестве временного решения некоторых из ваших проблем я могу предложить использовать ui->textEdit_console->append(toPrint) вместо insertPlainText(toPrint).

Для автоматической прокрутки редактирования вы можете переместить курсор в конец с помощью QTextEdit::moveCursor() и позвонить по телефону QTextEdit::ensureCursorVisible().

3

Я сделал вывод, основанный QTextEdit для SWI-Prolog, pqConsole, с некоторыми особенностями, как ANSI красящих последовательностей (подмножество) декодирования, команды управления историей, множеством точек вставки, завершение, намекая ...

Он управляет неблокирующим пользовательским интерфейсом при обслуживании модального REPL (Read/Eval/Print/Loop), наиболее распространенного интерфейса для интерпретируемых языков, например Prolog.

Код сложный в проблемах с потоками (по запросу пользователя возможно иметь несколько консолей или несколько потоков, взаимодействующих на основном), но ядро ​​довольно простое. Я просто отслеживаю точки вставки и позволяю курсору перемещаться, отключая редактирование в области вывода.

pqConsole Это общий объект (мне нравится такое повторное использование кода), но для развертывания более удобна автономная программа swipl-win.

Вот некоторые выбранные фрагменты, переменные состояния, используемые для управления выводом является promptPosition и fixedPosition.

/** display different cursor where editing available 
*/ 
void ConsoleEdit::onCursorPositionChanged() { 
    QTextCursor c = textCursor(); 
    set_cursor_tip(c); 
    if (fixedPosition > c.position()) { 
     viewport()->setCursor(Qt::OpenHandCursor); 
     set_editable(false); 
     clickable_message_line(c, true); 
    } else { 
     set_editable(true); 
     viewport()->setCursor(Qt::IBeamCursor); 
    } 

    if (pmatched.size()) { 
     pmatched.format_both(c); 
     pmatched = ParenMatching::range(); 
    } 

    ParenMatching pm(c); 
    if (pm) 
     (pmatched = pm.positions).format_both(c, pmatched.bold()); 
} 

/** strict control on keyboard events required 
*/ 
void ConsoleEdit::keyPressEvent(QKeyEvent *event) { 

    using namespace Qt; 
... 
    bool accept = true, ret = false, down = true, editable = (cp >= fixedPosition); 

    QString cmd; 

    switch (k) { 

    case Key_Space: 
     if (!on_completion && ctrl && editable) { 
      compinit2(c); 
      return; 
     } 
     accept = editable; 
     break; 
    case Key_Tab: 
     if (ctrl) { 
      event->ignore(); // otherwise tab control get lost ! 
      return; 
     } 
     if (!on_completion && !ctrl && editable) { 
      compinit(c); 
      return; 
     } 
     break; 

    case Key_Backtab: 
     // otherwise tab control get lost ! 
     event->ignore(); 
     return; 

    case Key_Home: 
     if (!ctrl && cp > fixedPosition) { 
      c.setPosition(fixedPosition, (event->modifiers() & SHIFT) ? c.KeepAnchor : c.MoveAnchor); 
      setTextCursor(c); 
      return; 
     } 
    case Key_End: 
    case Key_Left: 
    case Key_Right: 
    case Key_PageUp: 
    case Key_PageDown: 
     break; 
} 

вы можете увидеть, что большинство сложность идет в управлении клавиатурой ...

/** \brief send text to output 
* 
* Decode ANSI terminal sequences, to output coloured text. 
* Colours encoding are (approx) derived from swipl console. 
*/ 
void ConsoleEdit::user_output(QString text) { 

#if defined(Q_OS_WIN) 
    text.replace("\r\n", "\n"); 
#endif 

    QTextCursor c = textCursor(); 
    if (status == wait_input) 
     c.setPosition(promptPosition); 
    else { 
     promptPosition = c.position(); // save for later 
     c.movePosition(QTextCursor::End); 
    } 

    auto instext = [&](QString text) { 
     c.insertText(text, output_text_fmt); 
     // Jan requested extension: put messages *above* the prompt location 
     if (status == wait_input) { 
      int ltext = text.length(); 
      promptPosition += ltext; 
      fixedPosition += ltext; 
      ensureCursorVisible(); 
     } 
    }; 

// filter and apply (some) ANSI sequence 
int pos = text.indexOf('\x1B'); 
if (pos >= 0) { 
    int left = 0; 
... 

     instext(text.mid(pos)); 
    } 
    else 
     instext(text); 

    linkto_message_source(); 
} 

Я думаю, что вы не должны использовать статическую переменную (например, что появляется в вашем коде), но вместо этого полагаются на QTextCursor интерфейс и некоторую переменную статуса, как и я.

+0

Хороший ответ! Эффективное использование замены() при избавлении от возврата каретки. Это распространенная проблема? Перед тем, как копать больше в нем, фиксируется позиция, в которой материал должен быть напечатан (не контролируется пользователем напрямую) и promptPosition позицию, которую пользователь может изменить? – user3050215

+0

@ user3050215: 1) Я разработал в Linux при переносе в Windows эту (мини) проблему исправили с помощью этого простого #ifdef. 2) fixedPosition сохраняет последнее редактируемое положение пользователя - то есть, когда каретка была помещена после вывода, позже была введена подсказка, чтобы позволить выход из процесса асинхронизации без вмешательства в модальное диалоговое окно. Чистый эффект трудно объяснить словами, очевидно, что при выдаче любой команды, которая производит вывод из фонового движка - например [consult] (http://www.swi-prolog.org/pldoc/doc_for?object=consult/1) ... – CapelliC

Смежные вопросы