【问题标题】:How to stop a QTimer?如何停止 QTimer?
【发布时间】:2020-11-09 06:32:30
【问题描述】:

所以我在下面有一个简单的类,它使用 QTimer 每 1 秒向总数添加一个数字:


// score.h

#include <QObject>
#include <QTimer>

class Score : public QObject
{
    Q_OBJECT
public:
    explicit Score(QObject *parent = nullptr);
    void start();
    void stop();
    QTimer *timer;
    int getScore();

private slots:
    void update();

private:
    int score;

};

// score.cpp

#include "score.h"

Score::Score(QObject *parent) : QObject(parent)
{
    score = 0;
    timer = new QTimer(this);
}

void Score::start()
{
    timer->start(1000);
}

void Score::stop()
{
    timer->stop();
}

int Score::getScore()
{
    return score;
}

void Score::update()
{
    score += 10;
    qDebug() << score;
}

// main.cpp

#include <QCoreApplication>
#include "score.h"
#include <QtDebug>
#include <iostream>

int main(int argc, char *argv[])

{
    QCoreApplication a(argc, argv);

    Score score{};
    std::string input{""};

    while(input!="1") {
        std::cout << "1. to stop" << std::endl;
        std::cout << "2. to start" << std::endl;
        std::cin >> input;

        if(input=="1") {
            score.stop();
        }
        else if(input=="2") {
            score.start();
        }
    }
    return a.exec();
}

在循环过程中,如果我按下如果我的输入是 2,则什么也没有发生。该插槽似乎没有触发,因为我没有看到任何输出到控制台的内容。一般来说,我对 QT 很陌生,所以我可能做错了什么。另一个想法是我认为这可能是由于一些线程问题。但是我之前没有太多线程方面的经验。

【问题讨论】:

  • 在您启动 a.exec() 之前计时器无法触发。它包含管理计时器的事件循环(除其他外)。您必须了解如何通过QCoreApplication 事件处理控制台输入。如果我选择 Qt,我这样做是为了开发 GUI 应用程序(其中输入只是对小部件事件的反应)。如果我想做控制台应用程序,我不会选择 Qt。仅供参考:I/O in concurrent program(使用多线程,您可以同时处理用户输入和计时器,尽管您仍然必须使用非标准非阻塞输入。)

标签: c++ qt


【解决方案1】:

您的实现有 2 个关键错误:

  • eventloop 永远不会启动,因为 while 循环不允许它,如果 eventloop 没有启动,那么 QTimer、信号等异步元素将不起作用。

  • 即便如此,事件循环也将起作用。您尚未在超时信号与更新数据槽之间建立连接。

考虑到上述情况,您必须在不使用循环的情况下实现标准输入的读取,并且读取的实现将取决于操作系统,因此为了简化解决方案,我们可以使用通过信号实现标准输入读取的QConsole library

├── 3rdParty
│   └── QConsole
│       ├── Demo
│       │   ├── Demo.pro
│       │   └── main.cpp
│       ├── LICENSE
│       ├── qconsole.cpp
│       ├── qconsole.h
│       ├── qconsole.pri
│       ├── README.md
│       ├── readthread_win.cpp
│       └── readthread_win.h
├── 64746801.pro
├── main.cpp
├── score.cpp
└── score.h

*.pro

QT -= gui

CONFIG += c++11 console
CONFIG -= app_bundle

SOURCES += \
        main.cpp \
        score.cpp

HEADERS += \
    score.h

include(3rdParty/QConsole/qconsole.pri)

ma​​in.cpp

#include <QCoreApplication>
#include <QFile>
#include <QDebug>

#include <qconsole.h>

#include "score.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Score score;

    QConsole console;
    QObject::connect(&console, &QConsole::readyRead, [&](){
        auto data = console.read(console.bytesAvailable());
        if(data == QStringLiteral("1\n")){
            score.stop();
        }
        else if(data == QStringLiteral("2\n")){
            score.start();
        }
    });
    if(!console.open()) {
        qCritical() << console.errorString();
        return EXIT_FAILURE;
    }
    return a.exec();
}

score.h

#ifndef SCORE_H
#define SCORE_H

#include <QObject>

class QTimer;

class Score : public QObject
{
    Q_OBJECT
public:
    explicit Score(QObject *parent = nullptr);
    void start();
    void stop();
    int getScore();

private slots:
    void update();

private:
    int score;
    QTimer *timer;
};

#endif // SCORE_H

score.cpp

#include "score.h"

#include <QTimer>
#include <QDebug>

Score::Score(QObject *parent) : QObject(parent)
{
    score = 0;
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Score::update);
}

void Score::start()
{
    timer->start(1000);
}

void Score::stop()
{
    timer->stop();
}

int Score::getScore()
{
    return score;
}

void Score::update()
{
    score += 10;
    qDebug() << score;
}

完整的例子是here

【讨论】:

  • 我从未见过 Qt 控制台应用程序,也从未打算编写一个。所以,我真的很喜欢这个带有示例的答案,看看它的样子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
相关资源
最近更新 更多