I went throught suggested "questions" about my problem. However neither does not solve it.
I program two windows. The second window is opening from first window. I need active the both windows, however to start the first window(MainWindow) I use:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.setWindowModality(Qt::NonModal);
return a.exec();
}
As was mentioned, the second window is started from pushButton, which is situated in first window(MainWindow) by same way.
void MainWindow::on_pushButton_2_clicked()
{
Graphics gr;
gr.setWindowModality(Qt::NonModal);
gr.exec();
}
I changed modality to NonModal,however the problem is without change. The Non-Modal mean:"The window is not modal and does not block input to other windows." <- from documentation
By documentation is recommended to avoid used .exec(). The alternatives are .show() and open(), which i tried. After the modification, the second window is shut down immediately after opening. after open immediately shut down.
Do you have any idea, how to solve that?
Graphics gr; defines a local variable, so the object is destructed as soon as it goes out of scope (at the end of your function).
In Qt, the typical approach is to work with pointers to Qt widgets (and, more generally, QObjects), but have a parent for each – the parent will clean it up.
Try this instead:
auto gr = new Graphics(this);
gr->setWindowModality(Qt::NonModal); // this is the default, no need for this call
gr->show();
This way the window will survive until your main window is destructed. In Qt there is also a mechanism for widgets/objects to self-destruct:
this->deleteLater();
So for example if you want to close and cleanup gr you can use that mechanism (you could also store gr as a member and call gr->deleteLater().
Related
In my main window i used this code to open my game application
void MainWindow::on_playButton_clicked(){
CSpaceInwaders* pGame = new CSpaceInwaders(qApp->screens()[0]->size());
pGame->showFullScreen();
pGame->Run();
}
Then in there this is the run function that I called
void CSpaceInwaders::Run(){
scene()->clear();
setCursor(Qt::BlankCursor);
m_pCannon =new CCannon(EColor::Red);
m_pCannon->setPos(m_onScreenSize.width()/2,m_onScreenSize.height()-gCannonSize.height());
m_pCannon->setFlag(QGraphicsItem::ItemIsFocusable);
m_pCannon->setFocus();
scene()->addItem(m_pCannon);
connect(m_pCannon, &CCannon::sigIncreaseScore,this,&CSpaceInwaders::onIncreaseScore);
connect(m_pCannon, &CCannon::sigDecreseScore,this,&CSpaceInwaders::onDecreseScore);
m_pPoints = new CPoints();
scene()->addItem(m_pPoints);
QTimer* pTimer = new QTimer(this);
connect(pTimer, &QTimer::timeout,this,&CSpaceInwaders::onCreateEnemy);
pTimer->start(2000);}
after the game over I want to go back to my main window. So I used this function
void CSpaceInwaders::onGameOver(){
scene()->clear();
QMessageBox msgBox;
msgBox.setText("Game.");
msgBox.setInformativeText("You got hit ! Game Over");
msgBox.setStandardButtons(QMessageBox::Ok);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Ok:
close();
MainWindow w;
w.show();
}}
This takes me back to the main window but after few seconds it closes.
I want to know how to fix this
Note : Created using QT
The problem is with the code in the case:
case QMessageBox::Ok:
close();
MainWindow w;
w.show();
The problem is two-fold: First of all you can't actually define variables inside a case like that. You need to add a scope. I'm surprised the compiler doesn't yell at you for that.
The second problem (and that's causing your problem) is that the variable w is a local variable inside the switch statement. Once the statement ends so does the life-time and w and it's destructed and ceases to exist.
The solution (as far as I know) seems to be simple: Don't create and open a new main window! When you start the "space invaders" game you never close the original main window, it's should still be running in the background.
However this is a very bad way to "run" what should essentially be either a separate program or at the very least part of your normal program flow and event loop. Either extract the mini-game into its own program that you then load and execute, or don't create a separate application object and just open a normal window and let the main application event loop handle it.
Using this I solved my problem
void CSpaceInwaders::onGameOver(){
this->close();
}
I've been recently trying to get into Qt to better understand class hierarchy and OOP. I just fell upon this question in a test bank, asking to "fix" this code to prevent compiler and runtime errors. However, I unfortunately couldn't find the solution and I wasn't able to come up with a solution myself. For me, all QObject-derived classes handle all memory deallocation. So the following code does not pose any problems that I can see, and it compiles.
#include <QLabel>
#include <QWidget>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel label("my string");
QWidget window;
label.setParent(&window);
window.show();
return a.exec();
}
For me, all QObject-derived classes handle all memory deallocation.
Exactly, that's why this sample code contains an error of the kind you'll see when you close window. Qt's parent-children system works in the way that the widget manages it's children's lifetime and deletes them when being deleted itself.
So, when QApplication quits ~QWidget() destructor is called, causing deletion of the label. Thus, ~QLabel() is called.
But on the other hand, when main is finished, local variables are being deleted, label is one of them. It is not a pointer but a value variable, we get another call of ~QLabel().
Double call of the destructor is the error. It can be fixed by creating label on a heap via new.
Qt handles memory management by parent-child relationships. If a parent widget/window is destroyed, it destroys all the children as well. In this instance the label is set as a child of the window, which means that the windows destructor will try to delete it. As it is create on the stack, the memory deallocation will fail. And even if it will not (assuming the memory manger silently ignores such call, which it should not), the label will be destroyed the second time when the execution of main() finishes, leading to double-delete. As others have already pointed out, you could solve it by allocating the label on the heap using QLabel *label = new QLabel("my string"); instead, but there is an even simpler solution: re-order the creation of the window and the label:
#include <QLabel>
#include <QWidget>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QLabel label("my string");
label.setParent(&window);
window.show();
return a.exec();
}
This way the label will be destroyed before the window. That will remove the label from the windows children list and allow correct termination.
Finally, the use of the setParent() method is actually relatively rare in Qt. Normally you would have passed the parent to the constructor of the child widget:
QWidget window;
QLabel label("my string", &window); // No need for setParent()
This requires that the window already exists, and is Qt-s way of leading you towards the correct solution.
Qt recently started crashing without having a reason for it. The most recent one which is currently grinding my nerves down to a pulp is crashing due to starting another form programmatically. The "must construct QApplication before a QWidget" apparently is a common issue with Qt 5.7.* versions and the solutions I have found so far in StackOverflow haven't helped me.
This is a screenshot of the error message I got after the application crashed:
And here is the bit of the code that I remove which allows me to restart the application without any noticeable problems:
#include "operations.h"
Operations o;
void mainWindow::on_thisButton_clicked()
{
o.show();
this->hide();
}
----
The main.cpp as requested :)
#include "mainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
mainWindow w;
w.show();
return a.exec();
}
Try this:
#include "operations.h"
void mainWindow::on_thisButton_clicked()
{
Operations *o = new Operations();
o->show();
this->hide();
}
You might want to declare Operations *o as a member of mainWindow and initialize it the the constructor if you don't want to create a new one each time the button is clicked.
"must construct QApplication before a QWidget" is the standard type of error you get with Qt applications, when linking something incompatible ( like mixing debug/release ).
So in most use cases this indicates a build problem and has nothing to with the code itself.
Don't create Operations object as a global variable, as it will be created as a static BEFORE running main(), therefore the error message is simply correct and relevant. This is a C++ issue, not a Qt one.
All other suggestions work because you now create the object at the right time, after the QApplication...
Okay, I have managed to find a solution, however, it is borderline idiotic as it does not make any sense why it does not work in its prior state. Technically, all you need to do in order to have the error not appearing is to stick the declaration of the form class you are referring within the function itself(ie Operations o;).
Here is the code solution itself:
#include "operations.h"
void mainWindow::on_thisButton_clicked()
{
Operations o;
o.show();
this->hide();
}
Bare in mind that this is not the end of all problems as I currently have the problem of the new form closing in the very same 1 second period it opens. If I manage to solve it I will update my solution.
I have a QSharedMemory to prevent that two processes of my application are running at the same time. Process A sets the QSharedMemory to "locked" when started. Now my process B sets a value like "please come back to foreground".
Is there an easy way for process A to observe changes in the QSharedMemory, i.e. avoids implementing a stupid pulling timer?
Here we are: QSystemSemaphore
Like its lighter counterpart QSemaphore, a QSystemSemaphore can be accessed from multiple threads. Unlike QSemaphore, a QSystemSemaphore can also be accessed from multiple processes.
Like QSharedMemory, QSystemSemaphore uses a key-based access method.
Instead of using shared memory, the process could open a QLocalSocket to a named local server, and when it fails, open a QLocalServer. All subsequent processes will success to open the socket to the server, and can communicate with it. That's probably the simplest, most portable way of accomplishing the job.
You can also use QtSingleApplication, iff it has been ported to Qt 5.
To answere your question: No, QSharedMemory does not have such a feature.
If you just want to have a "single instance" application, you can use https://github.com/Skycoder42/QSingleInstance.
It makes shure you have only 1 instance of you application at a time, can automatically bring the active window to the front and allows you to pass parameters from the new process to the running one.
Simple example:
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <qsingleinstance.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSingleInstance instance;
MainWindow *w = NULL;
instance.setStartupFunction([&]() -> int {
w = new MainWindow(NULL);
instance.setNotifyWindow(w);
w->show();
return 0;
});
QObject::connect(qApp, &QApplication::aboutToQuit, [&](){
delete w;
});
QObject::connect(&instance, &QSingleInstance::instanceMessage, [&](QStringList args){
QMessageBox::information(w, "Message", args.join('\n'));
});
return instance.singleExec();
}
This will show the mainwindow, just like you woudl expect. If the application is run a second time, the currently running mainwindow will be raised to the foreground and a messagebox with the arguments will be shown.
Note: This example uses the QWidgets, but the QSingleInstance can be used with a gui or core application, too.
I'm having an issue. My textEditBox doesn't seem to be updating when my Addtext function is called.
Here's my Addtext:
void CTextBox::AddText(QString string, QString spriteString)
{
textBrowser->setText(string + spriteString);
update();
}
Another class then calls the function and it should add text to the textbox but it doesn't.
How do you call CTextBox::AddText()? update() only schedules a paintEvent() for later, when the program returns to the event loop. That means that
you actually need to have an event loop, ie. at some point you need to call qApp->exec();
you need to allow the programm some time to qApp->processEvents() (insert that after update()), if you want any paining done within a blocking while() {...} or something like that.
Edit: Come to think of it, you shouldn't even need to call update() nor processEvents() if your program returns to the event loop some time after AddText, so there really seems to be an issue with the event loop. Post your main.cpp, will you?
Here is a trivial example of what it sounds like you are trying to do. Maybe you can see where your design differs?
Notice: no explicit update() is needed. I think that's a red herring. I think it far more likely that (1) you are somehow calling your AddText method with empty strings, or (2) your real text edit is a different variable, and have somehow created two of them and are updating one that just exists in memory and was never added to a layout. Perhaps the code of your FileLoaderQT would help? (You can edit your question rather than posting in comments.)
#include <QtGui>
int main(int argc, char **argv) {
QApplication app(argc, argv);
QMainWindow w;
QTextEdit *edit = new QTextEdit;
w.setCentralWidget(edit);
edit->setText("Hello world!");
w.show();
edit->append("Hello world again!");
return app.exec();
}