Ncurses 和 Qt 互操作性
有一个基于 Qt 和 ncurses 的应用程序,在等待用户输入时每秒刷新屏幕的最佳方法是什么?(例如,显示时钟并获取用户输入).
Having a Qt and ncurses based application, what is the best way to refresh the screen every second, while waiting for user input? (e.g. show the clock and get user input).
我需要在 CPU 使用率和应用程序响应能力之间取得最佳折衷.
I need the best compromise between CPU usage and application responsiveness.
更具体地说,如何获取用户输入并仍然使用 QTimer
和信号槽机制?
To be more specific with the question, how to get user input and still use QTimer
and the signal-slot mechanism?
使用下面的代码时,定时器不起作用.
When using the code below, the timers doen't work.
nodelay(stdscr,true); while(1) { sleep(1); getch(); processInput(); }
推荐答案
使用
QSocketNotifier
来通知stdin
上可用的东西.
Use
QSocketNotifier
to be notified of things being available onstdin
.
在循环中调用非阻塞 getch()
直到没有更多输入可用.这一点非常重要:只有当新数据可用时,通知程序才会通知,但这并不意味着它会通知每个字符!如果您一次收到多个字符,您通常只会收到一个通知 - 因此您必须继续发出非阻塞 getch()
直到它返回 ERR
意味着没有更多数据目前可用.
Call nonblocking getch()
in a loop until no more input is available. This is vitally important: the notifier will notify only when new data is available, but this doesn't mean that it notifies on every character! If you receive multiple characters at a time, you will usually get just one notification - thus you must keep issuing non-blocking getch()
until it returns ERR
meaning that no more data is available at the moment.
您还应该读取在连接套接字通知程序之前可用的所有数据.
You should also read all of the data that became available in the time before the socket notifier became attached.
下面的代码在接收到输入时回显,并且每秒额外输出一个 *
.这适用于 Linux 和 OS X,不能移植到 Windows.要退出,请按 Q.
The code below echoes the input as it receives it, and additionally outputs a *
every second. This works on Linux and OS X, and is not portable to Windows. To quit, press Q.
在需要时将 ncurses 用于传统文本模式用户界面,同时将 Qt 用于其他所有方面(计时、网络、具有基于文本的视图的数据模型、XML、QObjects 等)是一种完全有效的方法.
Using ncurses for a legacy text-mode user interface, where desired, while leveraging Qt for everything else (timing, networking, data models with text-based views, XML, QObjects, etc.) is a perfectly valid approach.
// https://github.com/KubaO/stackoverflown/tree/master/questions/ncurses-20606318
#include <QtCore>
#include <ncurses.h>
class Worker : public QObject
{
Q_OBJECT
QSocketNotifier m_notifier{0, QSocketNotifier::Read, this};
QBasicTimer m_timer;
Q_SLOT void readyRead() {
// It's OK to call this with no data available to be read.
int c;
while ((c = getch()) != ERR) {
printw("%c", (char)(c <= 255 ? c : '?'));
if (c == 'q' || c == 'Q') qApp->quit();
}
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timer.timerId()) return;
printw("*");
refresh();
}
public:
Worker(QObject * parent = 0) : QObject(parent) {
connect(&m_notifier, SIGNAL(activated(int)), SLOT(readyRead()));
readyRead(); // data might be already available without notification
m_timer.start(1000, this);
}
};
int main(int argc, char *argv[])
{
QCoreApplication a{argc, argv};
Worker w;
auto win = initscr();
clear();
cbreak(); // all input is available immediately
noecho(); // no echo
printw("Press <q> to quit
");
keypad(win, true); // special keys are interpreted and returned as single int from getch()
nodelay(win, true); // getch() is a non-blocking call
auto rc = a.exec();
endwin();
return rc;
}
#include "main.moc"
相关文章