Simple line drawing by using a paint object
-
Hi all,
I have a container.qml view and a container.cpp class, with his header container.h. I want draw a simple line in the qml view, but this time I want do it by using a paint object I already created in container.cpp class. Unfortunately doesn't work; I think, I have done some mistake by connecting the cpp class to the qml view.The class line should be correct:
#include "container.h" #include <QPainter> class DrawElement : public QQuickPaintedItem { void paint(QPainter *painter) { QBrush brush(Qt::cyan); painter->setBrush(brush); painter->setPen(Qt::NoPen); painter->setRenderHint(QPainter::Antialiasing); painter->drawLine(0, 0, 200, 200); } };
This is the container.h code:
#ifndef CONTAINER_H #define CONTAINER_H #include <QQuickPaintedItem> #include <QObject> class container : public QQuickPaintedItem { public: container(); void paint(); }; #endif // CONTAINER_H
And this is the container.qml code (if I try to import here the container.h file, I receive an error about "no such directory"):
import QtQuick 2.0 Window { width: 640 height: 480 visible: true title: qsTr("Container page") Rectangle{ height: 50 width: 100 color: "#ffffff" } }
I tried to be more detailed as possible, could someone tell me please why I can't import the desired c++ class into my QML? Thank you very much
-
@Shadow-01 said in Simple line drawing by using a paint object:
could someone tell me please why I can't import the desired c++ class into my QML?
Because you have to register it before.
There are 2 way to do it:- with
QML_ELEMENT
(Qt 5.15 or higher required) => https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html - with
qmlRegisterType()
(any Qt version)=> https://qmlbook.github.io/ch18-extensions/extensions.html
- with
-
First of all, thanks for your link. I choosen the first solution. In the link you sent me I understand almost all and all is done as indicated except the point 3: if I add the indicated lines, I see an error. I think, the reason is that my app is done in cmake and not qmake, so the project file is a little bit different. To be totally clear, I sent below my project file in order to ask, how can I edit it in order to make visible also my "container" class? Thanks!
cmake_minimum_required(VERSION 3.14) project(myApp VERSION 0.1 LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 COMPONENTS Core Quick REQUIRED) find_package(Qt6 COMPONENTS Core Quick REQUIRED) set(PROJECT_SOURCES main.cpp qml.qrc home.h home.cpp container.h container.cpp ) qt_add_executable(myApp MANUAL_FINALIZATION ${PROJECT_SOURCES} ) target_compile_definitions(myApp PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>) target_link_libraries(myApp PRIVATE Qt6::Core Qt6::Quick) set_target_properties(myApp PROPERTIES QT_QML_MODULE_VERSION 1.0 QT_QML_MODULE_URI me.myApp ) list(APPEND QML_IMPORT_PATH .) qt6_qml_type_registration(myApp) qt_import_qml_plugins(myApp) qt_finalize_executable(myApp)```
-
@Shadow-01 said in Simple line drawing by using a paint object:
This should be change
set_target_properties(myApp PROPERTIES QT_QML_MODULE_VERSION 1.0 QT_QML_MODULE_URI me.myApp ) qt6_qml_type_registration(myApp) qt_import_qml_plugins(myApp)
to
set_target_properties(container PROPERTIES QT_QML_MODULE_VERSION 1.0 QT_QML_MODULE_URI me.myApp ) qt6_qml_type_registration(container)
And in your QML:
import me.myApp // container should be available
As side note: C++ class name should be UpperCamelCase to be Qt naming convention comform. The class name should be Container and not container.
EDIT: I never use cmake, so I am not 100% sure of this. I don't know if
QML_ELEMENT
is good integrated incmake
or if it only works withqmake
.If it don"t work, I would recommand you to prefere
qmlRegisterType()
which always works:- with all Qt version
- with all build systems.
-
Ok, thanks, I already solved it. It's only enough to import the class name in the project sources list and nothing else. The mistakes appeared because I searched also to import the single class.
Now, a big part of the question is solved and what I need now is: how can I create inside a paint function a line drawing?
-
@Shadow-01 said in Simple line drawing by using a paint object:
class which gives me a "hello world" message, that I can use in a QML file?
Do you have read documentation about C++ integration with QML?
Create a simple
QObject
based class:class Backend: public QObject { Q_OBJECT Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged) public: void setAuthor(const QString &a) { if (a != m_author) { m_author = a; emit authorChanged(); } } QString author() const { return m_author; } signals: void authorChanged(); private: QString m_author; };
A simple main:
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView view; Backend backend; view.engine()->rootContext()->setContextProperty("backend", &backend); view.setSource(QUrl::fromLocalFile("MyItem.qml")); view.show(); return app.exec(); }
And the
MyItem.qml
import QtQuick 2.0 Text { width: 100; height: 100 text: backend.author // invokes Backend::author() to get this value Component.onCompleted: { backend.author = "Jonah" // invokes Backend::setAuthor() } }
[EDIT]
Or for more "fun", you can change the main as follow:int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView view; Backend backend; view.engine()->rootContext()->setContextProperty("backend", &backend); view.setSource(QUrl::fromLocalFile("MyItem.qml")); view.show(); QTimer tmr; QObject::connect(&tmr, &QTimer::timeout, [&](){ backend.setAuthor(QDateTime::currentDateTime().toString("dd/MM/yyyy hh:mm:ss.zzz")); tmr.start(100); }); tmr.setSingleShot(true); tmr.start(10); return app.exec(); }
-
Ok, thanks to your indications. The question is now absolutely easier and I have isolated the 90% of the problem. So, I have now a container.ccp class:
#include "profileview.h" #include <QPainter> ProfileView::ProfileView() { } void ProfileView::paint(QPainter *painter) { QBrush brush(Qt::cyan); painter->setBrush(brush); painter->setPen(Qt::NoPen); painter->setRenderHint(QPainter::Antialiasing); painter->drawLine(0, 0, 200, 200); }
with the corrispondent header:
#ifndef CONTAINER_H #define CONTAINER_H #include <QQuickPaintedItem> #include <QObject> class container : public QQuickPaintedItem { public: container(); void paint(); }; #endif // CONTAINER_H
And this is the way I am using to call it in the qml:
import QtQuick 2.0 import com.me.myApp Window { width: 640 height: 480 visible: true title: qsTr("Container page") Rectangle{ height: 50 width: 100 color: "#ffffff" } //Here the paint calling ProfileView { id: newCanvas anchors.fill: parent } }
Now, my class is perfectly visible in my container.qml (if I try to write the name of the void, I don't see any error; by changing the name, the name is not accepted. The last question is: how can I "consume" in my qml view the paint function of my class, so I can see in the qml the line I have defined in the class?
Really thank you very much!