How to disable a button after clicking it?
-
Use a single shot timer to delay the calculation and thus allow the UI to update.
(Untested code)
@
void GUI:onCalculate()
{
ui->calculateButton->setEnabled(false);
QTimer::singleShot(0, this, SLOT(doCalculate()));
}void GUI::doCalculate()
{
// do calculations which take some time
ui->calculateButton->setEnabled(true);
}
@ -
Same result.
I've uploaded the whole project if someone's interested in this challenge ;)"Project Euler Nr. 5":http://www.mediafire.com/?r6rkv94rxbnxavt
I know it's not that important, but I wanted to make it "uncrashable" and 100% bug-free.
-
Have you tried to perform the calculations in separate thread and to notify the GUI when they are ready?
-
I think the problem is another one. The mouse click event that triggeres the first clicked event is currently processed, so the main eventloop is blocked. inside this blocked state, you disable the button (which is no real window, just a widget). The second click event is emitted by mouse to the OS and the OS sends the event to the message loop of the Qt application. It will be send to the widget, when the event loop is entered again, which happens after GUI::onCalculate() is left.
So during processing of the event, the widget is not disabled...
long calculations should not be done inside the GUI thread so the UI is not blocked. Then this would also not happen, you could trigger some thread, threadpool, QFuture, whatever, disable the button and return. Then the mouse click during the thread is running, will not be processed by the button.
-
Okay, looks like there's no way around threads for this. Thanks for the advises and explanation.
I'll try it out and report back if I succeed.PS: I forgot to mention that the calculations aren't performed within the GUI class/(thread?).
The whole method looks like this:@
void GUI::onCalculate()
{
ui->pbCalculate->setEnabled(false);
ui->lwOutput->clear();
ui->pbCalculate->repaint();
ui->lwOutput->repaint();Euler euler; int j, k, n; n=ui->sbInput->text().toInt(); for(k=1; k<=n; k++) { j=euler.calculate(k); ui->lwOutput->addItem(QString::number(k) + ": " + QString::number(j)); ui->lwOutput->doItemsLayout(); ui->lwOutput->repaint(); } ui->pbCalculate->setEnabled(true);
}
@ -
This piece of code did the trick for me:
@
GUI::GUI(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::GUI)
{
ui->setupUi(this);
euler = new Euler();connect(ui->pbCalculate, SIGNAL(clicked()), this, SLOT(onCalculate())); connect(ui->actionExit, SIGNAL(triggered()), qApp, SLOT(quit())); connect(euler, SIGNAL(finished()), this, SLOT(calculationsDone()));
}
void GUI::onCalculate()
{
ui->pbCalculate->setEnabled(false);
ui->pbCalculate->repaint();
ui->lwOutput->clear();
ui->lwOutput->repaint();int n; n=ui->sbInput->text().toInt(); euler->setN(n); euler->start(QThread::IdlePriority);
}
void GUI::calculationsDone()
{
int i;
QList<int> results = euler->getResults();for(i=0; i<results.size(); i++) { ui->lwOutput->addItem("Number " + QString::number(results[i]) + " is the smallest number which can be divided evenly by all numbers from 1 to " + QString::number(i+1)); } ui->lwOutput->doItemsLayout(); ui->lwOutput->repaint(); ui->pbCalculate->setEnabled(true); ui->pbCalculate->repaint();
}
@ -
Actually, this worked perfectly for me:
@void wave::on_pushButton_clicked() //Starts program
{
thread->start();
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
}void wave::on_pushButton_2_clicked() //Terminates program
{
thread->terminate();
ui->pushButton_2->setEnabled(false);
ui->pushButton->setEnabled(true);}@
-
See http://developer.qt.nokia.com/wiki/Threads_Events_QObjects , especially the last examples. If your job is not splittable and/or you can't insert calls to QCoreApplication::processEvents, use a separate thread.