赞
踩
在Qt设计师中使用自定义窗口部件之前,我们必须让Qt设计师先察觉到它们的存在。有两种方法可以完成这一任务:改进法(promotion)和插件法(pluigin)。
改进法是最为快捷和简单的方法。这种方法包括:选择一个内置的Qt窗口部件,但该窗口部件要和我们自定义的窗口部件具有相类似的应用程序编程接口,并在Qt设计师的自定义窗口部件对话框(如图所示)中填写一些与这个窗口部件相关的信息。然后,这个自定义窗口部件就可用于由Qt设计师开发的窗体中,尽管在编辑或者预览该窗体时它有可能仍旧显示为与之相关的内置Qt窗口部件的形式。
以下给出了如何使用这种方法在窗体中插人一个HexSpinBox窗口部件的步骤:
1.从Qt设计师的左侧窗口部件工具盒中拖动一个QSpinBox到窗体中,由此创建一个QSpinBox。
2.右键单击这个微调框,并且从上下文菜单中选择"提升为…"(改进成自定义窗口部件)。
3.在弹出的对话框中,填入"HexSpinBox"作为类的名字,填入"hexspinbox.h"作为头文件的名字。
这三步就足够了。由uic生成的代码将会包含hexspinbox.h,而不是,并且会生成一个HexSpinBox 的实例。在Qt设计师中,将会用QSpinBox的图标来代表HexSpinBox 窗口部件,从而允许我们设置QSpinBox的所有属性(例如,它的作用范围和当前值)。
改进法的缺点是:在Qt设计师中,无法对自定义窗口部件中的那些特定属性进行访问,并且也无法对这个窗口部件自身进行绘制。所有这两个问题都可以通过使用插件法得到解决。
插件法需要创建一个插件库,Qt设计师可以在运行时加载这个库,并且可以利用该库创建窗口部件的实例。在对窗体进行编辑或者用于窗体预览时,Qt设计师就会用到这个真正的窗口部件,这要归功于Qt的元对象系统,Qt设计师才可以动态获取它的这些属性的列表。为了说明它是如何工作的,我们将把前一小节中的IconEditor 集成为一个插件。
首先,必须对QDesignerCustomWideTnterface进行子类化,并且需要重新实现一些虚函数。假定插件的源代码放在一个名为iconeditorplugin的目录中,并且IconEditor 的源代码放在与iconeditorplugin目录同级的iconeditor 目录中。
#ifndef ICONEDITORPLUGIN_H #define ICONEDITORPLUGIN_H #include <QDesignerCustomWidgetInterface> class IconEditorPlugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_INTERFACES(QDesignerCustomWidgetInterface) public: IconEditorPlugin(QObject *parent = 0); QString name() const; //返回该插件提供给这个窗口部件的名字 QString includeFile() const; //返回由该插件封装的特定窗口部件的头文件的名称。这个头文件会包含在由uic工具所生成的代码中 QString group() const; //返回自定义窗口部件所应属于的窗口部件工具箱群组的名字 QIcon icon() const; //返回一个图标,可在Qt设计师窗口部件工具箱中用它来代表自定义窗口部件 QString toolTip() const; //返回一个工具提示信息,可在鼠标悬停在Qt设计师窗口部件工具箱中自定义窗口部件上时显示该信息 QString whatsThis() const; //返回于Qt设计师"What's This?"中显示的文本 bool isContainer() const; //判断该窗口部件还可以包含其他窗口部件 QWidget *createWidget(QWidget *parent); //利用给定的父对象创建该窗口部件类的一个实例 }; #endif
IconEditorPlugin子类是一个封装了这个IconEditor窗口部件的工厂(factory)类。它从QObject和QDesignerCustomWidegtlterface中派生而来,并且使用Q_INTERFACES()宏通知moc:这里的第二个基类是一个插件接口。Qt设计师会使用这些函数创建这个类的各个实例并且获取相关信息。
#include <QtPlugin> #include "../q01_hello_QT/iconeditor.h" #include "iconeditorplugin.h" IconEditorPlugin::IconEditorPlugin(QObject *parent) : QObject(parent) { } QString IconEditorPlugin::name() const { return "IconEditor"; } QString IconEditorPlugin::includeFile() const { return "iconeditor.h"; } QString IconEditorPlugin::group() const { //但如果以这个名字命名的窗口部件工具箱群组还没有使用到,那么Qt设计师将会为这个窗口部件创建一个新群组。 return tr("Image Manipulation Widgets"); } QIcon IconEditorPlugin::icon() const { //这里,我们假定IconEditorPlugin有一个与之相关联的Qt资源文件(resource file) ,其中有适当的一项可作为图标编辑器图像。 return QIcon(":/images/iconeditor.png"); } QString IconEditorPlugin::toolTip() const { return tr("An icon editor widget"); } QString IconEditorPlugin::whatsThis() const { return tr("This widget is presented in Chapter 5 of <i>C++ GUI " "Programming with Qt 4</i> as an example of a custom Qt " "widget."); } bool IconEditorPlugin::isContainer() const { /* 如果该窗口部件还可以包含其他窗口部件, isContainer()函数就返回true;否则,它就返回false。 * 例如,QFrame就是一个可以包含其他窗口部件的窗口部件。 * 一般情况下,任何窗口部件都可以再包含其他窗口部件,但是当isContainer()返回false时,Qt设计师则不会允许它再包含其他的窗口部件。 */ return false; } QWidget *IconEditorPlugin::createWidget(QWidget *parent) { return new IconEditor(parent); } Q_EXPORT_PLUGIN2(iconeditorplugin, IconEditorPlugin) //在实现该插件类的源文件的末尾,必须使用Q_EXPORT_ PLUGIN2()宏,从而可以在Qt设计师中使用这个插件。 //第一个参数是希望给插件的名字,第二个参数是实现该插件类的名字。
TEMPLATE = lib
CONFIG += designer plugin release
HEADERS = ../q01_hello_QT/iconeditor.h \
iconeditorplugin.h
SOURCES = ../q01_hello_QT/iconeditor.cpp \
iconeditorplugin.cpp
RESOURCES = iconeditorplugin.qrc
DESTDIR = $$[QT_INSTALL_PLUGINS]/designer
qmake构建工具已经构建了一些预定义变量。$$ [QT_ INSTALL_ PLUGINS]就是它们当中的一个,它保存了指向Qt安装目录中plugins 目录所在的路径。当键入make或者nmake来构建该插件时,它就会自动把自己安装到Qt设计师的plugins/designer目录中。插件一旦构建完毕,在Qt设计师中就可以像使用其他内置的Qt窗口部件一样来使用IconEditor 窗口部件。
如果想在Qt设计师中集成多个自定义窗口部件,则既可以为每个窗口部件创建一个插件,也可以通过从QDesignerCustomWidgetCOllectionInterface中派生的方式把它们组合成一个单一插件。
打开Qt Creator,创建一个新工程,选择"其他项目"->“Qt4设计师自定义控件”->“choose”。
填写项目名称,并指定项目路径。接下来Kits默认即可,本人是Windows系统,编译器为msvc10.0,点击下一步。
添加控件类,这里要注意类名称的首字母必须大写,右侧的源文件名称全部自动生成,不用管,直接下一步。
插件名称可以自定义,只要不与已存在插件重名即可。点击下一步,完成工程创建。
默认会打开自动生成的plugin后缀的源文件,不要修改这个文件。如下图所示,在头文件ipedit.h中添加:#include <QtDesigner/QDesignerExportWidget>;在类名前面添加:QDESIGNER_WIDGET_EXPORT。
保存文件,选择Release模式构建。
在输出目录下找到生成的库文件。
将这两个库文件拷贝到Qt库的designer路径下。本人Qt库安装在C盘根目录,所以designer路径为:C:\Qt\4.8.4\plugins\designer。
在Qt Creator中创建一个Qt窗口应用程序,将自定义控件的dll和lib文件,以及ipedit.h头文件,都拷贝到当前窗口程序的工程目录下。
右击工程名选择"添加库",选择"外部库",库文件路径选择当前工程路径。
使用Qt Designer打开ui文件。
向下拉左侧的控件栏,就可以看到自定义窗口部件“IpEdit”,可以像内置控件一样直接拖入窗口内使用。
最后构建,运行。可以看到自定义控件工作正常。
#include "myedit.h" #include <QPushButton> #include <QHBoxLayout> Myedit::Myedit(QWidget *parent) : QWidget(parent) { QPushButton *button1 = new QPushButton; QPushButton *button2 = new QPushButton; button1->setText("My"); button2->setText("plugin"); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(button1); mainLayout->addWidget(button2); this->setLayout(mainLayout); }
以Release模式构建,会弹出"自定义执行挡",不要管,直接关闭即可,在你所建立的工程目录下并找到如图所示的两个文件.dll和.lib。
将编译完成后,在输出目录下,将生成的dll文件和lib文件一起拷贝到Qt的插件目录下,以我使用的Qt 5.6.3为例。在Qt 5.6.3的安装目录E:\qt5.6\5.6.3\msvc2013下,找到plugins目录,在其中找到designer目录,然后把dll和lib放进去,完整路径为:E:\qt5.6\5.6.3\msvc2013\plugins\designer。
使用Qt Designer打开ui文件。
这时候如果用Debug版本运行则会报QWidget: Must construct a QApplication before a QPaintDevice
网上搜了一下好像是Debug/Release的Dll混到一起,如果要用Debug版本的话就把之前的构建Debug模式构建。
自定义插件的发布版本不同,导致动态库出现问题。
用Release版本运行则可以实现想要的效果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。