2014-01-07 105 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