我已經做了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("\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接口和一些狀態變量,就像我一樣。
很好的回覆!在擺脫回車時有效使用replace()。這是一個常見問題嗎? 在進一步深入研究之前,fixedPosition是應該打印東西的位置(不能由用戶直接控制),並且promptPosition用戶可以更改的位置? – user3050215
@ user3050215:1)我在Linux中開發時,在移植到Windows時,(微型)問題已通過簡單的#ifdef修復。 2)fixedPosition保留最後一個用戶可編輯的位置 - 即輸出後放置插入符號的位置,稍後引入promptPosition,以允許從異步過程輸出而不干擾模式對話框。淨效應很難用語言來解釋,在發佈任何從後臺引擎生成輸出的命令時很明顯 - 例如[consult](http://www.swi-prolog.org/pldoc/doc_for?object=consult/1) ... – CapelliC