Ncurses和Qt的互操作性

7
拥有一个基于Qt和ncurses的应用程序,如何在等待用户输入的同时每秒刷新屏幕呢?(例如显示时钟并获取用户输入)
我需要在CPU使用率和应用程序响应性之间取得最佳平衡。
更具体地说,如何获取用户输入并仍然使用QTimer和信号槽机制?
当使用下面的代码时,定时器不起作用。
nodelay(stdscr,true); while(1) { sleep(1); getch(); processInput(); }

3
QT和ncurses?同时使用两个非常不同的用户界面? - Kos
1
Qt 有计时器。 - Some programmer dude
6
@Kos Qt不仅仅是你所熟悉的GUI部分? :) - Some programmer dude
有趣的组合 :-) 你是想在Qt中包装一个现有的ncurses应用程序,还是基于这两个工具包编写一个新的应用程序?在第二种情况下,我建议您检查一下是否可以仅使用Qt完成所有操作。 - Valentin H
@JoachimPileborg 我使用QT进行核心和Sql开发,并使用QTimer来刷新时钟。 - Marian
2个回答

8
  1. 使用QSocketNotifier来通知stdin有可用数据。

  2. 在循环中调用非阻塞的getch(),直到没有更多输入为止。这非常重要:通知器只在有新数据可用时通知,但这并不意味着它会在每个字符上通知!如果一次接收多个字符,通常只会收到一个通知 - 因此必须继续发出非阻塞的getch(),直到它返回ERR表示当前没有更多数据可用。

  3. 还应该读取在套接字通知器附加之前已经可用的所有数据。

以下代码在接收到输入时将其回显,并每秒输出一个*。这适用于Linux和OS X,但无法在Windows上运行。要退出,请按Q键。

在需要的情况下使用ncurses进行传统文本模式用户界面,并利用Qt进行其他方面(定时、网络、基于文本的视图的数据模型、XML、QObjects等)的开发是完全有效的方法。

// 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\n");
   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"

-1
我找到了解决while循环内信号槽机制不工作的方法,那就是使用QCoreApplication::processEvents()函数。因此,要接收信号:
while(1)
{
    sleep(1);
    getch();
    processInput();
    QCoreApplication::processEvents();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接