How to: Create custom designer widget using Visual Studio
-
Hi there. Just spent a few hours trying to make it works so i'd like to share my solution in case someone will come with same problem.
What i was trying to do is to create custom widget with using only Visual studio & "Qt VS Tools" plugin. I really like visual studio and wished to not use any "side" tools in my toolchain like QtCreator or explicit usage of qmake. The widget we make meant to be designer-compatible: it have to show actual widget content, not only empty boundary box.
I'm not pretending it's the best solution but just one that works for me and I wasn't able to google any similar guides. Tested with VS2019 & Qt 5.14.2
So, here is the plan:
-
Install and setup Visual Studio & Qt Visual Studio tools plugin (just in case)
-
Create new solution. Type should be"Qt Class Library", make it dynamic (don't check "Create static library (.lib)")
-
The project will consist of two classes: the widget itself ("QtWidgetTest" in this guide) & wrapper for compatibility with designer("QtWidgetTestWrapper").
-
Setup Qt project modules that pointed in this guide : https://doc.qt.io/qt-5/qtdesigner-customwidgetplugin-example.html . In VS for this you need to go project properties -> Qt Project settings -> Qt Modules; and list there all required modules separated by semicolons. In this example I'll set this line to "core;gui;widgets;designer;uiplugin"
-
Creating widget:
4.1 Add new Qt GUI class to project: rmb on project -> add -> Add Qt Class... -> Qt GUI Class
4.2 Double click on "QtWidgetTest.ui" in solution explorer will open this file in Qt designer. Open it and throw in some content. For example group box, label & button, also i suggest to setup any layout for root form, just to have pretty widget. Save form. Note that class name of ui variable in header will depend on .ui's root window object name(in case you get error like: [ 'QtWidgetTest': is not a member of 'Ui' ])
4.3 [optional step for convenience] By some reason by default studio isn't able to find "ui_*.h" files for GUI Classes and this break highlighting. My solution is to compile project once(for uic to create this file at all) and then add uic folder to the project's include paths for current configuration, ex. "$(SolutionDir)QtWidgetTest\x64\Debug\uic". (To add path go to rmb on project -> properties -> C/C++ -> General -> Additional include directories)
4.4 You can implement whatever functionality you require from widget in this class. For example increase counter in the label by 1 on each button click. -
Create wrapper:
5.1 Wrapper will have no gui and will only consist of .h & .cpp
5.2 In wrapper header include your widget header, and <QtUiPlugin/QDesignerCustomWidgetInterface>.
5.3 From this point you are free to follow this guide for writing wrapper: https://doc.qt.io/qt-5/qtdesigner-customwidgetplugin-example.html .
5.4 A few things you should know about guide above:
5.4.1 Wrapper class must be derrived from QObject & QDesignerCustomWidgetInterface and annotated with Q_OBJECT, Q_PLUGIN_METADATE & Q_INTERFACES, don't miss it.
5.4.2 It's convenient to move cursor over "public QDesignerCustomWidgetInterface" in header -> alt+enter -> implement pure virtuals from this class. This way you'll generate most of required code. But guide above suggest to define a few extra functions like "isInitialized()", "initialize()" and "domXml()".
5.4.3 While setting "name()", "domXml():widget class" - make sure they set to actual widget class name, "QtWidgetTest" in this guide. "domXml():widget name" is a name for newly added widgets on form, this one should not be equal to widget class name for sake of avoiding unnecessary errors during compilation. -
Compiling and setuping widget for Qt Designer
6.1 Compile your project in release mode for architecture corresponding to your QtDesigner was built in. In my case it's Release/Win32.
6.2 Copy your assembled in previous step dll into designer's plugin folder. For visual studio & win32 designer the path is: %QtInstallationRoot%\5.14.2\msvc2017\plugins\designer
6.3 Open QtDesigner (double click on any .ui file in project), go to menu Help -> About plugins, click "refresh". If all steps above was completed without mistakes - your plugin will appear in the list without any error message boxes in background
6.4 You will see your widget in the widget box on the left and will be able to throw it onto the form and see it's actual content. -
Using created widget
7.1 Unfortunately step 6 only let you use your widget in designer, but not let you compile app using it without additional step.
7.2 Create a new Qt GUI Solution(or project in current solution if you like)
7.3 Add your widget into your .ui file, save it and try compile. See "cannot find QtWidgetTest.h" or "unresolved externals" errors.
7.4 Include into your project an actual implementation of widget(.h, .cpp and .ui files). It should be in exact the same spot relatively to project root as you pointed during 5.3 step in function "includeFile()". Copy them from first project, for example into root of second project and then add them into second project by rmb->add->existing item.
7.5 In case you getting error like [syntax error: identifier "QtWidgetTest"] this means your object's instance on form have the same name as a your widget class :) Change it. Don't forget to save form file and rebuild project.
7.6 Build it, run it. You widget should appear exactly where you put them and work fine.
Thats all.
In conclusion i add that i'm not sure about step 5.4.3 but it's the way it's works and it's fine for me.
You can check code created with guide above here -