Showing a messagebox from library - qt

I need to show a messagebox to user from my static library but using QMessageBox needs QApplication;
How can I show a message box without QApplication?

Just instantiate an instance of QApplication for the lifetime of the app. (e.g. in your "main", "WinMain", or somewhere early in your app initialization sequence)
From then on, you can create modal instances of QMessageBox all you want. It should co-exist fine with your own message pump as long as you are using a recent version of Qt.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMessageBox msgBox;
msgBox.setText("Hello World");
msgBox.exec(); // blocks until the user finishes interacting with the message box
return 0;
}

Related

QT - SplashScreen implementation

I have an embedded Qt application for Linux which has the following startup code:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Startup actions neeeded to display AppView correctly
// Black screen is shown for several seconds
// ...
QQuickView AppView;
AppView.setSource(QUrl(QStringLiteral("main.qml")));
AppView.resize(480, 800);
AppView.show();
return app.exec();
}
I'd like to remove the black screen shown before AppView and to display QML animation
instead of it.
I see two possible options here but non of them is clear. Could you please advice
which one of them is more correct and also comment/answer the questions in each.
Option 1: To display QSplashScreen at the beginnning of main().
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSplashScreen *splash = new QSplashScreen();
splash->show();
// Startup actions neeeded to display AppView correctly
// Black screen is shown for several seconds
// ...
}
The question here is what API to use to attach QML animation to QSplashScreen?
QSplashScreen inherits from QWidget, and so as I understand, no API like QQuickWidget::setSource() can be used.
Option 2: To display another QQuickView at the beginnning of main() with attached QML animation.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQuickView SplashView;
SplashView.setSource(QUrl(QStringLiteral("SplashScreen.qml")));
SplashView.resize(480, 800);
SplashView.show();
app.exec();
// Startup actions neeeded to display AppView correctly
// Black screen is shown for several seconds
// ...
QQuickView AppView;
AppView.setSource(QUrl(QStringLiteral("main.qml")));
AppView.resize(480, 800);
AppView.show();
}
The question here is how to to close the SplashView and to display AppView on top of it?
Thanks
Option 1 is not good idea. You should not mix Qt Quick and Qt Widgets applications.
QApplication::exec() starts event loop of main gui thread and never returns until application is quit. Although I do not like your way of handling splash screen, in this case, you can use something like this.
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl("SplashScreen.qml"));
view.resize(640, 480);
view.show();
QTimer::singleShot(2000,&view,[&view](){
view.close();
view.setSource(QUrl("main.qml"));
view.show();
});
return app.exec();
I used timer to simulate "actions to display app correctly" . You should replace that part with your class, which does actions. When actions are done that class can emit a signal in receiving slot you can close current view which shows splash screen and show main app.

QFileDialog from child window closes the application

I'm new to QT and I'm having issues when calling QFileDialog from a child window. My app is relatively simple. I have one prompt widget that gets user input and then runs show on its parent.
This is my main.
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
ParentWidjet w(nullptr);
ChildWidget input(&w);
input.show();
return a.exec();
}
This is the relevant section of the child widget:
ChildWidget::ChildWidget(QWidget *parent) :
QDialog(parent),
ui(new Ui::InputPrompt){
ui->setupUi(this);
this->setParent(parent);
}
...
void ChildWidget::on_imagesSelect_clicked() {
inputFilepath = QFileDialog::getExistingDirectory(static_cast<ParentWidget *>(this->parent()), QCoreApplication::translate("main", "Open directory"), "./", QFileDialog::ShowDirsOnly);
ui->inputPath->setPlainText(inputFilepath);
std::cout << "y u exit" << std::endl;
}
//Setup and show the parent
void ChildWidget::on_buttonBox_accepted() {
static_cast<ParentWidjet *>(this->parent())->setup(inputFilepath, outputFilepath);
static_cast<ParentWidjet *>(this->parent())->show();
}
For some reason when QFileDialog is called, closing it with either OK or Cancel closes both the parent and the child. If I don't use it, but click the OK button of the child, which calls the on_buttonBox_accepted() function, the child closes and the parent widget appears as expected. If I don't pass the parent widget to the child widget in the main, QFileDialog no longer closes the child widget when running. I tried changing the parent of QFileDialog to this or to nullptr but that didn't help.
I think my question is similar to QFileDialog closes window when called
or PyQt5 QFileDialog finishes app when called from child window
But i couldn't extract a solution from them that works for me.
Long story short, the second window is not shown, and there is no action waiting to receive the accept call, so my app just dies. This can be prevented if the quit on last window closed property is disabled. Qt forums suggested a solution, together with a few better design choices. This is what I went with in the end.
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
ParentWidget w(nullptr);
ChildWidget input;
if ( input.exec() == QDialog::accepted) // exec() blocks execution until ok/cancel. unlike show()
{
w.setup(input.inputFilepath, input.outputFilepath); // assuming these are public
w.show()
} else
{ // user closed or pressed cancelled
... what u want to do..
}
return a.exec();
}

Qt Login Dialog Box before Main Window

How do I have the user first login before getting to the main window in my QT app? I'm new to QT and have looked through the documentation and have not found anything very helpful. Thank you.
I would make this in the following way. Let's assume, that my login dialog is a QDialog:
class Login : public QDialog
{
[..]
};
In my application, I create an instance of my Login dialog and if it is accepted, i.e. closed with OK button, I open my main window:
int main(int argc, char *argv[])
{
[..]
QMainWindow mw;
Login login;
if (login.exec() == QDialog::Accepted) {
mw.show();
}
[..]
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
LoginWindow l; // create login-widget
connect(&l, SIGNAL(loggedIn), &w, SLOT(show()); // connect to mainwindow show()
l.show(); // show login-window instead of
// mainwindow at start
return a.exec();
}
You might want to :
1 - exec the loop only if the dialog is accepted, otherwise you application continues to run
2 - create the mainwindow only if accepted, cause it might be a heavy interface, which takes time to initialize
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog_Login dialog;
if(dialog.exec() == QDialog::Accepted){
MainWindow w;
w.setUser(dialog.GetUser());
w.show();
return a.exec();
}
else return 0;
}
You need to create the QApplication instance in parrallel with the login dialog.

How do I quit a qt console application? Are there criterions for the QApplication::quit() slot to work?

I have a weird qt problem: My application doesn't quit in some configurations.
The idea is to have a program, which can be started as a program with a GUI (through myWindow) or as a pure console application (controlled via myConsole, which runs its own loop in its thread to record keyboard inputs). Either way quitting is done by calling the myObject slot quitMyObject, which in turn cleans up some objects and emits the signal signalQuitapplication, which is connected to the QApplication (app) quit slot.
Unfortunately the application only quits when the the window is enabled and the quit command is entered in the console (although the slotQuitMyObject of myObject is always called). So I wonder what criterions Qt has to actually quit the main event loop and exit the program.
The code looks like this:
int main(int argc, char *argv[])
{
bool enableWindow = false;
QApplication app(argc, argv, enableWindow);
MyUiAbstract* myConsole = new ConsoleUi(); // ConsoleUi inherits from MyUiAbstract, which inherits from QThread
MyWindow* myWindow = NULL; // MyWindow inherits from QMainWindow
if(enableWindow)
{
myWindow = new MyWindow();
myWindow->show();
}
MyObject* myObject = new MyObject(myConsole, myWindow, ...);
QObject::connect(myObject, SIGNAL(signalQuitQApplication()), &app, SLOT(quit()), Qt::QueuedConnection);
QObject::connect(myConsole, SIGNAL(signalQuitMyObject()), myObject, SLOT(slotQuitMyObject()), Qt::QueuedConnection);
QObject::connect(myWindow, SIGNAL(signalQuitMyObject()), myObject, SLOT(slotQuitMyObject()), Qt::QueuedConnection);
QObject::connect(myWindow, SIGNAL(signalQuitConsoleUI()), myConsole, SLOT(slotQuitMyUi()), Qt::QueuedConnection);
return app.exec();
}
Try to use that code in your MyConsole class:
#include <QApplication>
...
qApp->quit();
Also you need to close all the event loops & threads before quit.

QX11EmbedWidget and QX11EmbedContainer

Can one place an arbitrary program (firefox, openoffice, etc...) in a QX11EmbedContainer? The fllowing seems, to work
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QX11EmbedContainer container;
container.show();
QProcess * process = new QProcess(&container);
QString executable("xterm");
QStringList arguments;
arguments << "-into";
arguments << QString::number(container.winId());
process->start(executable, arguments);
int status = app.exec();
process->close();
return status;
}
but the next snippet launches a new window, not what I want
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QX11EmbedContainer container;
container.show();
QProcess * process = new QProcess(&container);
QString executable("konsole");
process->start(executable);
int status = app.exec();
process->close();
return status;
}
The first example work because xterm is able to reparent its top level widget (an X11 window). You tell it to do so with the argument -into <WinId>.
I don't know if Konsole can do that, i don't use it and the man page doesn't seem to talk about this.
But that doesn't mean it is not doable, the X Window system is very flexible and anyone can reparent another window (that's how windows managers add decorations to windows).
Take a look at man 3 XReparentWindow ;-)

Resources