I have situation that I open QDialog window from the main.cpp file and then I wait for the exec() method to return based on success or fail of the QDialog. Like this :
int main( ... ) {
LoginDialog *loginDlg = new LoginDlg;
if( loginDlg->exec() != Qt:;Accepted ) {
return 0;
}
//check the login Info
delete loginDlg;
MainWindow w;
w.show()
return app.exec();
}
From the Qt Examples (Address book) I saw I just can use the accept() and reject() slots.
The thing is that I like the window to close based on some function flow, and not ok/close buttons.
How can I trigger those slots from function? .
As liaK pointed out you can just call the following functions from your code:
loginDlg->accept();
loginDlg->reject();
You can also call the following equivalent function using the result as a parameter:
loginDlg->done(QDialog::Accepted);
loginDlg->done(QDialog::Rejected);
PS: Note also there is no Qt::Accepted value as specified in your question.
The correct constant is QDialog::Accepted
Just call them.. They are normal functions..
E.g:
loginDlg->accept();
Also see this..
Related
I am creating a laundry machine simulation with my team for school. I have simulation.cpp where I have functions to control the GUI and main.cpp where I only call one Work() function which is supposed to check whether the user has clicked on a button (e.g. adding coins). There are many classes and interfaces in between these two which handles the application logic which do not matter for the simulation part.
My problem is that I want to be able to check a checkbox when a button is clicked. However, in main.cpp I cannot do anything after return a.exec(). I also cannot do anything before that since this is what pops up the GUI.
So I want to use a timer with 1 sec interval, which when ticks calls the Work() function. I created this timer in simulation.cpp which works but I could not create it in main.cpp.
My simulation.cpp looks like this:
bool button10 = false;
Simulation::Simulation(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::Simulation)
{
ui->setupUi(this);
timer = new QTimer(this); // create it
connect(timer, &QTimer::timeout, this, &Simulation::TimerSlot ); // connect it
timer->start(1000);
}
void Simulation::TimerSlot()
{
SetCoin_10(coin10);
coin10++;
}
void Simulation::SetCoin_10(uint8_t nrOfCoins){
if(nrOfCoins == 1){
ui->checkBox_17->setChecked(1);
}
else if(nrOfCoins ==2){
ui->checkBox_16->setChecked(1);
}
else if(nrOfCoins ==3){
ui->checkBox_15->setChecked(1);
}
}
uint8_t Simulation::GetBtn_10(){
if(button10){
button10 = false;
return true;
}
else{
return false;
}
}
and main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
simulation = new Simulation();
cs = new Coins(simulation);
ps = new ProgramSelector(simulation);
sp = new Soap(simulation);
dr = new Director(cs, ps, sp);
simulation->show();
dr->Work(); //this is what I want to execute every second (from director class)
return a.exec();
}
How do I make this happen? Thanks a lot in advance!
You can "connect" to Events. Qt will enter the event loop on exec() and call the connected functions when events occur.
You already did that on your timer. You just call the TimerSlot() whenever the timer fires.
Your problem is just the accessibility of your variables. Right now, you cannot access "dr" to call "dr->Work()" from within the simulation class.
Option1:
Pass the objects like "dr" and "cs" to the Simulation, either in Constructor like new Simulation(dr, cs...) or by adding setter function that you then call like simulation.setCoins(cs)
Option2:
Create the objects like "dr" and "cs" in the Simulation. Probably best in constructor.
Hint: For both options, you should probably create member variables like this:
private Coins coins;
This will not require new keyword, because it's created on the stack instead of the heap. This also means, you don't need to delete the coins object in destructor. As you don't get a pointer then, you access functions using . instead of ->.
I got a program in which I connect with a QSignalMapper multiple signal from object to a slot in the main program:
class A()
{
private:
QSignalMapper * signalMapperRead_;
std::vector<Service*> services_;
public:
void initConnection()
{
signalMapperRead_ = new QSignalMapper();
connect(signalMapperRead_, SIGNAL(mapped(int)), this, SLOT(readyToSendToService(int)));
for ( size_t i = 0 ; i < services_.size() ; ++i )
{
connect(services_.at(i), SIGNAL(readyToSendToServer()), signalMapperRead_, SLOT(map()));
signalMapperRead_->setMapping(services_.at(i), (int)i);
}
}
int run()
{
initConnection();
for(;;)
{
//do stuff;
}
}
};
int main()
{
QApplication app(argc, argv);
A * a = new A();
a->run();
return app.exec
}
then, as the program is a kind of server i make him loop, and waiting for new client, ...
But the slot is never called. I am thinking that maybe it's because the program is always in the loop and never check if a signal has been emitted.
Can you please help me
Don't use your own loop, create a QApplication and call its exec() method.
You have to call QApplication::exec() for Qt to deliver signals.
Edit for changed code: Just remove the for(;;)-Loop, it's uneccessary. QApplication::exec() has its own loop.
But the slot is never called.
The Qt documentation about QApplication::exec says:
Enters the main event loop and waits until exit() is called [...].
It is necessary to call this function to start event handling. The main event loop receives events from the window system and dispatches these to the application widgets. [...]
Generally, no user interaction can take place before calling exec(). [...]
This means that it's the exec method that takes care of the signal-slot system. You are calling A::run (before the exec function) which contains an for(;;) infinite loop which will block the real loop from being executed leading to your signals to be lost.
I have found a work-around. Beside I am not sure it's very efficient, my solution is to start a QEventLoop at every cycle of my for(;;) loop, and I made this QEventLoop quit on a QTimer timeout
In my application I have a tray icon and so I overrode closeEvent so that the application "minimizes" when certain things happen. However, I do expect that upon pressing exit, that the application will completely exit. However, after overriding closeEvent and calling the function quit(), it seems to bypass the MainWindow destructor, where I have some code.
What am I missing in closeEvent to properly close the application so that the destructor of MainWindow is called, as is the case when closeEvent isn't overriden?
I've tried using
QMainWindow::closeEvent(event);
and a few other things, but the destructor is never called.
My close event implementation is:
void MainWindow::closeEvent(QCloseEvent * event)
{
if(m_closeCompletely == false)
{
if (trayIcon->isVisible())
{
QMessageBox::information(this, tr("Hello"),
tr("The program will keep running in the "
"system tray. To terminate the program, "
"choose <b>Quit</b> in the context menu "
"of the system tray entry."));
}
}
else
{
event->accept();
}
}
The WA_DeleteOnClose attribute needs to be set to call the destructor on a close event, otherwise a widget or window is just hidden from view. Add the following to the class constructor:
this->setAttribute(Qt::WA_DeleteOnClose);
This will cause the destructor to be called on a close event.
It all depends on where and how you allocated the objects you are using. If you create the QApplication and QMainWindow on the heap then they will lurk around until the OS cleans up the memory. Sending a close() to a QWidget (and QMainWindow is one) will only close it .. hide it visually from the user. You can show() later on, close() does not destruct it.
You could use something like this:
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
MyMainWindow mw;
mw.show();
int rc = app.exec();
// optional: do_cleanup();
return rc;
}
app and mw are constructed on the stack. They will be destructed in reverse order when the app returns from the exec() call (usually when you send quit() to the QCoreApplication::instance()). You can even provide a plain cleanup function, no need to put something into the destructor of the UI.
Remember that all the Application Resources are hold by the QApplication;
Once your MainWindow is closed, it just be close, aka hide from the screen;
I wonder why you want to destructor your MainWindow, it seems that you've made a system tray entry, so my suggestion is just to hide the MainWindow but to destructor, cause there is a system tray, you may want to click it to show the MainWindow.
Hope to Help. : )
I just ran into this same problem and it was because I was running an infinite loop that never allowed the application to close.
forever
{
_runGameLoop();
}
I had to make the loop end when MainWindow closed
while(!M->isClosed())
{
_runGameLoop();
}
And of course I had to implement isClosed()
bool MainWindow::isClosed()
{
return _isClosed;
}
void MainWindow::closeEvent(QCloseEvent*)
{
_isClosed = true;
}
I have subclassed QDialog to implement functionality similar to QMessageBox ( I needed this to allow for customization). It has a text message and OK, Cancel buttons. I am showing the dialog using exec() to make it blocking. Now, how do I return values of true/false when the user clicks on OK/Cancel?
I tried connecting the buttons to setResult() and then, return the result value when clicked, but
Clicking the buttons does not close the dialog box
the return value is incorrect.
Following is the code I have written. I think I am wrong in the exec/result part - but I am not sure how to fix it.
class MyMessageBox : public QDialog {
Q_OBJECT
private slots:
void onOKButtonClicked() { this->setResult(QDialog::Accepted); }
void onCancelButtonClicked() { this->setResult(QDialog::Rejected); }
public:
MyMessageBox(QMessageBox::Icon icon, const QString& title,
const QString& text, bool showCancelButton = true,
QWidget* parent = 0);
virtual void resizeEvent(QResizeEvent* e);
QDialog::DialogCode showYourself()
{
this->setWindowModality(Qt::ApplicationModal);
this->exec();
return static_cast<QDialog::DialogCode>(this->result());
}
};
The user will instantiate the class and call showYourself() which is expected to return the value and also close(and delete) the dialog.
I have posted partial code. Let me know if you need more and I will post the complete version.
Some points :
Rather than using setResult() yourself, use QDialog::accept() and QDialog::reject().
It seems you are not taking full advantage of the signals and slots. You need the object which create the dialog (or another one) to listen to the signals of the dialog.
In your code you are not connecting signals to slots either.
With my fix onOKButtonClicked and onCancelButtonClicked are unnecessary.
With my fix you don't need showYourself(). Just call exec and with the events
information will flow.
You need to add this code before showing the dialog (this assume it is in a dialog method):
QObject::connect(acceptButton, SIGNAL(clicked()), this, SLOT(accept()));
QObject::connect(rejectButton, SIGNAL(clicked()), this, SLOT(reject()));
In the caller object you have
void someInitFunctionOrConstructor(){
QObject::connect(mydialog, SIGNAL(finished (int)), this, SLOT(dialogIsFinished(int)));
}
void dialogIsFinished(int){ //this is a slot
if(result == QDialog::Accepted){
//do something
return
}
//do another thing
}
Another solution:
// set signal and slot for "Buttons"
connect(YesButton, SIGNAL(clicked()), dlg, SLOT(accept()));
connect(NoButton, SIGNAL(clicked()), dlg, SLOT(reject()));
// show modal window event loop and wait for button clicks
int dialogCode = dlg->exec();
// act on dialog return code
if(dialogCode == QDialog::Accepted) { // YesButton clicked }
if(dialogCode == QDialog::Rejected) { // NoButton clicked }
Case 1 Clicking the buttons does not close the dialog box.
For this you have to close the dialog on respective SLOTS, so Use
void onOKButtonClicked(){ this->setResult(QDialog::Accepted); this->close();}
void onCancelButtonClicked(){ this->setResult(QDialog::Rejected);this->close();}
Note: Only after you have clicked the Ok button or Cancel button in a standard QMessageBox, setResult() function is triggered and the status is changed. It's not the same effect when done vice versa.
Case 2 The return value is incorrect.
I think only after your dialog gets closed, you will have the result available in result() function. So I guess it will be solved, after you have made the changes specified in Case 1.
If it still persists, use your own private member function to resolve it.
I have a Qt application that uses a QMainWindow-derived class for the main UI. On startup I want to make some security checks and, if they fail, display a message to the user and close the main window. Currently I make these checks in the QMainWindow constructor, but if I call the close method, nothing happens and the application continues to run. For example:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setupUi(this);
...
if (checkFails())
{
QMessageBox::warning(this, tr("Error"), tr("You cannot run this app"));
// This has no effect
close();
}
}
Alternatively I could make the checks in the main function but then I lose the ability to display a language-specific message box (the tr macro only works in a QObject-derived class by the looks of things.)
Any ideas on how to close the main window on startup or make the tr macro work outside of a QObject derived class?
The event loop needs to be running before you can successfully close the main window. Since you probably first construct a window, and then start the event loop the close() call has no effect. Try the following solution instead:
QTimer::singleShot(0, this, SLOT(close()));
The QTimer::singleShot() will fire as soon as an event loop has been started, and subsequently calls the close() method on your application main window.
The above solution will probably cause your main application window to be visible for a short period of time, causing unwanted flickering.
A cleaner solution should perform the security checks prior to constructing the main window. Since tr() is also available as a static method on QObject, this can be done from the main function.
Most applications start up in three steps: 1) construct the window; 2) show the window; 3) start the event loop. You can make steps 2 and 3 conditional on the success of step 1 by adding a flag, whose value is set by the window constructor, to the window class:
Window class:
class myMainWindowClass : public QMainWindow
{
Q_OBJECT
public:
myMainWindowClass()
: isFinished_(false) { if (error) isFinished_ = true; } // constructor
bool isFinished() const { return isFinished_; }
private:
bool isFinished_;
}
Application code:
int main()
{
myMainWindowClass main_window(); // Step 1
// Finish early if isFinished flag is set
if (main_window.isFinished())
return 0;
main_window.show(); // Step 2
return a.exec(); // Step 3
}
This should also avoid any flicker as the application will end before the window is show()n.
tr is a public static member of QObject. You should be able to call QObject::tr("Error") in your main function.
Have you tried first hide()ing the window (this should occur anyway when close() is called) to see if this then allows close() to destroy the window.
If this does not work, you could always try destroy(true, true)ing the window along with any sub-windows.