I am trying to connect QML signal to Qt slot. I have read that example and here is code
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
qDebug()<<QUrl::fromLocalFile("main.qml");
QQuickView view(QUrl::fromLocalFile("main.qml"));//I should replace that line
QObject *item = view.rootObject();
MyClass myClass;
QObject::connect(item, SIGNAL(qmlSignal(QString)),
&myClass, SLOT(cppSlot(QString)));
view.show();
return app.exec();
}
It works fine, but the problem is that main.qml should be in the folder where .exe file is. So, every time I modify main.qml I should copy it to another foder. File path to main.qml is: "C:\Qt\projects\ConnectionsQT\main.qml". I have tried to replace line by
QQuickView view(QUrl("C:\Qt\projects\ConnectionsQT\main.qml");
and by
QQuickView view(QUrl("C:\\Qt\\projects\\ConnectionsQT\\main.qml");
but in that cases the program cannot find the main.qml file. What should I do?
The good practice is making your qml file part of the app executable by putting into .qrc resource file with Qt creator or by hand:
http://qt-project.org/doc/qt-5/qtquick-deployment.html#managing-resource-files-with-the-qt-resource-system
And the you can make use of it with something like:
QQuickView view(QUrl("qrc:///res/qml/main.qml"));
Related
I am new to Qt. I want to make a game with many different screens (e.g. Main Screen, Loading Screen...), but in a single window, switched by index in a QstackWidget. When switching to the Main Screen, it should play a background music continuously. Searching the web, I found QMediaPlayer with QMediaPlayerlist can do the trick. So I tried like this (using a basic QMainWindow to simplify the code):
QtWidgetApplication1.h
#pragma once
#include <QtWidgets/QMainWindow>
#include <QMediaPlayer>
#include <QMediaPlaylist>
class QtWidgetsApplication1 : public QMainWindow
{
Q_OBJECT
public:
QtWidgetsApplication1(QWidget *parent = Q_NULLPTR);
void playAudio();
void stopAudio();
private:
QMediaPlayer* player;
QMediaPlaylist* playList;
};
QtWidgetApplication1.cpp
#include "QtWidgetsApplication1.h"
QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
: QMainWindow(parent)
{
playAudio();
}
void QtWidgetsApplication1::playAudio() {
player = new QMediaPlayer();
playList = new QMediaPlaylist();
playList->addMedia(QUrl::fromLocalFile("main_theme.mp3"));
playList->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
player->setPlaylist(playList);
player->play();
}
void QtWidgetsApplication1::stopAudio() {
player->stop();
delete player;
delete playList;
player = Q_NULLPTR;
playList = Q_NULLPTR;
}
main.cpp
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtWidgetsApplication1 w;
w.show();
return a.exec();
}
Error:
It only plays the audio once, and shows an error message
QObject::startTimer: Timers can only be used with threads started with
QThread
Note:
I've tried (1.) using QMediaPlayer only and detecting QMediaPlayer::endOfMedia signal, (2.) QSound with a .wav file. First approach cannot get QMediaPlayer::endOfMedia signal but get QMediaPlayer::pauseState signal, however, I still fail to replay the audio. Second approach doesn't even play the audio and shows a QEventLoop error.
Enviroment:
Windows 10
Qt 5.15.2 MSVC2019 X64
Visual Studio 2019
Instead of adding QT += multimedia in the .pro file, which the projects in VS doesn't have, I tried to include those .lib to the project settings (Refer to How to add Qt libraries to visual studio). Actually, the best way to include QtMultiMedia is: go to
Extensions (in VS) > Qt VS tools > Qt Project Settings > General > Qt Modules and select the modules you want to include. By including the right modules, the problem I have faced has gone.
There is an example in the documentation providing the following code, which seems to be quite simple :
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPixmap pixmap(":/splash.png");
QSplashScreen splash(pixmap);
splash.show();
app.processEvents();
...
QMainWindow window;
window.show();
splash.finish(&window);
return app.exec();
}
Now the thing is that I am using QApplication, create an engine and open my QML files like this:
engine->load(QUrl(QLatin1String("qrc:/qml/main.qml")));
And from the documentation I cannot really understand how to go the QMainWindow way like in the example, without passing a URL of the file as an argument (there is no such function available). Do I have to write a C++ class derived from QMainWindow or something like this? Or am I missing another important point?
I am furthermore happy about any other suggestions of getting QSplashScreen to work.
I have an application that I want to translate the UI for Persian language. For that, I need to load qt_fa.qm and my_app_fa.qm in it. But the misfortune is, both files aren't loaded correctly. Below code always run as I expected:
QApplication app(argc, argv);
QTranslator translator;
translator.load("qt_fa"); // returns true
app.installTranslator(&translator);
translator.load("my_app_fa"); // returns true
app.installTranslator(&translator);
.
.
sometimes the qt_fa affects the application and the layout is changed to RTL and the translation of Qt used words are displayed and none of my own translations are shown.
Sometimes the my_app_fa affects the app and just my own translations are displayed.
Do have any idea about the reason?
Thanks
According to Qt Documentation with the sample code snippet you should create two objects from QTranslator
int main()
{
QApplication app(argc, argv);
QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&qtTranslator);
QTranslator myappTranslator;
myappTranslator.load("myapp_" + QLocale::system().name());
app.installTranslator(&myappTranslator);
...
return app.exec();
}
I' ve created quick project in Qt, selected from wizard at the begin, when Qt creator is started.
Qt creator create project. There are qmlapplicationvierwer subproject and qml files in main project. I want to add new cpp source and header files (MainMenu.cpp and MainMenu.h) to project and then invoke function from these files in main.qml file.
How I can register new type in qmlapplicationviewer and invoke function from ManiMenu ?
qmlapplicationvierwer has only few function:
QApplication app(argc, argv);
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qml/PUTest/main.qml"));
viewer.showExpanded();
return app.exec();
and:
viewer.addImportPath(const string &path);
Better way is not create project without project wizard ?
Thanks
Normally, you use this wizard to create QML only projects.
The QmlApplication viewer is just a lightweight C++ wrapper around your QML file so a binary is generated and the QML file is loaded.
There's not much magic to do that on your own, see:
https://doc.qt.io/archives/qt-4.7/qtbinding.html
#include <QApplication>
#include <QDeclarativeView>
#include <QDeclarativeContext>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QDeclarativeView view;
QDeclarativeContext *context = view.rootContext();
context->setContextProperty("backgroundColor",
QColor(Qt::yellow));
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
return app.exec();
}
And with setContextProperty you can ad global QML types via cpp...
Of course you can also reuse the QmlApplicationViewer. The Mainclass QmlApplicationViewer is derived from QDeclarativeView, so you directly have access to the context in this class.
So like in the example above, it should be possible to use:
QDeclarativeContext *context = this.rootContext();
context->setContextProperty("backgroundColor", QColor(Qt::yellow));
somewhere in the QmlApplicationViewer costructor or afterwards (didn't try it for now, let me know if it doesn't work).
Do I have to delete objects from the heap in the example below? And if yes, how?
#include <QApplication>
#include <QTreeView>
#include <QListView>
#include <QTableView>
#include <QSplitter>
int main(int argc, char* argv[])
{
QApplication app(argc,argv);
QTreeView* tree = new QTreeView;
QListView* list = new QListView;
QTableView* table = new QTableView;
QSplitter* splitter = new QSplitter;
splitter->addWidget(tree);
splitter->addWidget(list);
splitter->addWidget(table);
splitter->show();
// delete splitter; WHEN TRYING TO DELETE I'M GETTING INFO THAT app EXITED
// delete table; WITH CODE -1073741819
// delete list;
// delete tree;
return app.exec();
}
Thank you for any help.
Just allocate splitter on the stack. Then tree, list and table become children of splitter which takes ownership. When splitter gets deleted, all the children are deleted.
From Widgets Tutorial - Child Widgets:
The button is now a child of the window and will be deleted when the window is destroyed. Note that hiding or closing the window does not automatically destroy it. It will be destroyed when the example exits.
See also Object Trees and Object Ownership.
Gregory Pakosz pointed out the proper solution, but I wanted to reiterate with a code example and to suggest you look into C++ object scope. Greg is accurate but did not clarify that putting splitter on the stack means that once it goes out of scope (the application exits) it will be deleted.
More accurately you should set a QObject's parent. When a parent object takes ownership of an another object it deletes it's children upon calling delete on the parent object. In QSplitters case, addWidget adds to QWidget's layout and the layout takes ownership of those objects.
#include <QApplication>
#include <QTreeView>
#include <QListView>
#include <QTableView>
#include <QSplitter>
int main(int argc, char* argv[])
{
QApplication app(argc,argv);
QTreeView* tree = new QTreeView;
QListView* list = new QListView;
QTableView* table = new QTableView;
QSplitter splitter;
splitter.addWidget(tree);
splitter.addWidget(list);
splitter.addWidget(table);
splitter.show();
return app.exec();
}
So simply making 'splitter' a local variable will cause it to be deleted when it goes out of scope. In turn, it's children will also be deleted.
http://doc.qt.io/qt-5/qtwidgets-tutorials-widgets-windowlayout-example.html
http://doc.qt.io/qt-5/qsplitter.html#addWidget
Instead of managing the memory manually, you can let the compiler do it for you. At that point you may ask: why use the heap at all? You should keep things by value as much as feasible, and let the compiler do the hard work.
The objects will be destroyed in the reverse order of declaration. Thus the splitter - the implicit parent - must be declared first, so that it doesn't attempt to incorrectly delete its children. In C++, the order of declarations has a meaning!
int main(int argc, char* argv[])
{
QApplication app(argc,argv);
QSplitter splitter;
QTreeView tree;
QListView list;
QTableView table;
splitter.addWidget(&tree);
splitter.addWidget(&list);
splitter.addWidget(&table);
splitter.show();
return app.exec();
}