HERE IS Qt PROJECT with minimal skeleton to show what is the problem (check console after you run that project)
http://uloz.to/xqxrXpdL/qtproject-zip
I try to call public slot from qml
Component.onCompleted: print(model.activate())
Still getting error:
TypeError: Property 'activate' of object QQmlDMObjectData(0x7fa35dd89eb0) is not a function
If i tried to call the method dynamically from C++, it works:
auto item = new TreeItem<MainMenuItem>(new MainMenuItem("kyklop"));
QMetaObject::invokeMethod(item, "activate");
If i try to access regular property of my TreeItemTemplateBackend class from qml (for instance level), it works, so problem is only if calling method. I am thinking it could be something with that subclass/template class.
Registering to qml:
qmlRegisterType<TreeItemTemplateBackend>("engine.ui", 1, 0, "TreeItemTemplateBackend");
qmlRegisterType<TreeItem<InspectorItem>>("engine.ui", 1, 0, "InspectorTreeItem");
qmlRegisterType<TreeItem<MainMenuItem>>("engine.ui", 1, 0, "MainMenuTreeItem");
TreeItem.h
#ifndef TREEITEM_H
#define TREEITEM_H
#include <QObject>
#include "TreeItemTemplateBackend.h"
template <typename T>
class TreeItem : public TreeItemTemplateBackend
{
public:
explicit TreeItem(QObject * parent = NULL);
explicit TreeItem(T * data, QObject * parent = NULL);
explicit TreeItem(TreeItem<T> & other);
void addChild(TreeItem<T> * child);
~TreeItem() {}
};
#endif // TREEITEM_H
TreeItemTemplateBackend.h
#ifndef TREEITEMTEMPLATEBACKEND_H
#define TREEITEMTEMPLATEBACKEND_H
#include <QList>
#include <QQmlListProperty>
class TreeItemTemplateBackend : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject * data READ data WRITE setData NOTIFY dataChanged)
Q_PROPERTY(QQmlListProperty<TreeItemTemplateBackend> childs READ childs NOTIFY childsChanged)
Q_PROPERTY(int level READ level WRITE setLevel NOTIFY levelChanged)
public:
explicit TreeItemTemplateBackend(QObject * parent = NULL);
QObject * data() const;
void setData(QObject * data);
QQmlListProperty<TreeItemTemplateBackend> childs() const;
void addChild(TreeItemTemplateBackend * child);
int level() const;
void setLevel(int level);
void dump(QString propertyName) const;
~TreeItemTemplateBackend() {}
signals:
void activated();
void dataChanged();
void childsChanged();
void levelChanged();
public slots:
void activate(); // this is what i am trying to call
protected:
QObject * m_data;
QList<TreeItemTemplateBackend *> m_children;
int m_level;
static void append_function(QQmlListProperty<TreeItemTemplateBackend> * property, TreeItemTemplateBackend * item);
static TreeItemTemplateBackend * at_function(QQmlListProperty<TreeItemTemplateBackend> * property, int index);
static void clear_function(QQmlListProperty<TreeItemTemplateBackend> * property);
static int count_function(QQmlListProperty<TreeItemTemplateBackend> * property);
};
#endif // TREEITEMTEMPLATEBACKEND_H
QQmlDMObjectData is a wrapper for the actual object used in delegates. The original object is accessible via the property modelData, so model.modelData.activate() should work.
If you cal for it "method" and still you are use it as a method so convert it to the method:
...
public:
void Q_INVOKABLE activate();
...
Related
I am writing my first application in Qt4, basically using the books of Blanchette/Summerfield andSams 24 hours, and a lot of Qt search on internet.
my actual call is:
connect( thumbNailView,
SIGNAL(leftClicked(QListWidgetItem *)),
leftKeypointList,
SLOT(openItem(QListWidgetItem *)));
which gives the following error:
"no matching function for call to DAPPMainWindowWidget::connect(DAPPListWidget*&, const char [32], DAPPKeypointList*&, const char [29])"
I also connected this signal to another object which works flawless:
connect( thumbNailView,
SIGNAL(leftClicked(QListWidgetItem *)),
leftImage,
SLOT(openItem(QListWidgetItem *)));
Both leftImage and leftKeypointList are pointers to objects to a standard QWidget and and a custom object DAPPKeypointList : public QList with DAPPKeypoint holding index and position
of the keypoint.
My idea is that I cannot simply pass a pointer to QList sort of object the same way as I do a pointer to a standard Qwidget.
below follow:
in my DAPP.h
private:
DAPPKeypointList * leftKeypointList;
DAPPKeypointList * rightKeypointList;
and classes:
class DAPPKeypoint {
public:
DAPPKeypoint();
~DAPPKeypoint();
QPoint getKeypointPos();
void setKeypointPos(QPoint);
int getKeypointIndex();
void setKeypointIndex(int);
private:
QPoint keypointPos;
int keypointIndex;
};
class DAPPKeypointList : public QList<DAPPKeypoint> {
Q_OBJECT
public: DAPPKeypointList();
~DAPPKeypointList();
private slots:
void openItem(QListWidgetItem *);
};
in my cpp files:
DAPPKeypoint.cpp
#include "DAPP.h"
DAPPKeypoint::DAPPKeypoint(){}
DAPPKeypoint::~DAPPKeypoint(){}
QPoint DAPPKeypoint::getKeypointPos(){ return keypointPos; }
void DAPPKeypoint::setKeypointPos(QPoint kpPos){ keypointPos = kpPos; }
int DAPPKeypoint::getKeypointIndex(){ return keypointIndex; }
void DAPPKeypoint::setKeypointIndex(int kpIndex){ keypointIndex = kpIndex; }
DAPPKeypointList.cpp: (for the moment just a template ...)
#include "DAPP.h"
DAPPKeypointList::DAPPKeypointList(){}
DAPPKeypointList::~DAPPKeypointList(){}
void DAPPKeypointList:: openItem(QListWidgetItem *) {}
And DAPPMainWindowWidget.cpp :
Parts that are relevant (if you need more, let me know, but I think this is sufficient to have an idea of the problem):
leftKeypointList = new DAPPKeypointList;
rightKeypointList = new DAPPKeypointList;
leftImage = new DAPPImageWidget(leftImageLabel);
connect(thumbNailView,SIGNAL(leftClicked(QListWidgetItem *)) ,leftKeypointList ,SLOT(openItem(QListWidgetItem *)));
connect(thumbNailView,SIGNAL(leftClicked(QListWidgetItem *)) ,leftImage ,SLOT(openItem(QListWidgetItem *)));
Started using QtRO and generated files inherently complain about vtable:
#ifndef REP_REMOTEEXAMPLE_H
#define REP_REMOTEEXAMPLE_H
// This is an autogenerated file.
// Do not edit this file, any changes made will be lost the next time it is generated.
#include <QtCore/qobject.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmetatype.h>
#include <QtRemoteObjects/qremoteobjectnode.h>
#include <QtRemoteObjects/qremoteobjectpendingcall.h>
#include <QtRemoteObjects/qremoteobjectreplica.h>
class remoteExampleReplica : public QRemoteObjectReplica
{
Q_OBJECT
Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "remoteExample")
Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, "5e40a606abdd95f709878d419edaa735fce25d0d")
public:
remoteExampleReplica() : QRemoteObjectReplica() { initialize(); }
static void registerMetatypes()
{
static bool initialized = false;
if (initialized)
return;
initialized = true;
}
private:
remoteExampleReplica(QRemoteObjectNode *node, const QString &name = QString())
: QRemoteObjectReplica(ConstructWithNode)
{
initializeNode(node, name);
}
void initialize() override
{
remoteExampleReplica::registerMetatypes();
QVariantList properties;
properties.reserve(0);
setProperties(properties);
}
public:
virtual ~remoteExampleReplica() {}
Q_SIGNALS:
void Close(QString a);
void Open(QString b);
public Q_SLOTS:
void onClosed()
{
static int __repc_index = remoteExampleReplica::staticMetaObject.indexOfSlot("onClosed()");
QVariantList __repc_args;
send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
}
void onOpened()
{
static int __repc_index = remoteExampleReplica::staticMetaObject.indexOfSlot("onOpened()");
QVariantList __repc_args;
send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
}
private:
friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);
};
#if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
#endif
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
#endif // REP_REMOTEEXAMPLE_H
The issue points to the private constructor. I only included the replica header in my code without really using the remote object as a test run. I've read a lot about vtables how they work and when the linker complains about the vtable but in this case, with the private constructor, I'm not sure what the issue is. Am I missing an implementation of the remote object? Did I not generate the files correctly?
.rep:
class remoteExample
{
SIGNAL(Close(QString a));
SIGNAL(Open(QString b));
SLOT(onClosed());
SLOT(onOpened());
};
I have a little problem with the Qt class QGraphicsScene:
To detect the current mouse coordinates I made a new class QGraphicsScenePlus with QGraphicsScene as the base class. I have already redefined the slot function mouseMoveEvent(QGraphicsSceneMouseEvent* event) and the received coordinates seem to be correct. Now I want to notify the parent QMainWindow class, where the QGraphicsScenePlus object is stored, whenever the mouse coordinates change. What is the best way to do this? I already tried to define signals and slots, but it didn't work. The slot function wasn't found during the execution of the program.
Here is the code so far:
qgraphicssceneplus.h
#ifndef QGRAPHICSSCENEPLUS_H
#define QGRAPHICSSCENEPLUS_H
#include <QObject>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
class QGraphicsScenePlus : public QGraphicsScene {
public:
QGraphicsScenePlus(QObject* parent = 0);
public slots:
void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
public:
int mx = 0;
int my = 0;
};
#endif // QGRAPHICSSCENEPLUS_H
qgraphicssceneplus.cpp
#include "qgraphicssceneplus.h"
QGraphicsScenePlus::QGraphicsScenePlus(QObject* parent) : QGraphicsScene(parent) {
}
void QGraphicsScenePlus::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
mx = mouseEvent->scenePos().x();
my = mouseEvent->scenePos().y();
this->update();
}
Comment
I am not sure how you made the above code compiled.
1. Even though you subclass from a QObject, you still need the Q_OBJECT macro to keep meta-object compiler informed:
class QGraphicsScenePlus : public QGraphicsScene {
Q_OBJECT // <--- You miss this
public:
QGraphicsScenePlus(QObject* parent = 0);
2. It's not allowed to assign primitive value in C++ class definition, do it in the constructor instead:
public:
int mx /*= 0*/;
int my /*= 0*/;
};
Solution
As for your question:
What is the best way to do this? I already tried to define signals and slots, but it didn't work.
The best way is still Signals & Slots.
Code
qgraphicssceneplus.h
class QGraphicsScenePlus : public QGraphicsScene {
Q_OBJECT
public:
QGraphicsScenePlus(QObject* parent = 0);
public slots:
void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
signals:
void sendCoord(int,int); // for sending the information of coordinates
public:
int mx;
int my;
};
qgraphicssceneplus.cpp
QGraphicsScenePlus::QGraphicsScenePlus(QObject* parent) : QGraphicsScene(parent) {
mx = 0;
my = 0;
}
void QGraphicsScenePlus::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
mx = mouseEvent->scenePos().x();
my = mouseEvent->scenePos().y();
emit sendCoord(mx, my); // emit the signal
this->update();
}
To catch the signal, define the slot in QMainWindow. For example:
public slots:
void receiveCoord(int x, int y);
and connect it to the signal of your graphic scene.
Demo
What do I have to implement to make my own boolean widget for use with QDataWidgetMapper?
I have created a USER property that the mapper is, to my understanding, supposed to use.
The interaction with the database via QSqlTableModel using the (same) QDataWidgetMapper works with qt's own widgets, but does not seem to work with this widget I created.
Even though the widget works and displays database data, changing widget value does not change the value in the database. [correction: data from database is read to the widget state ok.]
Current header file:
#ifndef COMPENSATIONCONTROLCHECKABLE_H
#define COMPENSATIONCONTROLCHECKABLE_H
#include <QAbstractButton>
#include <QWidget>
namespace Ui {
class CompensationControlCheckable;
}
class CompensationControlCheckable : public QAbstractButton
{
Q_OBJECT
Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY compensationChanged USER true )
public:
explicit CompensationControlCheckable(QWidget *parent = 0);
~CompensationControlCheckable();
void setChecked(bool checkd);
const bool isChecked() const;
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
private slots:
void on_startCompensation_clicked();
void on_cancelCompensation_clicked();
signals:
void compensationChanged(bool);
void checked(bool);
private:
bool checkedValue;
Ui::CompensationControlCheckable *ui;
};
#endif // COMPENSATIONCONTROLCHECKABLE_H
Version 2, now I have removed checked overrides and instead call the QAbstractButton setChecked and isChecked in setCompensation and isCompensation, respectively. The constructor calls setCheckable(true);. This works exactly as above; reading from db ok, writing to db does not work:
#ifndef COMPENSATIONCONTROLCHECKABLE_H
#define COMPENSATIONCONTROLCHECKABLE_H
#include <QAbstractButton>
#include <QWidget>
namespace Ui {
class CompensationControlCheckable;
}
class CompensationControlCheckable : public QAbstractButton
{
Q_OBJECT
Q_PROPERTY(bool compensation READ isCompensation WRITE setCompensation NOTIFY compensationChanged USER true )
public:
explicit CompensationControlCheckable(QWidget *parent = 0);
~CompensationControlCheckable();
void setCompensation(bool checkd);
bool isCompensation() const;
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
private slots:
void on_startCompensation_clicked();
void on_cancelCompensation_clicked();
signals:
void compensationChanged(bool);
private:
bool compensationValue;
Ui::CompensationControlCheckable *ui;
};
#endif // COMPENSATIONCONTROLCHECKABLE_H
QDataWidgetMapper prefers to use the property with USER true for its mapping but there already one called checked in QAbstractButton use that property instead. You may need to call isCheckable(true) in the constructor;
Can you explain a methods for storing program data with global access ?
I found these keywords:
- using static class to store data
- pass QList by value
- pass Qlist by reference
- use 'friend' keyword
but I cannot find any real example of storing global QList, as they say, it is a bad design to use global variables. Also there is a mention that using pointers on a QList is a bad idea because of implicit sharing (?).
So where should I store my Qlist for accessing it from a different class in an other .cpp ? So I have:
mainwindow.h
QList <SceneCard> sceneList;
QString mTitle;
public slots:
QString setValue()
{
return mTitle;
}
mainwindow.cpp
MainWindow::AddScene()
{
sceneCard = new SceneCard(sNumber);
sceneList.append(sceneCard);
mTitle = "Nejat is right!"
}
void MainWindow::showSceneCard()
{
SceneDialog D;
connect(D,SIGNAL(getValue()),this,SLOT(setValue()));
D.exec();
}
scenedialog.h
#ifndef SCENEDIALOG_H
#define SCENEDIALOG_H
#include <QDialog>
#include <QList>
namespace Ui {
class SceneDialog;
}
class SceneDialog : public QDialog
{
Q_OBJECT
public:
SceneDialog(QWidget *parent = 0);
~SceneDialog();
signals:
QString getValue();
private:
Ui::SceneDialog *ui;
QString myText;
};
scenedialog.cpp
#include "scenedialog.h"
#include "ui_scenedialog.h"
#include <QDebug>
SceneDialog::SceneDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SceneDialog)
{
ui->setupUi(this);
myText = getValue();
qDebug() << myText; // myText is empty!!
}
You can put your list as a class member and use Qt's Signal/slot mechanism to access the list from other classes. Just make a signal in the target class, connect it to a slot in the class containing the list and make a connection between two objects of the classes. This way you can access any data member of other classes by connecting a signal to a slot returning that value and just emitting the signal and getting the return value.
For example if you have two classes like :
class A: public QObject
{
Q_OBJECT
public:
A(QObject *parent = 0);
~A();
signals:
int getValue();
private:
void someFunction()
{
int val = getValue();
}
};
class B
{
Q_OBJECT
public:
B(QObject *parent = 0);
~B();
public slots:
int getValue()
{
return someValue;
}
};
And connect the signal from an object of A to the slot in an object of B :
connect(a, SIGNAL(getValue()), b, SLOT(getValue()));
In class A you can access the value returned from getValue slot in B by just calling the signal and using the returned value.
Note that the two objects should be in the same thread for this to work. If they are in different threads then the connection type should be of type Qt::BlockingQueuedConnection :
connect(a, SIGNAL(getValue()), b, SLOT(getValue()), Qt::BlockingQueuedConnection);
Another way is two use static class members but it is not recommended unless you have a good reason to do it. If you have two classes like :
class A {
public:
static QList<int> list;
};
class B {
public:
void do_something();
};
You can access A's static data member from B like this:
void B::do_something()
{
int val = A::list[0];
...
};