如何使用QTimer重复特定操作

时间:2016-10-06 20:37:32

标签: qt qtimer qnetworkrequest

我在理解如何使用QTimer时遇到问题,因此我重复特定操作点击按钮网络请求)。

关注此answerquestion后,我无法弄清楚如何将定时器的QTimer::Timeout信号连接到MainWIndow::request信号就像我当前连接的按钮一样。问题是我无法重复;它编译并运行没有错误,但没有重复。

(就像发布问题的人一样,如果我将所有代码都放在main.cpp中,我也可以重复计时器,但我想知道在这种情况下如何完成它。)< / p>

以下是从该示例中获取的简化代码,以指出我的尝试:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QKeyEvent>
#include <QApplication>
#include <QtWidgets>
#include <QTimer>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // GUI setup here //

    networkManager = new QNetworkAccessManager;

    connect(networkManager, &QNetworkAccessManager::finished, this, &MainWindow::on_NetworkManagerFinished);
    connect(ui->getButton, &QPushButton::clicked, this, &MainWindow::on_getButton_clicked);

    // Connect the timer to repeat the GET request
    QTimer timer;

    // [1st attempt]
    connect(&timer, SIGNAL(&QTimer::timeout), this, SLOT(&MainWindow::on_TimerTimeout));

    // [2nd attempt]
    connect(&timer, SIGNAL(timeout()), this, SLOT(timer_buttonClicked()));

    timer.start(1500); // 1.5 secs
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_NetworkManagerFinished(QNetworkReply *reply)
{
        // Parse and display JSON here //
}

// Make GET request when button is clicked
void MainWindow::on_getButton_clicked() //on_TimerTimeout()
{
    // Make GET request    
    QUrlQuery query;

    QUrl url("http://blah/blahblah");
    query.addQueryItem("blah", "blah");
    url.setQuery(query);
    QNetworkRequest networkRequest(url);

    networkManager->get(networkRequest);

    ui->getButton->setEnabled(false);

    // Restart timer
    timer->start(1500); // 1.5 secs

    // Do stuff in the GUI here //
}

更新

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_NetworkManagerFinished(QNetworkReply* reply);
    void on_getButton_clicked();

private:
    Ui::MainWindow *ui;
    QNetworkAccessManager *networkManager;
};

#endif // MAINWINDOW_H

正如在评论部分中可以看到的那样,我还尝试在mainwindow.h中使用onTimeout替换按钮的私有插槽,并在连接之前在mainwindow.cpp中创建了一个QTimer对象启动它,然后我使用该对象来定义connect(&timer,&QTimer::timeout,this,&MainWindow::onTimeout)‌​;。另外,我用onTimeout相关代码替换了最后的按钮插槽定义。

如果您可以解释我缺少的内容,或者甚至提供我看到here的确切示例的代码,这对我来说很有用。

3 个答案:

答案 0 :(得分:3)

下面的代码片段根据您提供的代码说明了正确的方法

#include <QTimer>    

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {

// setup your GUI

// declare a pointer variable for pointing to a QTimer object
QTimer *timer = new QTimer;

// make the connection using the timer variable
connect(timer, &QTimer::timeout, this, &MainWindow::on_getButton_clicked);

// start the timer object by first dereferencing that object first
timer->start(1500);

// do other stuff //

}

您应该对指针进行进一步阅读,并使用点(。)运算符进行differences

注意

使用计时器作为班级成员时,

ddriver的答案会更好;这避免了我的方法中指针引用的局部性。

答案 1 :(得分:2)

如果您的代码甚至编译,则意味着您的班级中很可能有=IF(F2=1,"Resistant to 1",IF(F2=0,"Resistant to 0","Resistant to More than 1"))成员。您可以从以下几行中推断出这一点:

QTimer *timer

如果您没有,请将其添加到课程中:

// Restart timer
timer->start(1500); // 1.5 secs

但是,在类构造函数中,您正在创建名为class MainWindow { Q_OBJECT ... private: QTimer *timer; // add this }; 另一个变量,并将数据成员隐藏起来:

timer

你绝对不想在那里引入新的变量。更重要的是,这个变量有自动存储,这意味着它将在其封闭范围的末尾被破坏(这是构造函数本身:所以当你从构造函数返回时,{{1对象消失了。)

解决方案:只是不要声明一个全新的变量,使用现有的数据成员。将构造函数更改为:

// Connect the timer to repeat the GET request
QTimer timer;

关于实际的timer语句。

这个是错的:

// not introducing any new variable here!
timer = new QTimer(this);
connect(timer, ...);

它将编译,但在运行时发出警告。摆脱它。 (为什么你最后输入这个?如果你正在使用Qt Creator你会有SIGNAL和SLOT宏的自动完成......)

这一个:

connect

具有正确的语法,但我不知道它是否真的有用,你有connect(&timer, SIGNAL(&timeout()), this, SLOT(&MainWindow::on_TimerTimeout)); 成员函数标记为插槽吗?另一个connect(&timer, SIGNAL(timeout()), this, SLOT(timer_buttonClicked())); 使用另一个函数。

如果您使用的是Qt 5,请尽快转到:

void timer_buttonClicked()
如果出现问题,

在编译时失败。

答案 2 :(得分:2)

我说最简单的解决方案就是让计时器成为一个类成员,实际上不需要使用堆分配:

class YourClass : public QObject {
  Q_OBJECT
  QTimer timer;
  public:
  YourClass() {
    connect(&timer, SIGNAL(timeout()), this, SLOT(timer_yourSlot()));
    // or the new and safer syntax in Qt 5
    // connect(&timer, &QTimer::timeout, this, &YourClass::yourSlot);
    timer.start(1500);
  }
  public slots:
  void yourSlot() { ... }
};

除非您知道所需内容,否则建议避免堆分配。在这种情况下,你不需要它。避免它的原因很多 - 它更慢,它将使用更多的内存,它可能会失败(如果你的内存不足),它将需要额外的管理 - 自动或手动,并且它更容易出错。将计时器作为类成员将自动将其与类实例的生命周期联系起来,这样就可以避免所有不必要的开销。

Peppe的回答假设你有一个QTimer * timer;班级成员,你不会,这是额外混乱的根源。

  

如果我QTimer timer; timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWindow::on_getButton_clicked);我得到了   &#39; C2679没有找到哪个操作符采用类型的右操作数   QTimer&#39;

此处的问题是,计时器的类型为QTimer,而new QTimer会将指针返回给QTimer,而不是QTimer。非常不同的事情。然后connect()需要一个对象指针,但在你的情况下timer是一个对象实例,而不是一个对象指针。使用&运算符,您可以在内存中获取计时器地址,或者换句话说,指向它的指针。

  

如果我timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWindow::on_getButton_clicked);我得到&#39;计时器未声明   标识符&#39;

正如它所说,计时器是未声明的,编译器不知道timer是什么,因为你没有用适当的类型声明它。现在,如果执行QTimer * timer,编译器就知道timer是指向计时器的类型指针。