I am attempting to make a custom TCP widget for QML for my project (WebSocket sends a HTTP request, it doesn't allow me to send raw TCP packets). I created the "TCPSocketConnection" (named in cpp as TCPSocketConn) class and gave it some properties with placeholder methods and tried to insert it into QML. When I tried to use the class, I get the following error
qrc:/qml/qmlwebsocketclient/main.qml:43:9: Cannot assign to non-existent property "onTextMessageReceived"
I have a QML file like this
****************************************************************************/
import QtQuick 2.0
import QtWebSockets 1.0
import Qt.Comm 2.0
Rectangle {
width: 360
height: 360
TCPSocketConnection{
id: socket
url: "ff"
onTextMessageReceived: {
console.log("On Recieve: " + messsage)
}
}
}
The TCPSocketConnection is defined as follows
qmlRegisterType<TCPSocketConn>("Qt.Comm", 2, 0, "TCPSocketConnection");
in tcpsocketconn.h
#ifndef TCPSOCKETCONN_H
#define TCPSOCKETCONN_H
#include <QQuickItem>
class TCPSocketConn : public QQuickItem
{
Q_PROPERTY(QString url READ url WRITE a_1 NOTIFY a_2)
Q_PROPERTY(QString message READ message WRITE a_3 NOTIFY textMessageRecieved)
Q_PROPERTY(int status READ status WRITE a_4 NOTIFY statusChanged)
public:
explicit TCPSocketConn(QQuickItem *parent = 0);
QString url();
QString message();
int status();
signals:
void a_2();
void textMessageReceived();
void statusChanged();
public slots:
void a_1(QString);
void a_3(QString);
void a_4(int);
};
#endif // TCPSOCKETCONN_H
with a placeholder cpp file
#include "tcpsocketconn.h"
TCPSocketConn::TCPSocketConn(QQuickItem *parent) : QQuickItem(parent)
{
}
QString TCPSocketConn::url(){
return "";
}
QString TCPSocketConn::message(){
return "";
}
int TCPSocketConn::status(){
return 0;
}
void TCPSocketConn::a_1(QString d){
}
void TCPSocketConn::a_3(QString d){
}
void TCPSocketConn::a_4(int s){
}
void TCPSocketConn::textMessageReceived(){
}
void TCPSocketConn::statusChanged(){
}
void TCPSocketConn::a_2(){
}
You're missing the Q_OBJECT macro; it's not enough to just derive from a QObject subclass:
The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system.
There's also this paragraph:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the Meta Object Compiler on the source file. We strongly recommend the use of this macro in all subclasses of QObject regardless of whether or not they actually use signals, slots and properties, since failure to do so may lead certain functions to exhibit strange behavior.
This is explained in more detail here.
Related
After integration C++ and QML using the way described here:
QML C++ integration
I have noticed only .h methods are visible outside class (from QML level), I have no access for public variables.
After research I found that:
void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
Is this way proper?
If not, how can I get access to my class public variables from QML level ?
Supposedly I can create functions for this purpose, but I don't like this way.
It looks for me like way around...
In the following example, I wanted to expose the C++ qVersion() from QtGlobal to QML as System.qtVersion.
//System.h
#ifndef System_H
#define System_H
#include <QObject>
class System : public QObject
{
Q_OBJECT
Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT)
public:
System(QObject* parent = nullptr);
QString qtVersion() const;
};
#endif
//System.cpp
#include "System.h"
System::System(QObject * parent) :
QObject(parent)
{
}
QString System::qtVersion() const
{
return qVersion();
}
#endif
```c++
//main.cpp
//...
qmlRegisterSingletonType<System>("qmlonline", 1, 0, "System", [](QQmlEngine*,QJSEngine*) -> QObject* { return new System(); } );
I can access the above in QML with the following snippet:
import QtQuick
import QtQuick.Controls
import qmlonline
Page {
Text {
text: System.qtVersion
}
}
You can try the QML portion online
For other examples of C++ wrappings to QML checkout my GitHub projects:
https://github.com/stephenquan/qt-toolkit
https://github.com/stephenquan/qmlonline6
I want to add C++ class like this notchedrectangle.hpp to QML:
#ifndef NOTCHEDRECTANGLE_HPP
#define NOTCHEDRECTANGLE_HPP
#include <QtQml/qqmlregistration.h>
#include <QQuickPaintedItem>
class NotchedRectangle : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
QML_ELEMENT
public:
NotchedRectangle();
void paint(QPainter* painter) override;
QColor color() const;
void setColor(QColor color);
signals:
void colorChanged();
private:
QColor m_color;
};
#endif // NOTCHEDRECTANGLE_HPP
I have qmake build system, but don't know - what should I add in qmake file.
My filesystem looks like that:
I tried to add to qmake file this strings:
CONFIG += qmltypes
QML_IMPORT_NAME = UI.NR
QML_IMPORT_MAJOR_VERSION = 1
INCLUDEPATH += UI/NotchedRectangle
But they will cause error:
[Makefile.Debug:1175: qlauncher_metatypes.json] Error 1
Can you help me, please?
you should import in qml file after exposing the class:
import UI.NR 1.0
I suggest you to change UI.NR to smth else which has no dot in it.
Then take an instance:
WhatEverYouNamed {
}
QML_IMPORT_NAME is not a name of class!
It's the name of package and must be different.
I use "Custom".
Next you must include class in main.cpp
And finally - you should make Recompile
I have a MainWindow class which is declared in mainwindow.h and defined in mainwindow.cpp respectively like this:
In mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
...
void addNewTab(QString fullFilePath, QString textString="");
public slots:
void disableMenuItem();
...
private:
...
};
In mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
...
connect(this, &MainWindow::addNewTab, this, &MainWindow::disableMenuItem);
...
}
void MainWindow::addNewTab(QString fullFilePath, QString textString)
{
...
}
void MainWindow::disableMenuItem()
{
...
}
Everything compiles and run fine except for the following message on the console:
QObject::connect: signal not found in MainWindow
The message come from the connect call in the constructor above. What does that message mean in my case, and where am I doing wrong?
As drescherjm and Learner mentioned, you forgot to add a signals: section to your header file, and declare your signal within it.
Qt connects signals to slots at runtime, not at compile time, so mis-connected signals and slots cannot be detected until the program is actually run; that's why this problem is reported when it is.
Qt uses the moc preprocessor to turn signals and slots into standard c++, so that's why the signals: and slots: sections of your header will not cause problems when compiling.
Signals are fully defined by moc, so you do not need to define them in your .cpp file, but they still need to be in the header so moc knows to create them.
EDIT:
It appears that you are trying to use a signal with the name of one of your class functions. I don't think that's going to work. the documentation for the new signal/slot syntax indicates that you can connect TO anything, it doesn't have to be a slot, but I believe you still need to define your signal as a signal.
I need to know what am I doing wrong.
I tried researching about it but I can't really find anything that it's related to my case. I am new to QT and debugging signal and slots is kinda technical for me.
What I wanted to do is just simple: make a thread that will continuously send signal to my QProgressBar widget.
Here's my essential code snippets:
thread.h
class MyThread : public QThread
{
public:
MyThread(QWidget * parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
MyThread * test = new MyThread(this);
connect(test,SIGNAL(valueChanged(int)),ui->progressBar,SLOT(setValue(int)));
test->start();
}
thread.cpp
MyThread::MyThread(QWidget * parent)
{
}
void MyThread::run(){
emit valueChanged(10); //for simplicity
}
void MyThread::valueChanged(int value){
}
I only have a single progressBar on my UI and my main is the same as the default.
Anyway, upon running of the code. I kept on getting this no such signal from my thread class. May I know what am I doing wrong?. I would also like to clarify if my understanding is right regarding signals and slots in my own words: it means that the slot will be triggered everytime the signal is called.
I believe the error message is due to a missing Q_OBJECT macro at the top of your MyThread declaration. The documentation at http://doc.qt.io/qt-5/signalsandslots.html explains this is necessary for any class that wants to declare signals and slots.
Change your class definition to:
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QWidget * parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
};
Take a look at the linked documentation, specifically the A Small Example section, for a complete explanation why this is needed.
You must not implement a signal in a .cpp file. MOC will do that and there must only be one implementation.
Just delete this part:
void MyThread::valueChanged(int value){
}
If your code works, that might be luck because the linker throws away the right implementation. You should not rely on that.
I am trying to subclass QEditLine so that I can define a new SIGNAL that sends an object identifier. At the moment, I connect a parent signal to a slot in the new class and from that slot I emits a proper new signal with the additional object identifier.
I cannot understand one thing. The problem is I don't know how to define a new signal function itself. I don't know what I should put there. I mean I know its arguments but I don't know what it shpould do as a function. I am doing this for the first time and it may looks very silly ;p but I really stuck there >.<.
Can anybody please provide some clues. It is probably a very easy problem.
Thanks
// myqeditline.h
#ifndef MYQEDITLINE_H
#define MYQEDITLINE_H
#include <QWidget>
#include <QLineEdit>
#include <QString>
class MyQEditLine : public QLineEdit
{
Q_OBJECT
public:
explicit MyQEditLine(const QString& n, QWidget *parent = 0);
protected:
QString name;
signals:
void textChanged(QString textCHanged, QString sender);
protected slots:
public slots:
void myTextChanged(QString textChanged);
};
#endif // MYQEDITLINE_H
// myqeditline.cpp
#include "myqeditline.h"
MyQEditLine::MyQEditLine(const QString &n, QWidget *parent)
: QLineEdit(parent),name(n) {
connect(this,SIGNAL(textChanged(QString)),this,SLOT(myTextChanged(QString)));
}
void MyQEditLine::myTextChanged(QString textChanged) {
emit textChanged(QString textChanged, QString name);
}
I just realised that the answer to my question is on this Qt Project website, in section regarding "Signals", in 4th paragraph. It says: "Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void)."