Qt: How to use slots when object are created in class function - c++

I'm learning Qt quick and want to create a tank game. I create QML components by C++ dynamically. It works great until I use QML signals to connect C++ slots. When the QML emit the signal, C++ fail to receive it and execute the function.
The following code is simplifed.
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
GameMap map;
map.generateMap();
return app.exec();
}
gamemap.cpp
void GameMap::generateMap()
{
Player player;
player.generate(&view);
//QEventLoop loop; //it works when I add these code, but still causes some problems. So I'm wondering if there is other solution?
//loop.exec();
}
player.cpp
void Player::generate(View *view)
{
QQmlComponent component(view.engine(),QUrl("qrc:/Player.qml"));
QObject *myObject=component.create();
QQuickItem *item=qobject_cast <QQuickItem*>(myObject);
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
item->setParentItem(view.rootObject());
item->setParent(&view);
QObject::connect(item,SIGNAL(queryCppFun(QString)),this,SLOT(queryFunction(QString)));
}
void Player::queryFunction(const QString &funName)
{
if(funName=="destroy")
qDebug()<<funName;
}
Player.qml
signal queryCppFun(string funName);
function initDestroy(){
queryCppFun("destroy");
}

OK, I know how to do with it.
Just put static in front of Player player;
And do not handle QML items in C++, thanks #folibis

Related

Custom Qt controls in C++

I'm trying to use a custom control in Qt, but don't know how.
My current main code:
int main(int argc, char *argv[]) {
QApplication application(argc, argv);
MainWindow window;
window.setWindowState(Qt::WindowMaximized);
window.show();
return application.exec();
}
MainWindow ui has a QTextEdit and a PushButton. Now, I want to use another control that inherits from QTextEdit.
I've added a CodeEditor class that is taken from the documentation, but it doesn't appear in Qt Creator designer.

Qt C++ connect QPushButton click

I have just started developing using QtGUI and I have checked out some tutorials and documentation, and by what I've read this should work.
#define CONNECT QObject::connect
void test();
QPushButton *lpTestBtn;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtProject w;
w.show();
lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
CONNECT(lpTestBtn, SIGNAL(clicked()),qApp,SLOT(test()));
return a.exec();
}
void test()
{
lpTestBtn->setText("Hi");
}
But test() never gets called. Also, lpTestBtn is not null and is found correctly.
I have tried the following changes
CONNECT(lpTestBtn, SIGNAL(clicked()),qApp->activeWindow(),SLOT(test()));
CONNECT(lpTestBtn, SIGNAL(clicked()),w.window(),SLOT(test()));
I know I can just do QtProject::on_TestBtn_clicked(); but I'd like to get it working using CONNECT,SIGNAL and SLOT.
The test function in your code is not a slot, nor does it belong to the Q(Core)Application class as you seem to have used it.
The best would be is to move that one line in the test function to the connection with the lambda syntax. This will require C++11 support, but that is in quite common use these days.
You would use the new shiny signal-slot syntax. This would spare you some headache for runtime issues in the future because they would appear at compilation-time.
Therefore, you would write something like this:
main.cpp
#include <QMainWindow>
#include <QApplication>
#include <QPushButton>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
// Replace it with "QtProject".
QMainWindow w;
w.show();
QPushButton * lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
QObject::connect(lpTestBtn, &QPushButton::clicked, [=]() {
lpTestBtn->setText("Hi");
});
return a.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Please also note that it is bad idea to create a global pointer for a QPushButton object. It not only leaks the memory, but you could have other issues, too.
1) QApplication doesn't have a test() slot in it. You need to make your own class, inheriting QApplication, and give that class a test() slot. What you've done is create a regular function, which won't help.
2) You didn't check the return value of connect, which means you didn't see that it was giving you an error, which would probably have given you some clues.
You can connect signals to the slots which are in classes derived from QObject so meta compiler can deduce slot calls. But your test() is global function. You have to put your slot function inside a class that derives from QObject and supports Q_OBJECT macro or define a lambda function ( with C++11 support) as Laszlo Papp showed.
Example:
// testwrapper.h
class TestWrapper : public QObject
{
Q_OBJECT
//...
public slots:
void test();
};
// main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtProject w;
w.show();
QPushButton * lpTestBtn = w.window()->findChild<QPushButton*>("TestBtn");
TestWrapper tw;
CONNECT( lpTestBtn, SIGNAL( clicked()),tw,SLOT( test()));
return a.exec();
}

What is the right way to make a class outside main.cpp to use QtQuick2ApplicationViewer?

I want to make a C++ application that uses QML for dialog UI.
I am trying to put my UI code outside main.cpp, so that I can later separate it to run in a thread.
I build & run: No errors in compilation, no errors in application output.
However, nothing shows up on the screen. But if written in main.cpp, this chunk of code shows the QML dialog correctly:
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/Kiosk/main.qml"));
viewer.showExpanded();
What I do:
New Project -> Applications -> Qt Quick 2 Application (Built-in Elements)
I leave main.qml as it is.
I add a new class "Dialog"
Dialog.h code:
#ifndef DIALOG_H
#define DIALOG_H
#include <QObject>
#include "qtquick2applicationviewer.h"
class Dialog : public QObject
{
Q_OBJECT
public:
explicit Dialog(QObject *parent = 0);
void show();
signals:
public slots:
};
#endif // DIALOG_H
Dialog.cpp code:
#include "dialog.h"
Dialog::Dialog(QObject *parent) :
QObject(parent)
{
}
void Dialog::show()
{
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/Kiosk/main.qml"));
viewer.showExpanded();
}
main.cpp code:
#include <QtGui/QGuiApplication>
#include "dialog.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Dialog *dia = new Dialog();
dia->show();
return app.exec();
}
When I switch back to QtQuick 1.0 and replace the chunk of code that uses QtQuick2ApplicationViewer with QDeclarativeView :
view = new QDeclarativeView();
view->rootContext()->setContextProperty("Dialog", this); //this
view->setSource(QUrl("qml/Kiosk/main.qml"));
view->setResizeMode(QDeclarativeView::SizeRootObjectToView);
my QML app displays correctly. But I want to use QtQuick 2.0. I am new to Qt programming, so any help would be highly appreciated. Thank you.
Came across this question while I was looking for resources myself. I think I can shed some light on your issues but am only just getting to grips with QtQuick myself.
in your Dialog::Show() method you are creating a local QtQuick2ApplicationViewer which will be destroyed when the function call ends and hence you won't see anything as it will return immediately.
Also the simplest way I have found to get a qml displaying is to use a QQuickView directly.
e.g.
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QQuickView qtQuickApp;
qtQuickApp.setSource(QUrl("test.qml"));
qtQuickApp.show();
app.connect( &app, SIGNAL( lastWindowClosed() ), &app, SLOT( quit() ) );
app.exec();
return 0;
} // main

Qt push button event using Qt Designer not working: "No such slot QApplication"

I've read several articles about push button events in Qt but none seem to solve my problem. I have a simple GUI built with Qt Designer which only contains one button. The run-time error I get is the following:
Object::connect: No such slot QApplication::FullSizeR() in CameraWindow.h:25
Object::connect: (sender name: 'FullSize')
Object::connect: (receiver name: 'CameraViewer')
FullSizeR() is the function I want called when My button is pushed.
Here's' how main is defined:
int main(int argc, char *argv[]) {
// initialize resources, if needed
// Q_INIT_RESOURCE(resfile);
QApplication app(argc, argv);
CameraWindow cw;
cw.show();
//app.setActiveWindow(&cw);
//cw.getData(); // this paints the window
return app.exec();
}
And this is how CameraWindow is defined:
class CameraWindow : public QDialog{
Q_OBJECT
public:
bool serverConnected;
void getData();
CameraWindow()
{
widget.setupUi(this); //this calls Qt Designer code
//the function bellow produces a run-time error
//access the button via widget.FullSize
connect(widget.FullSize,SIGNAL(clicked()), qApp, SLOT(FullSizeR()));
}
QLabel *imgl;
virtual ~CameraWindow();
protected slots:
void FullSizeR();
private:
Ui::CameraWindow widget;
};
I've properly included QObject and my function definition under 'slots'
This is the definition of FullSizeR:
void CameraWindow::FullSizeR()
{
QMessageBox::information(this,"Button clicked!\n", "Warning");
}
The above doesn't seem to be hard to solve. I know its something simple if I only knew Qt a bit better :-/
Thanks All
connect(widget.FullSize,SIGNAL(clicked()), qApp, SLOT(FullSizeR()));
The error message says it all: qApp doesn't have the slot. You need this:
connect(widget.FullSize, SIGNAL(clicked()), this, SLOT(FullSizeR()));

Qt: QPushButton never shows up

I'm trying to learn Qt, with a fairly simple application:
#include <QtGui/QApplication>
#include <QPushButton>
#include <QDebug>
/* -- header begin {{{ */
class BareBase {
public:
BareBase();
};
class BareBones: public QApplication {
private:
BareBase* base;
public:
BareBones(int &argc, char **argv);
~BareBones();
};
/* -- header end }}} */
/* -- implementation begin {{{ */
BareBase::BareBase()
{
QPushButton hello("Hello world!");
hello.resize(100, 30);
hello.show();
}
BareBones::BareBones(int& argc, char** argv): QApplication(argc, argv)
{
qDebug() << "Creating new instance ... ";
base = new BareBase();
}
BareBones::~BareBones()
{
qDebug() << "Cleaning up ... ";
delete base;
}
/* -- implementation end }}} */
int main(int argc, char **argv)
{
//Q_INIT_RESOURCE(files);
BareBones app(argc, argv);
return app.exec();
}
Now, the problem is that the Button created in BareBase never shows up, and i'm puzzled why?
Your QPushButton is creating and display correctly but go out of scope when leaving BareBase constructor. Using a member variable or a pointer will solve your problem.
If you use a pointer, you should add your button to its parent. By this way the button will be automatically deleted when the parent will be deleted.
QPushButton might have shown up but not in the visible area of the widget. That's why, you should add all your widgets to the Layouts that are available in Qt to obtain the desired behaviour. Check out the docs here... It has examples also...
Also, basically you will be having a base QWidget or most probably QMainWindow on which all your controls will be present.. So, your QPushButton will be in the parent widget.. Your QApplication will contain your application specific information like setting the window, setting the font for your entire application kinda stuff..
Hope it helps..