如何在Qt控制台应用程序中处理按键事件?

11
例如,当你按下“Esc”键时,应用程序会结束。
3个回答

9

这里是Linux的解决方法。使用以下文章:

从标准输入中捕获字符,而无需等待按下回车键 https://dev59.com/MnRC5IYBdhLWcg3wD83r#912796

我已经按照以下方式制作:

ConsoleReader.h

#ifndef CONSOLEREADER_H
#define CONSOLEREADER_H

#include <QThread>

class ConsoleReader : public QThread
{
    Q_OBJECT
signals:
    void KeyPressed(char ch);
public:
   ConsoleReader();
   ~ConsoleReader();
   void run();
};

#endif  /* CONSOLEREADER_H */

ConsoleReader.cpp

#include "ConsoleReader.h"
#include <stdio.h>
#include <unistd.h>
#include <termios.h>

static struct termios oldSettings;
static struct termios newSettings;

/* Initialize new terminal i/o settings */
void initTermios(int echo) 
{
  tcgetattr(0, &oldSettings); /* grab old terminal i/o settings */
  newSettings = oldSettings; /* make new settings same as old settings */
  newSettings.c_lflag &= ~ICANON; /* disable buffered i/o */
  newSettings.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
  tcsetattr(0, TCSANOW, &newSettings); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void) 
{
  tcsetattr(0, TCSANOW, &oldSettings);
}

/* Read 1 character without echo */
char getch(void) 
{
  return getchar();
}

ConsoleReader::ConsoleReader()
{
  initTermios(0);
}

ConsoleReader::~ConsoleReader()
{
  resetTermios();
}

void ConsoleReader::run()
{
    forever
    {
        char key = getch();        
        emit KeyPressed(key);
    }
}

然后开启新的线程来读取键:

ConsoleReader *consoleReader = new ConsoleReader();
connect (consoleReader, SIGNAL (KeyPressed(char)), this, SLOT(OnConsoleKeyPressed(char)));
consoleReader->start();

*已更新(添加了退出时恢复终端设置)


consoleReader->start(); -- 你是指 run() 吗? - Anon
我在我的项目中使用了这个,它运行得非常好。请注意,键码取决于您使用的终端类型。如果您通过SSH连接而不是使用终端会话,则可能会发生变化。 - Thomas H. Schmidt

7
如果你只需要“退出”,也许以下代码片段可以帮助你(需要c++11和qt5):
#include <iostream>
#include <future>

#include <QCoreApplication>
#include <QTimer>

int main(int argc, char *argv[])
{
    QCoreApplication application(argc, argv);
    bool exitFlag = false;

    auto f = std::async(std::launch::async, [&exitFlag]{
        std::getchar();
        exitFlag = true;
    });

    QTimer exitTimer;
    exitTimer.setInterval(500);
    exitTimer.setSingleShot(false);

    QObject::connect(&exitTimer,
                     &QTimer::timeout,
                     [&application,&exitFlag] {
        if (exitFlag)
            application.quit();
    });

    exitTimer.start();

    std::cout << "Started! Press Enter to quit...";
    int ret =  application.exec();
    std::cout.flush();
    f.wait();
    return ret;
}

运行正常!你能解释一下为什么在 exec() 后需要 f.wait() 吗? - spartawhy117
这是显式同步点,async()线程可以安全地加入其中。'f'对象std::future析构函数可能不会显式阻塞,直到线程加入(需要探讨)。 - vrogach
1
int ret = application.exec(); 行之前,必须添加 std::cout.flush(); - B0FEE664

5

Qt无法处理控制台事件,它只能从控制台读取以\n结尾的行。

您需要使用本地API或其他库(如curses)。


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