I'm a noob - not good with QML or C++ yet, but getting there. I seem to have hit a stumbling block I can't get past. I'm receiving the following error in my attempt to run a build and I'm not sure what I missed in my code...
**QObject::connect: Cannot connect (null)::buttonClicked_enable() to TLA_Funcs::sys_enable()
**
I've looked through the other versions of the question here and it seems that I have my code correct, but I still get the error. Can someone take a peek? Here's the relevant sample of my code (the rest is too long and I left out the guts of the function - too long).
QML Code:
Rectangle {
id: main
width: 800
height: 600
color: "#abcfe9"
border.width: 4
border.color: "#000000"
signal buttonClicked_enable()
Button {
id: enable
x: 628
y: 55
text: "ENABLE"
onClicked:buttonClicked_enable()
}
//....
}
My class header:
#ifndef TLA_FUNCS_H
#define TLA_FUNCS_H
#include <QObject>
class TLA_Funcs : public QObject
{
Q_OBJECT
public:
explicit TLA_Funcs(QObject *parent = 0);
signals:
public slots:
Q_INVOKABLE void sys_enable(){return ;}
private:
};
#endif
And in my main.cpp file:
#include "TLA_Funcs.h"
TLA_Funcs::TLA_Funcs(QObject *parent) :
QObject(parent)
{
}
int main (int argc, char*argv[]) {
QGuiApplication app(argc, argv);
QQuickView *view = new QQuickView(QUrl("main.qml"));
view->show();
QQuickItem *item = view->rootObject();
TLA_Funcs *funcs = new TLA_Funcs();
QObject::connect(item, SIGNAL(buttonClicked_enable()), funcs, SLOT(sys_enable()));
}
I've defined the signals in the parent rectangle, and in the button code I've tried using:
onClicked:main.buttonClicked_enable()
as well as:
onClicked: {
buttonClicked_enable()
TLA_Funcs.sys_enable()
}
That didn't help either. I also tried defining the functions under "signal" in the class, but that made more of a mess. Can someone at least point me in the right direction, and keep in mind, I'm still a noob... Thanks All!!!
Problem Solved: there was an error in the .pro file. I copied the code into a new project and it worked correctly 100%. Thanks all for the help!
Related
Hi i have bee playing recently with Qt for mobile development. I started simple using all the code in C++ (given that I have more experience with it) and now I'm starting to use QML. In my app I have a QQuickWidget in the ui where I display a map. The goal is simple to center the map every time the phone emits the coordinates.
This is how I set up my QML
ui->quickWidget->setSource(QUrl("qrc:/geom_map.qml"));
and this is my QML file
Rectangle {
width: 300
height: 300
visible: true
Plugin {
id: osmPlugin
name: "esri"
// specify plugin parameters if necessary
// PluginParameter {
// name:
// value:
// }
}
Map {
id: map
anchors.fill: parent
plugin: osmPlugin
center: QtPositioning.coordinate(51.0, -114.0)
zoomLevel: 10
activeMapType: map.supportedMapTypes[1] // This selects the type of map to display
}
I declared a class to handle the sending of the coordinates to the QML and setup a connection on the QML for receiving the signal
#ifndef COORDUPDATE_H
#define COORDUPDATE_H
#include <QObject>
#include <QVariant>
class coordUpdate : public QObject
{
Q_OBJECT
public:
explicit coordUpdate(QObject *parent = nullptr);
// Q_INVOKABLE void sendupd(double xcoord, double ycoord);
private:
signals:
void sendCoord(QVariant xcoord,QVariant ycoord);
private slots:
public slots:
void sendupd(double xcoord, double ycoord);
};
#endif // COORDUPDATE_H
#include "coordupdate.h"
#include <QDebug>
coordUpdate::coordUpdate(QObject *parent) :
QObject(parent)
{
}
void coordUpdate::sendupd(double xcoord,double ycoord){
emit sendCoord(xcoord,ycoord);
qDebug() << "signal emitted";
}
The problem I'm having is that if I call
void MainWindow::setGPSLocation(QGeoPositionInfo geoPositionInfo)
{
statusBar()->showMessage("Updating position...",1000);
QString text="Location=unknown";
if (geoPositionInfo.isValid())
{
// get the current location coordinates
QGeoCoordinate geoCoordinate = geoPositionInfo.coordinate();
// transform coordinates to lat/lon
qreal latitude = geoCoordinate.latitude();
qreal longitude = geoCoordinate.longitude();
qreal altitude = geoCoordinate.altitude();
double lon = longitude;
double lat = latitude;
//on position updated we also need to record the data
coordUpdate upd;
ui->quickWidget->rootContext()->setContextProperty("updcoord",&upd);
ui->quickWidget->setSource(QUrl("qrc:/geom_map.qml"));
upd.sendupd(longitude,latitude);
qDebug() << "reading coordinates" << longitude << latitude;
}
}
Then the coordinates get updated but the whole thing gets refreshed. Is there a better way to update the information sent to the QML file? I know I would better developing in QML exclusively but I very interested in the use of QQuickWiget for the time being.
I'm not asking how to connect a signal from C++ to QML. The code does that. What I was asking was how to properly update the map with the information passed. I already read the documentation. Unfortunately not much of the documentation focus on QQuickWidgets but rather have a main class instantiated with QQmlEngine.
As described here http://doc.qt.io/qt-5/qtqml-cppintegration-overview.html, you have basically three ways to integrate C++ with QML code :
Expose your C++ class to QML ( properties, signals, slots..) and register it as an instanciable QML type
Same as 1 but register it as a singleton type so it is instantiated by the QML engine, not explicitly in the QML code
Same as 1 but make it available to QML via context properties for example, in this case, you create the instance of your class on the C++ side of your application
Solved it by moving the Connections inside the Map and redefining in the mainwindow.cpp and mainwindow.h the way the QML is instantiated. That way the map is refreshed properly every time the QML captures the signal.
Added to mainwindow.cpp
private:
coordUpdate *upd;
Changed
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->startU->setDisabled(true);
setupLogging();
setupGPS();
coordUpdate upd;
ui->quickWidget->rootContext()->setContextProperty("updcoord",upd);
ui->quickWidget->setSource(QUrl("qrc:/geom_map.qml"));
}
to
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->startU->setDisabled(true);
setupLogging();
setupGPS();
upd = new coordUpdate;
ui->quickWidget->rootContext()->setContextProperty("updcoord",upd);
ui->quickWidget->setSource(QUrl("qrc:/geom_map.qml"));
}
and in the QML
Rectangle {
width: 300
height: 300
visible: true
Plugin {
id: osmPlugin
name: "esri"
}
Map {
id: map
anchors.fill: parent
plugin: osmPlugin
// center: QtPositioning.coordinate(y, x)
zoomLevel: 15
activeMapType: map.supportedMapTypes[1] // This selects thetype of mapa to display
MapCircle {
id:circle
center: QtPositioning.coordinate(y, x)
radius: 50
color: 'red'
}
// Create connections with c++
Connections // Define actions for custom slots
{
id:cppConnection
target: updcoord
onSendCoord: {
// To access signal parameter, name the parameter
console.log("signal received",ycoord,xcoord)
circle.center = QtPositioning.coordinate(ycoord,xcoord)
}
}
}
}
Qt QML, they do work, but no intellisense in QML references. Can I achieve intellisense?
pragma Singleton
import QtQuick 2.0
import QtQuick.Window 2.3
Item {
property int iMode: 0
property bool bSwapLeftRight: false
Registering it:
qmlRegisterSingletonType(QUrl(QLatin1String("qrc:/GlobalSettings.qml")), "ncs.global", 1, 0, "SingletonSettings" );
Second example;:
ctxt->setContextProperty("someModel", QVariant::fromValue(ownModel));
ctxt->setContextProperty("globalControl", QVariant::fromValue(globalControl.Get()));
First one i achieve IntelliSense in QML whilst using, the second one is the singleton, I do not achieve IntelliSense. Planning to expose some c++ defined enums to QML through this one, but looses value when no IntelliSense is provided..
Question is basically, do Qt Quick and Creator support IntelliSense for singleton classes ? Worthwhile investigating further?
Adding some more details, main question is NOT about enum's, but IntelliSense (auto-complete):
A few snippets:
main.cpp:
//Regular Pointer
SomeModel* ownModel = new SomeModel();
//Custom Singleton implementation
GlobalControlSP globalControl = GlobalControl::GetInstance();
//I did not really want this line. GlobalControl should be singleton, how would this be threated?
qmlRegisterType<GlobalControl>("ncs.global", 1, 0, "Global");
//Registering a "Pragma Singleton" file, Intellisense do not work
qmlRegisterSingletonType(QUrl(QLatin1String("qrc:/GlobalSettings.qml")), "ncs.global", 1, 0, "SingletonSettings" );
QQmlApplicationEngine engine;
QQmlContext* ctxt = engine.rootContext();
//Regular context property, not singleton. Intellisense works
ctxt->setContextProperty("ownModel", QVariant::fromValue(ownModel));
//Registering the singleton as context property, Intellisense do not work
ctxt->setContextProperty("globalControl", QVariant::fromValue(globalControl.Get()));
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
globalcontrol.h:
class GlobalControl : public QObject,
{
Q_OBJECT
Q_PROPERTY(QString backcolor READ backcolor NOTIFY backcolorChanged)
....
public:
GlobalControl(QObject *parent = nullptr);
QString backcolor() const { return m_backColor; }
....
enum EnButton
{
DEVICE_START,
DEVICE_IR,
.....
};
Q_ENUM(EnButton)
public slots:
void changeMode(int mode);
void buttonPressed(int button);
some qml file:
//This implementation works:
NcsButton {
property int valuent
id:ir
text: qsTr("IR")
width: 66 * widthScaling
Layout.row: 4
Layout.column: 1
fontColor: bIr ? valueColor : textColor
onClicked: {
globalControl.buttonPressed(Global.DEVICE_IR)
//This does not work:
NcsButton {
id:ir
text: qsTr("IR")
width: 66 * widthScaling
Layout.row: 4
Layout.column: 1
fontColor: bIr ? valueColor : textColor
onClicked: {
globalControl.buttonPressed(globalControl.DEVICE_IR)
Solution or workaround:
For QML defined singleton, add to Qt compiler QML library a generated file
..\..\..\bin\qmlplugindump -relocatable ncs.global 1.0 > plugins.qmltypes
For c++ registered singleton, make a "fake" pointer of normal class type. Register. To retrieve the enum from same singleton class, create a UncreatableType:
GlobalControlSP globalControlOrig = GlobalControl::GetInstance();
GlobalControl* globalControl = globalControlOrig.Get();
ctxt->setContextProperty("globalControl", QVariant::fromValue(globalControl));
qmlRegisterUncreatableType<GlobalControl>("ncs.global", 1, 0, "Global", "Singleton");
this is the first time i write in this site, I'm trying approach me at Qt-creator but I've a problem:
I want to delete the text of the label when the user click a button, i've tried some solution but without success
this is the code:
struct finestra{
float costo;
int altezza;
int larghezza;
QString text;
QString costoStr;
};
float Totale=0;
finestra vet[21];
int i=1;
//SOME CODE
Totale+=vet[i].costo;
vet[i].costoStr = QString::number(vet[i].costo);
vet[i].text = vet[i-1].text + "Finestra ad un anta bianca <br>" + "€" + vet[i].costoStr +"<br>";
ui->TotaleFinestre->setText(QString(vet[i].text));
i++;
I've tried with this function:
void preventivi::on_pushButton_clicked()
{
ui->TotaleFinestre->clear();
}
if someone know how to do please answer,
thanks to all and sorry for my bad english.
Maybe you should try
void preventivi::on_pushButton_clicked()
{
ui->TotaleFinestre->setText("");
}
As QLabel define the slot void QLabel::clear(), you can also just connect this slot with the clicked() signal that will be emitted after a click on your pushButton, using the QObject::connect method :
QObject::connect(pointer_to_your_pushButton, SIGNAL(clicked()), pointer_to_your_label, SLOT(clear()));
EDIT : Here is a small example
The UI is a QWidget that has a QLabel and a QPushButton. I did that with Qt Designer but it doesn't matter here.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QObject::connect(ui->pushButton, SIGNAL(clicked()), ui->label, SLOT(clear()));
}
Widget::~Widget()
{
delete ui;
}
You can even do that using "Edit Signals/Slots" inside Qt Designer and make the signal/slot connection between your widgets. ( you won't need to manually call the previous QObject::connect, as it will be done automatically inside the Ui_Widget class, generated by the uic)
Or you can do all without Qt Designer, it's up to you.
Hope this helps.
Threaded renderer is not working in the following code. I'm using Qt 5.4 on Arch linux-3.14 with proprietary drives.
---------- mytext.h -----------
#include <QObject>
class Thing : public QObject {
Q_OBJECT
Q_PROPERTY(int qm_no READ qm_no NOTIFY qm_noChanged)
public:
Q_INVOKABLE void loop();
int qm_no();
signals:
void qm_noChanged();
private:
int m_no;
};
---------- mytext.cpp ----------
#include "mytext.h"
#include <unistd.h>
int Thing::qm_no() {
return m_no;
}
void Thing::loop() {
while(true) {
m_no += 1;
emit qm_noChanged();
usleep(1000000);
}
}
--------- main.cpp -----------
#include <QQmlContext>
#include <QQuickView>
#include <QGuiApplication>
#include <QtQml>
#include "mytext.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Thing myTh;
QQuickView view;
view.rootContext()->setContextProperty("qmyTh",&myTh);
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
return app.exec();
}
------- main.qml ----------
import QtQuick 2.0;
Rectangle {
id: root
width: 200
height: 200
property var name: "test"
Text {
anchors.fill: parent
text: name
}
MouseArea {
anchors.fill: parent
onClicked: {
qmyTh.loop()
}
}
Connections {
target:qmyTh
onQm_noChanged: {
name = qmyTh.qm_no;
}
}
}
Explanation::
There is a classes Thing , with its object myTh. The function of class Thing is to provide an invokable function which here is loop. This function will then continuously update the m_no value and emit signal. Now the question is that how can I update the Text (name property) while the infinite loop is running which keeps on updating the value to be displayed ?
The code is correct for what concerns the QML part (now) and it works correctly. What is not correct is the C++ implementation. if you remove the while loop, leaving its content, and execute your code you'll see that the text is correctly updated.
The reason of such behaviour should be researched in the Qt quick render implementation. On certain platforms the render is not threaded by default. I guess you are working on Windows (see "Qt Quick" here). Hence, in a not threaded setting, by updating the variable and then sleeping, you are blocking the whole application, preventing the gui update.
You can use a QTimer to schedule the method execution at intervals, or set up a QML Timer for the exact same purpose.
Also, you don't need to save the new value in a temp variable (especially a var one which adds useless checks in this case). By setting an id inside the Text element you can directly set the text property. Here the revisited code:
import QtQuick 2.0;
Rectangle {
id: root
width: 200
height: 200
Text {
id: myText // the id!
anchors.fill: parent
text: "dummy" // dummy text || left empty || use "qmyTh.qm_no" (ensure a correct value is returned at creation time)
}
MouseArea {
anchors.fill: parent
onClicked: {
qmyTh.loop()
}
}
Connections {
target:qmyTh
onQm_noChanged: myText.text = qmyTh.qm_no // text directly set!
}
}
EDIT
It seems like the used render is threaded, hence my reasoning does not apply. There should be other problems. You can try to track down the problem exploiting the debugger and by adding console.info(...) statements in the JS handlers. Searching for the problem could be useful to track (possible) bugs in the libraries.
Depending on the background processing you have to run, I still think that using timers wouldn't be that bad. It really, truly depends on what you want to achieve. However, if you want to try threads, Qt documentation is full of explanations (as usual).
Have a look at this, this
and also absolutely this. Mind that a "moved" object (see the links) cannot be registered as a context property so you have to use one of the other ways to work with threads in a QML project.
I'm learning the signals/slots in Qt and I have found a problem. I need to create my own slot that is called when items on QGraphicsScene (in QGraphicsView) are moved or selected.
I'm starting with a simple app that has one widget and on it is graphicsView and label. I've created a slot in my window and connected it to QGraphicsScene's signal, but it is not being used. Where is my mistake?
Here is the code:
//MainWindow.h
//as generated by QtCreator, just added one slot to it
...omitted for brevity...
public slots:
void selectedItemChanged(QGraphicsItem * newItem, QgraphicsItem * oldItem);
..omitted for brevity...
//------------------------------------------------------------------
//MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene * scene = new QGraphicsScene();
scene->setBackgroundBrush (QBrush(Qt::gray));
ui->graphicsView->setScene (scene);
for(int x = 10; x < 250; x+=20)
{
QGraphicsEllipseItem * item = scene->addEllipse (x,x,5,5,QPen(Qt::darkGreen),QBrush(Qt::darkGreen));
item->setFlag (QGraphicsItem::ItemIsFocusable,true);
}
QObject::connect (scene,SIGNAL(focusItemChanged),this,SLOT(selectedItemChanged));
}
void MainWindow::selectedItemChanged (QGraphicsItem *newItem, QGraphicsItem *oldItem)
{
qDebug()<<"called";
if(newItem == 0)
{
ui->label->setText ("Není vybrán bod");
}
else
{
ui->label->setText (QString::number (newItem->scenePos ().x ()) + "," + QString::number (newItem->scenePos ().y ()));
}
}
Now, when I run the probram it rins ok, but I cannot set Focus on the circles(ellipses) drawn on the scene and the slot is not used. I tried setting IsSelectable flag, but it does not help. Is there any other preferred way to get this done or solution to my problem?
You're not linking against the signal's right signature, according to the documentation:
void QGraphicsScene::focusItemChanged( QGraphicsItem * newFocus, QGraphicsItem * oldFocus,
Qt::FocusReason reason)
and also notice that you can check the connection's success/failure status via the bool return type of the QObject::connect method
So, in the end i found the answer to my own question. It was a mistake on my side.
in the connect() i used the slots without parenthesis/parameters. It should have looked like:
QObject::connect (scene,
SIGNAL(focusItemChanged(QGraphicsItem*,QGraphicsItem*,Qt::FocusReason)),
this,
SLOT(selectedItemChanged(QGraphicsItem*,QGraphicsItem*)));