QT - SplashScreen implementation - qt

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.

Related

QSplashScreen disappears too quickly

I am trying to show a QSplashScreen before launching my application. The problem I have is that the QSplashScreen disappears too quickly. I would like it to show for 2 seconds before the real application loads.
Below the small example I built to show the error:
#include <QApplication>
#include <QSplashScreen>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSplashScreen *splash = new QSplashScreen;
splash->setPixmap(QPixmap(":/dredgingSplash.png"));
splash->show();
Qt::Alignment topRight = Qt::AlignRight | Qt::AlignTop;
splash->showMessage(QObject::tr("Setting up the main window..."), topRight, Qt::white);
QTimer::singleShot(2500, splash, SLOT(close()));
MainWindow w;
QTimer::singleShot(2500, &w, SLOT(show()));
splash->showMessage(QObject::tr("loading modules..."), topRight, Qt::white);
splash->showMessage(QObject::tr("Establishing Connections..."), topRight, Qt::white);
w.show();
delete splash;
return a.exec();
}
EDITS using QSplashScreen::finish() from official documentation:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSplashScreen *splash = new QSplashScreen;
splash->setPixmap(QPixmap(":/dredgingSplash.png"));
splash->show();
Qt::Alignment topRight = Qt::AlignRight | Qt::AlignTop;
splash->showMessage(QObject::tr("Setting up the main window..."), topRight, Qt::white);
MainWindow w;
splash->showMessage(QObject::tr("loading modules..."), topRight, Qt::white);
splash->showMessage(QObject::tr("Establishing Connections..."), topRight, Qt::white);
w.show();
splash->finish(&w);
return a.exec();
}
EDITS 2 using a class:
#include <QApplication>
#include <QSplashScreen>
#include <QTimer>
class ShowImageTime {
public:
void slInit();
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSplashScreen *splash = new QSplashScreen;
splash->setPixmap(QPixmap(":/dredgingSplash.png"));
splash->show();
Qt::Alignment topRight = Qt::AlignRight | Qt::AlignTop;
splash->showMessage(QObject::tr("Setting up the main window..."), topRight, Qt::white);
MainWindow w;
QTimer::singleShot(3000, splash, SLOT(close()));// close splash after 4s
QTimer::singleShot(3000, &w, SLOT(ShowImageTime::slInit(this->show)));// mainwindow reappears after 4s
splash->showMessage(QObject::tr("loading modules..."), topRight, Qt::white);
splash->showMessage(QObject::tr("Establishing Connections..."), topRight, Qt::white);
w.show();
splash->finish(&w);
return a.exec();
}
I tried to play with the QTimer as I thought that could be the potential problem due to priority of loading, but unfortunately if I change QTimer::singleShot(2500, splash, SLOT(close())); with QTimer::singleShot(12500, splash, SLOT(close())); or even higher numbers, there is literally no difference, so I am not sure why that is not an option.
Also I came across this source and I also followed official documentation but that also did not help me to figure out the problem.
Also this post suggests that the problem keeps being related to the QTimer but I don't see how since bigger or smaller intervals seems not to count.
What am I missing to keep the QSplashScreen to stay for 2 seconds instead of disappearing (or not even see it) right away?
Thanks for pointing to the right direction.
The problem is, that your code is starting the timer and then continues running. So the MainWindow is created, shown and the SplashScreen is deleted/finished. The timer's timout function will trigger after all this happened. That is why it closes so quickly.
SplashScreens are usually shown, if the application start is very slow, because there is so much going on in the background. In your case, there is basically no load and the code executes super quick.
You could either use a sleep call for 2sec right after calling splash->show() or put all the code for closing the SplashScreen, showing the Mainwindow in a timer's timout slot and delete the SplashScreen there.

QML application virtual keyboard behind fullscreen application

I want to use Qt virtual keyboard in my QML application. I use Qt 5.9.4 and I am on Windows 7.
I tried the Qt example called "basic", it works in "windowed" mode, but when I put the application window in full screen with
view.showFullScreen(); // instead of view.show() for windowed mode
the keyboard appears behind the application window and not above it, so it's not usable.
How to correct that?
EDIT:
Sorry, as I talk about Qt example, I thought, wrongly, that everyone had it.
Here is the code:
#include <QQuickView>
#include <QGuiApplication>
#include <QQmlEngine>
int main(int argc, char *argv[])
{
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
QGuiApplication app(argc, argv);
QQuickView view(QString("qrc:/%2").arg(MAIN_QML));
if (view.status() == QQuickView::Error)
return -1;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.showFullScreen();
return app.exec();
}

Showing a messagebox from library

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;
}

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.

Qt application crashes on quit event on Mac OSX

I'm just starting out with Qt on a Mac and working through:
http://doc.qt.nokia.com/4.7/gettingstartedqt.html
When I run the second example which has the following code:
#include <QtGui>
int main(int argv, char **args)
{
QApplication app(argv, args);
QTextEdit textEdit;
QPushButton quitButton("Quit");
QObject::connect(&quitButton, SIGNAL(clicked()), qApp, SLOT(quit()));
QVBoxLayout layout;
layout.addWidget(&textEdit);
layout.addWidget(&quitButton);
QWidget window;
window.setLayout(&layout);
window.show();
return app.exec();
}
The application starts up fine and works fine. The only issue occurs when I click the "Quit" button. When I do that the crash reporter is invoked and osx says the app quit unexpectedly.
Anything obvious I'm doing wrong?
Thanks
The problem is the order of the delete if you declare variables on the stack. The best it to give your object parents so that they can destroy the children.
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget window;
// If window get's destroyed, it will destroy it's children...
QTextEdit textEdit(&window);
QPushButton quitButton("Quit",&window);
QObject::connect(&quitButton, SIGNAL(clicked()), qApp, SLOT(quit()));
QVBoxLayout layout;
layout.addWidget(&textEdit);
layout.addWidget(&quitButton);
window.setLayout(&layout);
window.show();
return app.exec();
}
PS: Did you actually try a debugger to see where it crashes? It will give you an idea ;) My suggestion is to take a working Qt example and play with it.
PS2: The order I created the widgets also prevents the crash...
Try:
QTextEdit * textEdit = new QTextEdit;
QPushButton * quitButton = new QPushButton("Quit");

Resources