How to create custom widget to use in designer
-
I tryed to make a plugin using
QDesignerCustomWidgetInterface
.I thiught when i compile the plugin files get created here:
But they don't. Do I have to set the
QT_INSTALL_PLUGINS
some where?I already checked out the example: https://doc.qt.io/qt-5/qtdesigner-customwidgetplugin-example.html#
QT += widgets uiplugin CONFIG += plugin release TEMPLATE = lib TARGET = $$qtLibraryTarget($$TARGET) target.path = $$[QT_INSTALL_PLUGINS]/designer INSTALLS += target HEADERS += ../iconeditor/iconeditor.h \ iconeditorplugin.h SOURCES += ../iconeditor/iconeditor.cpp \ iconeditorplugin.cpp RESOURCES += \ iconeditorplugin.qrc OTHER_FILES += iconeditor.json
#ifndef ICONEDITORPLUGIN_H #define ICONEDITORPLUGIN_H #include <QObject> #include <QDesignerCustomWidgetInterface> class IconEditorPlugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface") Q_INTERFACES(QDesignerCustomWidgetInterface) public: explicit IconEditorPlugin(QObject *parent = nullptr); QString name() const override; QString includeFile() const override; QString group() const override; QIcon icon() const override; QString toolTip() const override; QString whatsThis() const override; bool isContainer() const override; QWidget *createWidget(QWidget *parent) override; QString domXml() const override; bool isInitialized() const override; void initialize(QDesignerFormEditorInterface *core) override; private: bool initialized{ false }; }; #endif // ICONEDITORPLUGIN_H
#include "iconeditorplugin.h" #include "../iconeditor/iconeditor.h" IconEditorPlugin::IconEditorPlugin(QObject *parent) : QObject{parent} { } QString IconEditorPlugin::name() const { return QStringLiteral("IconEditor"); } QString IconEditorPlugin::includeFile() const { return QStringLiteral("iconeditor.h"); } QString IconEditorPlugin::group() const { return tr("Image Manipulation Widgets"); } QIcon IconEditorPlugin::icon() const { return QIcon(":/images/iconeditor.png"); } QString IconEditorPlugin::toolTip() const { return tr("An icon editor widget"); } QString IconEditorPlugin::whatsThis() const { return tr("This widget is present in Chapter 5 of <i>C++ GUI " "Programming with Qt 4</i> as an example of a custom Qt " "widget."); } bool IconEditorPlugin::isContainer() const { return false; } QWidget *IconEditorPlugin::createWidget(QWidget *parent) { return new IconEditor{parent}; } QString IconEditorPlugin::domXml() const { return "<ui language=\"c++\">\n" " <widget class=\"IconEditor\" name=\"iconEditor\">\n" " <property name=\"geometry\">\n" " <rect>\n" " <x>0</x>\n" " <y>0</y>\n" " <width>100</width>\n" " <height>100</height>\n" " </rect>\n" " </property>\n" " <property name=\"toolTip\" >\n" " <string>An icon editor widget</string>\n" " </property>\n" " <property name=\"whatsThis\" >\n" " <string>This widget is present in Chapter 5 of C++ GUI Programming</string>\n" " </property>\n" " </widget>\n" "</ui>\n"; } bool IconEditorPlugin::isInitialized() const { return initialized; } void IconEditorPlugin::initialize(QDesignerFormEditorInterface * /*core*/) { if (initialized) { return; } initialized = true; }
-
Hi
The reason it doesnt copy from the build folder to the $$[QT_INSTALL_PLUGINS]/designer
is that you need a "make install" step for that to be executed.
(Projects->Press button "Add build step" then select make )then after build its copied
-
That works with creating the file. I totally forgot about install :(.
However if I open designer now I cannot see the new Widget. How can I check if it got loaded correctly?
-
@sandro4912
Hi
First check that plugin is built in release mode
then check you are using a Qt version and compiler that maches what your Creator was build with
So in this case my plugin should be Release visual studio 2017 (2015 can work) and
Qt 5.12.3. in 32 bit. Qt 5.12.xxx should work but not say 5.13Have a look here
https://doc.qt.io/qt-5/deployment-plugins.htmlI would first set the QT_DEBUG_PLUGINS environment and start Creator from the shell
to see what it says about my plugin. -
I build the plugin with MSVC2017 32 Bit.
My creator also says it was build with QT5.12.3(MSVC2017, 32 bit)@mrjj said in How to create custom widget to use in designer:
I would first set the QT_DEBUG_PLUGINS environment and start Creator from the shell
to see what it says about my plugin.What do you mean with that? Setting from the command window
QT_DEBUG_PLUGINS
and start QtCreator from there? -
@sandro4912
Yes but i just recalled it wont list in cmd prompt on windows (unlike linux )
so i used
https://docs.microsoft.com/en-us/sysinternals/downloads/debugview
(its portable and very small)to easy get path to Creator , i just
use the property on the icon
and grabbed the path -
I run alll the steps and could get the dump in DebugView.
But I cant find the plugin in the dump.
The plugin dll is located here:
but if i search the name in the debug Output view it does not show up. i can't find anything with designer in it.
-
at the end of the dump it says
[7960] [7960] loaded library "E:/Qt/Tools/QtCreator/lib/qtcreator/plugins/qmldesigner/qtquickplugin4.dll" [7960] SOFT ASSERT: "d->m_accessor" in file C:\Users\qt\work\build\qt-creator\src\plugins\projectexplorer\toolchainmanager.cpp, line 130
is that maybe a problem?
-
Hi
I copy to
C:\Qt\Tools\QtCreator\bin\plugins\designer
as Designer is a plugin to Creator and unless you really try to make a plugin for the
the standalone Designer app, then you have to use Creator's plugin location.
in my case its C:\Qt\Tools\QtCreator\bin\plugins\designer
I think that explains you see no mention of your icon editor plugin.btw: what does it do ? the name suggests a small icon designer which sounds cool.
-
I copied to the directory you described and it finnaly works. So what is the prupose of the pro file entry
TARGET = $$qtLibraryTarget($$TARGET) target.path = $$[QT_INSTALL_PLUGINS]/designer INSTALLS += target
If it copies to the wrong path and you need to copy manually. can it be adjusted to copy to the creator paths?
The Icon Editor is a example from the Book C++ Gui Programming with QT4. You can load a picture ( a icon) and zoom it to make it bigger and then edit the individual pixels of the icon. Its a cool little widget.
I ported it to c++17 and Qt 5. The old QT4 code can be found in the repository of the book: https://github.com/cggos/CPPGUIProgrammingWithQt4/tree/master/chap05/iconeditor
Here is my code with QT5 and c++17:
QT += widgets CONFIG += c++17 HEADERS += \ iconeditor.h SOURCES += \ iconeditor.cpp \ main.cpp RESOURCES += \ iconeditor.qrc
#ifndef ICONEDITOR_H #define ICONEDITOR_H #include <QColor> #include <QImage> #include <QWidget> class IconEditor : public QWidget { Q_OBJECT Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor) Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage) Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor) public: explicit IconEditor(QWidget *parent = nullptr); void setPenColor(const QColor &newColor); QColor penColor() const { return curColor; } void setZoomFactor(int newZoom); int zoomFactor() const { return zoom; } void setIconImage(const QImage &newImage); QImage iconImage() const { return image; } QSize sizeHint() const override; protected: void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *event) override; private: void drawGrid(QPainter &painter); void drawImage(QPainter &painter, QPaintEvent *event); void setImagePixel(const QPoint &pos, bool opaque); QRect pixelRect(int i, int j) const; QColor curColor; QImage image; int zoom; static constexpr auto thresholdShowGrid{3}; }; #endif // ICONEDITOR_H
#include "iconeditor.h" #include <QSizePolicy> #include <QPainter> #include <QPaintEvent> #include <QRegion> #include <QMouseEvent> #include <QDebug> IconEditor::IconEditor(QWidget *parent) : QWidget{ parent }, curColor{ Qt::black }, image{ QImage{16, 16, QImage::Format_ARGB32 }}, zoom{8} { setAttribute(Qt::WA_StaticContents); setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); image.fill(qRgba(0, 0, 0, 0)); } void IconEditor::setPenColor(const QColor &newColor) { curColor = newColor; } void IconEditor::setZoomFactor(int newZoom) { if (newZoom < 1) { newZoom = 1; } if (newZoom != zoom) { zoom = newZoom; update(); } } void IconEditor::setIconImage(const QImage &newImage) { if (newImage != image) { image = newImage.convertToFormat(QImage::Format_ARGB32); update(); updateGeometry(); } } QSize IconEditor::sizeHint() const { auto size = zoom * image.size(); if (zoom >= thresholdShowGrid) { size += QSize{1, 1}; } return size; } void IconEditor::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { setImagePixel(event->pos(), true); } else if (event->button() == Qt::RightButton) { setImagePixel(event->pos(), false); } } void IconEditor::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { setImagePixel(event->pos(), true); } else if (event->buttons() & Qt::RightButton) { setImagePixel(event->pos(), false); } } void IconEditor::paintEvent(QPaintEvent *event) { QPainter painter{this}; if (zoom >= thresholdShowGrid) { drawGrid(painter); } drawImage(painter, event); } void IconEditor::drawGrid(QPainter &painter) { painter.setPen(palette().foreground().color()); for (auto i = 0; i <= image.width(); ++i) { painter.drawLine(zoom * i, 0, zoom * i, zoom * image.height()); } for (auto j = 0; j <= image.height(); ++j) { painter.drawLine(0, zoom * j, zoom * image.width(), zoom * j); } } void IconEditor::drawImage(QPainter &painter, QPaintEvent *event) { for (auto i = 0; i < image.width(); ++i) { for (auto j = 0; j < image.height(); ++j) { auto rect = pixelRect(i, j); if (event->region().intersects(rect)) { auto color = QColor::fromRgba(image.pixel(i, j)); if (color.alpha() < 255) { painter.fillRect(rect, Qt::white); } painter.fillRect(rect, color); } } } } void IconEditor::setImagePixel(const QPoint &pos, bool opaque) { auto i = pos.x() / zoom; auto j = pos.y() / zoom; if (image.rect().contains(i, j)) { if (opaque) { image.setPixel(i, j, penColor().rgba()); } else { image.setPixel(i, j, qRgba(0, 0, 0, 0)); } update(pixelRect(i, j)); } } QRect IconEditor::pixelRect(int i, int j) const { if (zoom > thresholdShowGrid) { return QRect{ zoom * i + 1, zoom * j + 1, zoom - 1, zoom - 1 }; } return QRect{ zoom * i, zoom * j, zoom, zoom }; }
-
@sandro4912 said in How to create custom widget to use in designer:
If it copies to the wrong path and you need to copy manually. can it be adjusted to copy to the creator paths?
Hi
The docs talk about Designer plugins and i assume the examples were actually made for the standalone
Designer app and not in the case, Designer is a plugin in Creator.
Hence the wrong path. Yes, you can just change the path. Nothing magic, its just triggers a
file copy on the "make install" step and could copy it anywhere.Ahh, from that book. Cool. Did you have to change any of the Q_PLUGIN_METADATA, Q_INTERFACES
stuff to make it work ? -
Yes the book uses still the outdated
Q_EXPORT_PLUGIN2
Method to create the plugin because its in QT4. I had to addQ_PLUGIN_METADATA
it wasn't used back then. And now that you say it the book menthionsQT Designer
notQT Creator
so it is no wonder it got copied to the wrong dir.I wonder why would you use the standalone designer if you can run it in creator?
-
@sandro4912
Hi
In older version Designer and Creator was apart.
Not sure when it became integrated. However, the only use case i have for standalone designer is using it to view
UI files. Else Im not sure if there is any benefits.This is handy as you can then have one open for reference while using Creator.
-
Thats nice to know. So it makes sense to deploy all plugins to standalone designer and Qt creator to have them accesible in both.
-
@sandro4912
Yes it would if you are using the Designer app.
I do use sometimes as i can then have the UI on my second monitor.
Less fuss than running 2x Creator :) -
then is there a similar variabel like
QT_INSTALL_PLUGINS
for the Creator to define the path to the creator plugins to not do it absolute like this:target.path = $$[QT_INSTALL_PLUGINS]/designer INSTALLS += target target.path = E:/Qt\Tools/QtCreator/bin/plugins/designer INSTALLS += target
-
Hi
I think there is but could not locate it.
I assumed the actual Creator plugins would use something but it seems not.