2014-01-07 59 views
1

我正在修改Qt 5终端示例并使用QTextEdit窗口作为终端控制台。我遇到了几个问题。QTextEdit和光标交互

  1. 的Qt做的传入字符串回车( '\ r')一个奇怪的解释。偶尔,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(); 
} 

我有问题,如果用户在点击周围控制台,光标会改变位置,并且下面的传入数据最终会出现在错误的位置。问题:

  • 如果某个部分由用户标记,则新数据即将到来时标记会丢失。

  • 当像这样“强制”指针时,它会得到一个相当丑陋的自动滚动行为,这是无法禁用的。

  • 如果光标之间的程序的另一部分更改为打印输出,我也必须以某种方式记录。

    • 这听起来像是一个更合乎逻辑的解决方案的附加功能,做工精细,用于附加整个完整的字符串,但打印只是一个输入字符串的部分时,把人物和新的生产线处处显示一个不稳定的行为。

    • 我还没有找到关于此的一个设置,但应该有一个?将QTextEdit设置为“readOnly”不会禁用游标交互。

3.An想法是有在控制台两个光标。一种用于打印输出的不可见,并且根本不可能为用户操作,另一种是可见的,使用户可以选择文本。但如何做到这一点我:)任何相关的例子,常见问题或指导非常感谢。

回答

0

通常,使用QTextEdit作为一个功能丰富的终端小部件似乎是一个坏主意。您需要正确处理转义序列,例如光标移动和颜色模式设置,以某种方式将编辑粘贴到当前终端“页面”的左上角等。更好的解决方案可以是继承QScrollArea并实现所有需要的绘画选择滚动功能。

作为您的一些问题的临时解决办法,我可以建议使用ui->textEdit_console->append(toPrint)而不是insertPlainText(toPrint)

要自动滚动编辑,您可以将光标移动到末尾QTextEdit::moveCursor()并致电QTextEdit::ensureCursorVisible()

3

我已经做了SWI-的Prolog,pqConsole一个QTextEdit基于终端,具有一定的功能,如ANSI着色序列(子集)解码,命令历史管理,多个插入点,完井,暗示...

它在提供模式REPL(读/评估/打印/循环)时运行非阻塞用户界面,这是解释型语言最常用的界面,如Prolog。

该代码由线程问题(用户请求,可能有多个控制台,或多个线程在主要交互),但它的核心是相当简单的复杂。我只是跟踪插入点,并允许光标四处移动,禁止在输出区域进行编辑。

pqConsole它是一个共享对象(我喜欢这种类型的代码重用),但对于部署,独立程序swipl-win更方便。

这里一些选定的片段,用于控制输出状态变量是promptPositionfixedPosition

/** 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

很好的回复!在摆脱回车时有效使用replace()。这是一个常见问题吗? 在进一步深入研究之前,fixedPosition是应该打印东西的位置(不能由用户直接控制),并且promptPosition用户可以更改的位置? – user3050215

+0

@ user3050215:1)我在Linux中开发时,在移植到Windows时,(微型)问题已通过简单的#ifdef修复。 2)fixedPosition保留最后一个用户可编辑的位置 - 即输出后放置插入符号的位置,稍后引入promptPosition,以允许从异步过程输出而不干扰模式对话框。净效应很难用语言来解释,在发布任何从后台引擎生成输出的命令时很明显 - 例如[consult](http://www.swi-prolog.org/pldoc/doc_for?object=consult/1) ... – CapelliC