Cannot import QML plugin - qt

Let's consider an example QML plugin PluginExample (see C++ Plugins for QML) created in the directory $HOME/projects/org/example/PluginExample ($HOME/projects is in QML2_IMPORT_PATH).
pluginexample.pro:
TEMPLATE = lib
TARGET = PluginExample
QT += qml quick
CONFIG += qt plugin
TARGET = $$qtLibraryTarget($$TARGET)
uri = org.example.PluginExample
# Input
SOURCES += \
pluginexample_plugin.cc \
myitem.cc
HEADERS += \
pluginexample_plugin.hh \
myitem.hh
OTHER_FILES = qmldir
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
copy_qmldir.target = $$OUT_PWD/qmldir
copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
copy_qmldir.commands = $(COPY_FILE) \"$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)\"
QMAKE_EXTRA_TARGETS += copy_qmldir
PRE_TARGETDEPS += $$copy_qmldir.target
}
qmldir.files = qmldir
unix {
installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir
}
myitem.hh:
#ifndef MYITEM_H
#define MYITEM_H
#include <QQuickItem>
class MyItem : public QQuickItem
{
Q_OBJECT
Q_DISABLE_COPY(MyItem)
Q_PROPERTY(QString text READ text CONSTANT)
public:
MyItem(QQuickItem *parent = 0);
QString text() const;
~MyItem();
};
#endif // MYITEM_H
myitem.cc:
#include "myitem.hh"
MyItem::MyItem(QQuickItem *parent):
QQuickItem(parent)
{
}
MyItem::~MyItem()
{
}
QString MyItem::text() const
{
return "MyItem";
}
pluginexample_plugin.hh:
#ifndef PLUGINEXAMPLE_PLUGIN_H
#define PLUGINEXAMPLE_PLUGIN_H
#include <QQmlExtensionPlugin>
class PluginExamplePlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
void registerTypes(const char *uri);
};
#endif // PLUGINEXAMPLE_PLUGIN_H
pluginexample_plugin.cc:
#include "pluginexample_plugin.hh"
#include "myitem.hh"
#include <qqml.h>
void PluginExamplePlugin::registerTypes(const char *uri)
{
// #uri org.example.PluginExample
qmlRegisterType<MyItem>(uri, 1, 0, "MyItem");
}
qmldir:
module org.example.PluginExample
plugin PluginExample
The most part of the plugin's code was auto-generated by the project wizard.
It builds fine, but when I try to import org.example.PluginExample 1.0 from another project, I get this error:
module "org.example.PluginExample" plugin "PluginExample" not found
How can I fix that? Do I need to specify additional information to build/locate the plugin?
PS. Qt 5.3, Linux x86_64
EDIT 1:
I copied libPluginExample.so from the build directory (build-PluginExample-Desktop_Qt_5_3_0_GCC_64bit-Debug) to the source directory (PluginExample), and the error disappeared. Is this the best solution?
EDIT 2:
To avoid manual copying of the plugin library after each build, the following changes need to be applied to the *.pro file (unix-specific):
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
# ...
unix {
QMAKE_POST_LINK += $(COPY_FILE) $$quote($${OUT_PWD}/lib$${TARGET}.so) $$_PRO_FILE_PWD_
}
}

Related

My custom C++ plugin is not being consumed by the qml test application

I am new to Qt and learning few of the modules in Qt-Qml from youtube and Qt documentation. I want to create cpp plugin which is to be consumed by the qml application.
For this, I have created two projects. One is for creating a plugin library and another application is for consuming the plugin.
I am able to create the plugin library successfully. But, not able to consume it by the test application.
The test application is compiled successfully but throwing below error during run time.
QQmlApplicationEngine failed to load component
qrc:/main.qml:3:1: module "MyPlugin" is not installed
I have read the Qt documentation and googled a lot, but could not able to resolve it.
Qt : 5.15.7
Qt Creator: 5.0.3
OS: Ubuntu 18.04
Project 1: Creating Plugin library
CreatePlugin.pro
TEMPLATE = lib
TARGET = CreatePlugin
QT += qml quick
CONFIG += plugin c++11
DESTDIR = ../pluginFiles
TARGET = $$qtLibraryTarget($$TARGET)
uri = MyPlugin
# Input
SOURCES += \
createplugin_plugin.cpp \
myplugin.cpp
HEADERS += \
createplugin_plugin.h \
myplugin.h
DISTFILES = qmldir
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
copy_qmldir.target = $$OUT_PWD/qmldir
copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
copy_qmldir.commands = $(COPY_FILE) "$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)"
"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)"
QMAKE_EXTRA_TARGETS += copy_qmldir
PRE_TARGETDEPS += $$copy_qmldir.target
}
qmldir.files = qmldir
unix {
installPath = $$[QT_INSTALL_QML]/$$replace(uri, \., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir
}
# Copy the qmldir file to the same folder as the plugin binary
cpqmldir.files = qmldir
cpqmldir.path = $$DESTDIR
COPIES += cpqmldir
createplugin_plugin.h
#ifndef CREATEPLUGIN_PLUGIN_H
#define CREATEPLUGIN_PLUGIN_H
#include <QQmlExtensionPlugin>
class CreatePluginPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri) override;
};
#endif // CREATEPLUGIN_PLUGIN_H
createplugin_plugin.cpp
#include "createplugin_plugin.h"
#include "myplugin.h"
#include <qqml.h>
void CreatePluginPlugin::registerTypes(const char *uri)
{
// #uri MyPlugin
qmlRegisterType<MyPlugin>(uri, 1, 0, "MyPlugin");
}
myplugin.h
#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include <QObject>
#include <QString>
class MyPlugin : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(MyPlugin)
public:
explicit MyPlugin(QObject *parent = nullptr);
~MyPlugin() override;
public slots:
QString getString();
};
#endif // MYPLUGIN_H
myplugin.cpp
#include "myplugin.h"
MyPlugin::MyPlugin(QObject *parent)
: QObject(parent)
{
// By default, QQuickItem does not draw anything. If you subclass
// QQuickItem to create a visual item, you will need to uncomment the
// following line and re-implement updatePaintNode()
// setFlag(ItemHasContents, true);
}
MyPlugin::~MyPlugin()
{
}
QString MyPlugin::getString()
{
return "This is CPP String";
}
qmldir
module MyPlugin
plugin CreatePlugin
Project 2: TestPlugin
TestPlugin.pro
QT += quick
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before
Qt 6.0.0
SOURCES += \
main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import MyPlugin 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
MyPlugin {
id: mypluginId
}
Component.onCompleted: console.log(mypluginId.getString())
}

QT load resource files for debugging

So I've created a qrc file and have a file at /stylesheets/main.qss.
I have stylesheet information in this main.qss file. My goal here is to have a qss file I can work out of and potentially hot reload over time. My issue is that when I debug there is no /stylesheets/main.qss in the debug build location. So it loads the file as an empty string, don't even get an exception. What am I missing?
main.qss
/*#MainBackgroundColor = rgb(40,40,40)*/
/*#MainBorderColor = rgb(0,102,255)*/
/*#MainTextColor = rgb(255,255,255)*/
*
{
color: rgb(255,255,255);
background-color: rgb(40,40,40);
}
QStatusBar
{
border-top: 3px solid rgb(0,102,255);
}
Loading the stylesheet
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//We want a frameless window.
setWindowFlags(Qt::FramelessWindowHint);
//Load the style sheet into the window
QFile File(":/stylesheets/main.qss");
File.open(QFile::ReadOnly);
QString stylesheet = QLatin1String(File.readAll());
//Setup the UI
ui->setupUi(this);
this->setStyleSheet(stylesheet);
}
MainWindow::~MainWindow()
{
delete ui;
}
resources.qrc
<RCC>
<qresource prefix="/">
<file>stylesheets/main.qss</file>
</qresource>
</RCC>
.pro file
#-------------------------------------------------
#
# Project created by QtCreator 2019-02-20T18:02:31
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = SmartDraw
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp \
stylesheetloader.cpp
HEADERS += \
mainwindow.h \
stylesheetloader.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
resources.qrc
DISTFILES += \
stylesheets/main.qss
EDIT: Found the solution. Apparently Qt isn't very good about updating everything if you happen to have the pro file open. If something super obviously wrong happens like this you need to run Build->Clean All then Build->Run QMake to get everything stituated again.
What I do is keep the stylesheet file (*.qss) next to the app while debugging. Then load it in main.cpp and subscribe for changes using QFileSystemWatcher.
This way I can edit the *.qss file with a nice editor, like SublimeText, and every time I save it, I can see the changes inmediatly:
#include "mydialog.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QTextStream>
#include <QSharedPointer>
#include <QFileSystemWatcher>
typedef QSharedPointer<QFileSystemWatcher> QWatcherPtr;
void setStyleSheet(QApplication &a, const QString &strPath, const bool &subscribe = false)
{
// set stylesheet
QFile f(strPath);
if (!f.exists())
{
qDebug() << "[ERROR] Unable to set stylesheet," << strPath << "file not found.";
}
else
{
// set stylesheet
f.open(QFile::ReadOnly | QFile::Text);
QTextStream ts(&f);
a.setStyleSheet(ts.readAll());
f.close();
// subscribe to changes (only once)
if (!subscribe)
{
return;
}
QWatcherPtr watcher = QWatcherPtr(new QFileSystemWatcher);
watcher->addPath(strPath);
QObject::connect(watcher.data(), &QFileSystemWatcher::fileChanged, &a,
[&a, watcher, strPath]()
{
setStyleSheet(a, strPath, false);
});
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// set stylesheet and subscribe to changes
setStyleSheet(a, "./style.qss", true);
MyDialog w;
w.show();
return a.exec();
}

Qt not locating slots in simple example program

This is a simple example that fails to run. The run-time errors are:
QObject::connect: No such slot Bridge::setText(const QString& text)
QObject::connect: No such slot QLabel::setText(const QString& text)
I have two files, main.cpp and Bridge.h.
main.cpp
#include <QtWidgets>
#include "Bridge.h"
int main(int argc, char ** argv)
{
QApplication app (argc, argv);
QWidget widget;
QLineEdit * lineEdit = new QLineEdit;
QLabel * label = new QLabel;
QVBoxLayout * layout = new QVBoxLayout;
layout->addWidget(lineEdit);
layout->addWidget(label);
widget.setLayout(layout);
Bridge * bridge = new Bridge ("", &app);
QObject::connect(
lineEdit, SIGNAL(textChanged(const QString &)),
bridge, SLOT(setText(const QString & text))
);
QObject::connect(
bridge, SIGNAL(textChanged(const QString &)),
label, SLOT(setText(const QString & text))
);
widget.show();
return app.exec();
}
Bridge.h
#include <QString>
#include <QObject>
class Bridge : public QObject
{
Q_OBJECT
public:
Bridge(const QString & text, QObject * parent = 0) : QObject(parent), text(text) {}
const QString & getText() const;
int getLengthOfText() const;
public slots:
void setText(const QString & text) {
if (this->text == text) {
return;
}
this->text = text;
emit textChanged(text);
}
signals:
void textChanged(const QString &);
private:
QString text;
};
.pro file
######################################################################
# Automatically generated by qmake (3.0) Sat May 17 20:28:07 2014
######################################################################
TEMPLATE = app
TARGET = qtbox
INCLUDEPATH += .
INCLUDEPATH += headers
QT += widgets
# Input
HEADERS += headers/Bridge.h
SOURCES += sources/main.cpp
######################################################################
# Build to custom directories
######################################################################
release: DESTDIR = build/release
debug: DESTDIR = build/debug
OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.ui
Am I missing something obvious here? Some random things I can come up with:
Do I need to define setText in a .cpp file? If so, why would I have to do this?
Is whitespace a problem? ie QString& vs QString &
Am I missing something in my qmake file?
No, you do not. But it is common to do so, especially if you need to change your implementation; you will not have to recompile all files that include that header file.
No, both are valid.
No, also, the qmake file seems valid.
Change your connect calls not to have a variable, but only the type:
connect(bridge, SIGNAL(textChanged(QString)), label, SLOT(setText(QString)));
Edit: Also, #include <QLabel> to eventually run qmake manually once.

Simple QT console TCP application. What am I doing wrong?

#include <QtCore/QCoreApplication>
#include <QTCore>
#include <QtNetwork>
#include <QDebug>
#define CONNECT(sndr, sig, rcvr, slt) connect(sndr, SIGNAL(sig), rcvr, SLOT(slt))
class mynet : QObject
{
Q_OBJECT
public:
mynet()
{}
void start()
{
CONNECT(tcpServer, newConnection(), this, acceptConnection());
CONNECT(tcpClient, connected(), this, startTransfer());
CONNECT(tcpClient, bytesWritten(qint64), this, updateClientProgress(qint64));
CONNECT(tcpClient, error(QAbstractSocket::SocketError), this, displayError(QAbstractSocket::SocketError));
// start server listening
tcpServer->listen();
while(!tcpServer->isListening());
// make client connection
tcpClient->connectToHost(QHostAddress::LocalHost, tcpServer->serverPort());
}
public slots:
void acceptConnection()
{
tcpServerConnection = tcpServer->nextPendingConnection();
CONNECT(tcpServerConnection, readyRead(), this, updateServerProgress());
CONNECT(tcpServerConnection, error(QAbstractSocket::SocketError), this, displayError(QAbstractSocket));
tcpServer->close();
}
void startTransfer()
{
bytesToWrite = TotalBytes - (int)tcpClient->write(QByteArray(PayloadSize, '#'));
}
void updateServerProgress()
{
bytesReceived += (int)tcpServerConnection->bytesAvailable();
tcpServerConnection->readAll();
if (bytesReceived == TotalBytes)
{
qDebug() << "done";
tcpServerConnection->close();
}
}
void updateClientProgress(qint64 numBytes)
{
// callen when the TCP client has written some bytes
bytesWritten += (int)numBytes;
// only write more if not finished and when the Qt write buffer is below a certain size.
if (bytesToWrite > 0 && tcpClient->bytesToWrite() <= 4*PayloadSize)
bytesToWrite -= (int)tcpClient->write(QByteArray(qMin(bytesToWrite, PayloadSize), '#'));
}
void displayError(QAbstractSocket::SocketError socketError)
{
if (socketError == QTcpSocket::RemoteHostClosedError)
return;
qDebug() << tcpClient->errorString();
tcpClient->close();
tcpServer->close();
}
private:
QTcpServer* tcpServer;
QTcpSocket* tcpClient;
QTcpSocket* tcpServerConnection;
int bytesToWrite;
int bytesWritten;
int bytesReceived;
int TotalBytes;
int PayloadSize;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
mynet m1;
m1.start();
return a.exec();
}
I get an
Undefined symbols for architecture x86_64:
"vtable for mynet", referenced from:
mynet::mynet() in main.o
mynet::~mynet()in main.o.
Please advise what I am doing wrong. Can I not inline the method definitions in the class for some reason in Qt?
You need to add your class to the .pro file
HEADERS += mynet.h
SOURCES += mynet.cpp
so the meta-object compiler can scan them and work out they need moc'ing and generate the relevant stubs.
Assuming that your source file is named foo.cpp, you have to put the following line at the very end:
#include "foo.moc"
This line tells qmake and the VS Qt add-in that the file should be run via moc, and that the generated moc file should be named foo.moc.
You also have problems in the #include lines for Qt headers. I've found that the following work:
#include <QtCore/QCoreApplication>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
Make sure to add network to your .pro file. This will create the correct linking to the network library functions.
QT += core network
Two things:
1) You should publicly derive from QObject.
2) Are you moc'ing this file and then compiling and linking the output? If you include the Q_OBJECT macro and don't moc, you will get an error like that.

File not found during compilation

What is wrong with the code bellow? When I compile it I get a warning that file not found. Something is invalid. I'm probably making a few mistakes here. I think the problem is perhaps with the way I inherit from QWidget.
#include <QtGui/QApplication>
#include "filedialogs.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FileDialogs w;
w.openFile();
return 0;
}
#ifndef FILEDIALOGS_H
#define FILEDIALOGS_H
#include <QWidget>
class QFileDialog;
class FileDialogs : public QWidget
{
public:
FileDialogs(QWidget *parent = 0);
~FileDialogs();
void openFile();
};
#endif // FILEDIALOGS_H
#include <QFileDialog>
#include "filedialogs.h"
FileDialogs::FileDialogs(QWidget *parent)
: QWidget(parent)
{
}
FileDialogs::~FileDialogs()
{
}
void FileDialogs::openFile()
{
QString filename = QFileDialog::getOpenFileName(
this,
tr("Open Document"),
QDir::currentPath(),
tr("Document files (*.doc *.rtf);;All files (*.*)") );
if( !filename.isNull() )
{
qDebug( filename.toAscii() );
}
}
#-------------------------------------------------
#
# Project created by QtCreator 2011-07-29T19:06:33
#
#-------------------------------------------------
QT += core gui
TARGET = exX
TEMPLATE = app
SOURCES += main.cpp\
filedialogs.cpp
HEADERS += filedialogs.h
This error message is emitted by the MOC compiler. You are missing the Q_OBJECT macro. Put it in your class declaration like this:
class FileDialogs : public QWidget
{
Q_OBJECT
public:
....
I know this Question is very old. But in my case it was another problem.
I had to include the path of the headers manually in the .pro file.
INCLUDEPATH += src/subdir

Resources