QTextEdit和光标交互

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

  • Qt在传入的字符串中对回车(' r')做了一个奇怪的解释。 偶尔,3-7发送后,它将(' r')解释为新行(' n'),最令人讨厌。 当我最终发现我选择从传入数据中过滤出所有' r'时。 这是由于一些设置的行为?

  • 让光标交互正常工作有点问题。 我希望控制台通过复选框进行自动滚动选择。 我还希望可以在控制台运行时选择文本,而不会在新数据来临时丢失选择内容。

  • 这是我目前的打印功能,即一旦有任何数据到达,就会连接到发出的信号的插槽:

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


    我已经为SWI-Prolog,pqConsole做了一个基于QTextEdit的终端,其中包含一些功能,如ANSI着色序列(子集)解码,命令历史管理,多个插入点,完成,提示...

    它在提供模式REPL(读/评估/打印/循环)时运行非阻塞用户界面,这是解释型语言最常用的界面,如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("rn", "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接口和一些状态变量,就像我一样。


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

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

    要自动滚动编辑,可以使用QTextEdit::moveCursor()将光标移动到最后,并调用QTextEdit::ensureCursorVisible()

    链接地址: http://www.djcxy.com/p/49677.html

    上一篇: QTextEdit and cursor interaction

    下一篇: QT painting rich text on QGraphicsScene