Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use QTimer to print a message to a QTextBrowser every 10 seconds?

I have working at this for hours and cannot figure it out nor can I find any help online that works. Basically the gist of what I am trying to accomplish is to have a Qt GUI with a button and a QTextBrowser. When I push the button I want it to display a message and then keep printing this message every 10 seconds.

I figured I would use QTimer because it makes sense to have a timer to display the message every 10 seconds. When I originally implemented this into my `buttonClicked() SLOT it caused the program to freeze. I looked online for a solution and found QApplication::processEvents().

So basically in my function I had something like this:

while(1)
{
   QTimer *timer;
   connect(...)  //omitted parameters for this example     
   timer.start(10000);
   ui->diplay->append("Message");

   while(timer.isActive())
   {
      QApplication::processEvents() 
   }
}

I figured it would break out of the timer.isActive() while loop but it won't it simply stays in there.

So I figured this is a threading issue. So I figured out how to use QThreads but I still can't get it to work. Basically when I create a thread with a timer on it and the thread tells the timer to start, the program closes and the console says "The program has unexpectedly finished".

There has to be an easy way to do this but my track record with Qt has always been that th

like image 861
Aaron McKellar Avatar asked Jan 14 '11 19:01

Aaron McKellar


4 Answers

If you want to display your message for 10s, the better way to do that, is to create a slot in your application that will erase the message. Then, in your button clicked slot, add your message and initialize a timer which will trigger your remove message slot in 10s:

QTimer::singleShot(10000, this, SLOT(eraseMessageSlot()));

Also, there is no need for a thread there...

like image 146
tibur Avatar answered Nov 11 '22 10:11

tibur


Your code has many problems - I assume it's pseudocode, essentially, since timer doesn't exist and things like that.

Check out the QTimer reference. It has an example:

 QTimer *timer = new QTimer(this);
 connect(timer, SIGNAL(timeout()), this, SLOT(update()));
 timer->start(1000);

Basically, you want to make a slot that appends, then connect it to the timeout signal and start the timer. The timer will tick along and every second will call the slot. In your case, you'd change 1000 to 10000

If this isn't working, what exactly is the problem you're having? I don't understand why you're using threads, unless you need them anyway.

EDIT Looking at your update, you say that you want to wait for 10 seconds. Instead of busy-waiting, why not continue the program in your slot (called by singleShot)? I think you're missing some of the Qt philosophy...

like image 25
Robert Avatar answered Nov 11 '22 11:11

Robert


It will be better to organize your program like this:

class MainWindow : QWidget //or any other parent class
{
public:
MainWindow()
{
    QPushButton *button = new QPushButton(this);
    browser_ = new QTextBrowser(this); //and some params maybe
    QVBoxLayout * layout = new QVBoxLayout(this); //can be used another layout
    layout->addWidget(button);
    layout->addWidget(browser_);

    connect(button, SIGNAL(pressed()),
        this, SLOT(onButtonPressed()));

    timer_ = new QTimer(this);
    connect(timer, SIGNAL(timeout()), 
        this, SLOT(timerHandler()));
    }
    ~MainWindow();

public slots:
    void onButtonPressed()
    {
        timerHandler(); //to display message when button is pressed
        if (!timer->isActive()) timer->start(TIMER_INTERVAL); //TIMER_INTERVAL = 10000;
    }
    void timerHandler()
    {
         //put your code to display message here
    }

private:
    QTextBrowser *browser_;
    QTimer *timer_;
}
like image 43
Andrew Avatar answered Nov 11 '22 11:11

Andrew


By default, QTimer will fire every interval until you stop it. That's why timer.isActive() is always true. Use timer.setSingleShot(true) to make the timer fire only once. (Or use QTimer::singleShot as in @tibur's post.)

like image 1
Daniel Gallagher Avatar answered Nov 11 '22 11:11

Daniel Gallagher