Ncurses and Qt Interoperability

前端 未结 2 544
后悔当初
后悔当初 2020-11-28 15:45

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).

相关标签:
2条回答
  • 2020-11-28 16:10
    1. Use QSocketNotifier to be notified of things being available on stdin.

    2. 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.

    3. You should also read all of the data that became available in the time before the socket notifier became attached.

    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.

    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\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"
    
    0 讨论(0)
  • 2020-11-28 16:11

    I found the answer to signal-slot mechanism not working inside while loop, is QCoreApplication::processEvents(); So, to receive the signals:

    while(1)
    {
        sleep(1);
        getch();
        processInput();
        QCoreApplication::processEvents();
    }
    
    0 讨论(0)
提交回复
热议问题