2016-10-06 46 views
2

,這樣我就重複一個具體的行動點擊一個按鈕網絡請求的)。如何使用QTimer重複我有了解如何使用<code>QTimer</code>問題的具體行動

answer從這個漂亮的question,我無法弄清楚如何定時器的QTimer::Timeout信號連接到MainWIndow::request信號以同樣的方式,因爲我有當前連接的按鈕。問題是我無法重複它;它編譯和運行沒有錯誤,但沒有重複。

(喜歡誰張貼問題的人,我也可以有定時器重複,如果我把我所有的代碼在main.cpp,但我想看看究竟是如何能在這種情況下完成的。)

下面是從例如採取了簡化代碼,以我的嘗試:

#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之前用connect創建了一個QTimer對象並啓動它,之後我使用該對象定義connect(&timer,&QTimer::timeout,this,&MainWindow::onTimeout)‌​;。另外,我用onTimeout相關代碼替換了最後的按鈕槽定義。

如果你能解釋我缺少的東西,或者甚至提供精確範例的代碼,如here這對我來說很好理解。

+1

您在構造函數中創建了一個本地計時器,這意味着計時器在構造函數返回後被銷燬。動態分配它'QTimer * timer = new QTimer'或更好 - 使定時器成爲類成員。 – dtech

+0

我非常懷疑你希望定時器點擊按鈕或任何類型的東西。您希望計時器調用連接到按鈕單擊的任何操作。這是完全不同的。 –

回答

2

下面的代碼片段說明根據您提供代碼正確的做法

#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

ddriver的方法更適合作爲**班級成員**使用計時器,但是根據你的等級(沒有進攻),也許你有點提前。如果你能弄清楚爲什麼類成員方法是最優的,那將是很好的;後續作業:) – Yannis

+0

這就是我想要的,非常感謝您爲我寫清楚,即使ddriver在他的評論中提出了這個建議。我現在試着找出類成員的方法,謝謝 –

+0

重要的是要注意,這段代碼會導致你在構造函數返回後失去計時器。這意味着你將無法阻止它,或以任何方式改變它。對計時器的唯一引用是它的指針,它是一個本地構造函數,這就是爲什麼將指針或計時器本身作爲類成員是一個好主意。 – dtech

2

如果您的代碼編譯完成,這意味着您的班級中有一位QTimer *timer成員的可能性非常大。您可以從這些行推斷此:

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

如果你不用它,然後將其添加到類:

class MainWindow { 
    Q_OBJECT 
... 
private: 
    QTimer *timer; // add this 
}; 

然而,在類的構造函數,你正在創建另一變量稱爲timer,陰影數據成員:

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

你肯定不希望在那裏引入新的變量。更重要的是,這個變量有自動存儲,這意味着它將在其封閉範圍(這是構造函數本身:所以當你從構造函數返回時,該對象不在)結束時被銷燬。

解決方案:只是不聲明一個全新的變量,使用現有的數據成員。構造函數更改爲類似:

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

關於實際connect語句。

這一個是錯誤的:

connect(&timer, SIGNAL(&timeout()), this, SLOT(&MainWindow::on_TimerTimeout)); 

這將編譯,但在運行時發出警告。擺脫它。 (你怎麼會弄成甚至打字這一個,如果你使用Qt Creator中,你將有信號和SLOT宏自動完成......?)

這一個:

connect(&timer, SIGNAL(timeout()), this, SLOT(timer_buttonClicked())); 

有一個正確的語法,但我不知道它是否會真正起作用,您是否將void timer_buttonClicked()成員函數標記爲插槽?另一個connect使用另一個功能。

如果你正在使用Qt 5,儘快移動到:

connect(timer, &QTimer::timeout, this, &MainWindow::whatever); 

其在編譯時失敗,如果事情是錯誤的。

+0

我嘗試了你的建議,但我得到錯誤; **如果我做**'QTimer定時器; timer = new QTimer(this); connect(timer,&QTimer :: timeout,this,&MainWindow :: on_getButton_clicked);''我得到'C2679沒有找到操作符的類型爲QTimer的操作數'。 **如果我做**'timer = new QTimer(this);連接(定時器,&QTimer :: timeout,this,&MainWindow :: on_getButton_clicked);'我得到'定時器未聲明的標識符'。 *我更新了我的描述以顯示我的插槽* – Karim

+0

@Karim - 在嘗試在實踐中使用它之前,瞭解該語言總是一個好主意。 – dtech

+0

@ddriver我明白我可能會問一些愚蠢的問題,但在這裏,我正在問,閱讀並尋求指導,以便像你所說的那樣「學習語言」。對不起,如果這讓你煩惱。 – Karim

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);我得到 「C2679沒有操作員發現這需要 類型的右手操作數QTimer」

這裏的問題是,計時器QTimer類型,而new QTimer返回指針QTimer,而不是QTimer。非常不同的事情。然後connect()期望一個對象指針,但在你的情況下,timer是一個對象實例,而不是一個對象指針。使用&運算符,您可以獲取內存中的計時器地址,或換言之,指向它的指針。

如果我做timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWindow::on_getButton_clicked);我得到「計時器未申報 標識符」

,因爲它說,計時器未申報,編譯器不知道timer是什麼,因爲你還沒有一個適當的宣佈它類型。現在如果你做QTimer * timer編譯器知道timer是指向一個定時器的類型指針。

+1

很棒的回答。如果你有時間添加一個小的解釋,提到爲什麼你的類成員方法更好,那麼新手得到更完整的答案,而不僅僅是工作代碼是很好的。 +1 – Yannis