在使用Qt Designer设计窗体界面时,我们可以使用Widget Box里的窗体控件非常方便的绘制界面,比如拖进去一个按钮,一个文本编辑器等。虽然Qt Designer里的控件可以满足我们大部分的需求,但是有时候,也会产生一些自定义的需要,比如Switch开关。
下面就以此为例,讲解一下如何创建自定义的窗体控件。
第一步:创建QtDesigner自定义控件工程
打开Qt Creator,创建一个Qt4 设计师自定义控件,如下图所示:
![Qt Designer自定义插件(QSwitchButton)](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton).PNG)
添加自定义类QSwitchButton
![Qt Designer自定义插件(QSwitchButton)1](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)1.PNG)
添加说明(可以忽略,函数中可以修改):
组:该控件所属的组中的Qt Designer的小工具盒;
工具提示:一个简短的说明,以帮助用户识别Qt Designer中的部件;
这是什么:为Qt Designer用户设计的部件一个较长的描述
![Qt Designer自定义插件(QSwitchButton)1-1](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)1-1.PNG)
dom XML:描述了部件的属性,例如:对象名称、大小提示,以及其它标准的QWidget属性的描述。
![Qt Designer自定义插件(QSwitchButton)1-2](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)1-2.PNG)
定义插件名称:
![Qt Designer自定义插件(QSwitchButton)2](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)2.PNG)
第二步:编译控件工程
为了淌通整个自定义控件的编写流程,我们先不做任何更改,切换为Release版本,直接编译一下。
第三步:部署插件
编译完成后,在输出目录下,将生成的dll文件和lib文件一起拷贝到Qt designer和Qt Creator的插件目录下,以我使用的Qt为例完整路径为:
C:\Qt\Qt5.9.1\5.9.1\msvc2015\plugins\designer。
C:\Qt\Tools\QtCreator\bin\plugins\designer
之后,启动Qt designer或Qt Creator,创建一个窗体,此时就会发现在左侧的Buttons里出现了我们自己的Switch Button控件,我们可以像使用其它控件一样,把我们自己的控件拖绘到窗体上,如下图所示:
如果自定义控件没有出现在Widgetbox里,那么此时你可以通过【帮助-关于插件】菜单,打开插件信息对话框,点击刷新按钮,只要你没有忘记把dll和lib文件拷贝到正确的位置,插件都会自动识别并加载。对于其它版本的Qt也一样,比如我自己的电脑里安装了好几个版本的Qt,对于其它版本的Qt,做法也是一样,只需要把插件工程生成的dll和lib文件放置到相应版本的插件目录下去即可。
在自动向导创建的插件QSwitchButtonPlugin
继承了接口QDesignerCustomWidgetInterface
。
#ifndef QSWITCHBUTTONPLUGIN_H
#define QSWITCHBUTTONPLUGIN_H
#include
class QSwitchButtonPlugin : public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
#endif // QT_VERSION >= 0x050000
public:
QSwitchButtonPlugin(QObject *parent = 0);
//true表示部件将用来保存子部件,否则为false
bool isContainer() const;
//如果该部件已被初始化,则返回true;否则返回false
bool isInitialized() const;
//Qt Designer的插件箱中小窗口的图标
QIcon icon() const;
//描述了部件的属性,例如:对象名称、大小提示,以及其它标准的QWidget属性的描述。
QString domXml() const;
//该控件所属的组中的Qt Designer的小工具盒
QString group() const;
//头文件必须包含在使用该插件的应用程序的。此信息存储在UI文件中,并将由UIC创建用于包含自定义插件形式的代码合适的#includes语句。
QString includeFile() const;
//提供了插件的类名称
QString name() const;
//一个简短的说明,以帮助用户识别Qt Designer中的部件
QString toolTip() const;
//为Qt Designer用户设计的部件一个较长的描述
QString whatsThis() const;
//一个指向自定义窗口小部件的QWidget指针实例,构建了所提供的父母。注:createWidget()是一个工厂方法,只负责创建小部件的功能。自定义窗口小部件的属性将不可用,直到load()返回。
QWidget *createWidget(QWidget *parent);
//设置了自定义窗口部件扩展等功能
void initialize(QDesignerFormEditorInterface *core);
private:
bool m_initialized;
};
#endif
可以看到我们在向导中设置的一些信息在相应的函数中体现出来了。
domXml() 函数的注意事项:
domXml()函数返回一个UI文件代码段,使用Qt Designer窗口工厂创建一个自定义窗口部件和使用特性。从Qt4.4开始,Qt Designer的窗口部件中允许一个完整的UI文件来描述一个自定义窗口部件。UI文件可以使用标签加载。指定标签允许添加元素,其中包含自定义窗口部件的其它信息。如果不需要更多的信息,那么标签已经足够了。如果自定义窗口部件不提供合理的尺寸,有必要通过在子类的domXml()函数返回的字符串中指定默认的位置大小(geometry)。
domXml()函数的另一个特点是,如果它返回一个空字符串,部件不会安装在Qt Designer的窗口部件盒中。然而,它仍然可以被其它形式的部件所使用。这个特性用来隐藏部件,不应由用户显式地创建,但需要其它部件创建。
标签的属性:
属性 | 呈现形式 | 值 | 内容 |
---|---|---|---|
language |
可选项 | “c++”,”jambi” | 这个属性指定了自定义窗口部件提供的语言。主要有防止C++插件出现在Qt Jambi中。 |
displayname |
可选项 | 类名 | 属性的值将出现在小工具框,可以用来剥去命名空间。 |
如一个基本的domxml:
QString QSwitchButtonPlugin::domXml() const
{
return QLatin1String("\"Switch Button\"\n\"QSwitchButton\" name=\"qSwitchButton\">\n \n \n");
}
直接上代码
qswitchbutton.h
注意:
#include
以上版本为#include
QDESIGNER_WIDGET_EXPORT
宏。否则集成到Qt Creator 中编译会报错。不加的话可以在设计器中加载,但是编译会报错#ifndef QSWITCHBUTTON_H
#define QSWITCHBUTTON_H
#include
#include
#include
#include
namespace Ui {
class QSwitchButton;
}
class QDESIGNER_WIDGET_EXPORT QSwitchButton : public QWidget
{
Q_OBJECT
public:
QSwitchButton(QWidget *parent = 0);
~QSwitchButton();
private:
Ui::QSwitchButton *ui;
public:
// 返回开关状态 - 打开:true 关闭:false
bool isToggled() const;
// 设置开关状态
void setToggle(bool checked);
// 设置背景颜色
void setBackgroundColor(QColor color);
// 设置选中颜色
void setCheckedColor(QColor bcolor, QColor tcolor);
// 设置不可用颜色
void setDisbaledColor(QColor color);
//设置画笔
void setDrawPen(QPen bpen = Qt::NoPen, QPen tpen = Qt::NoPen);
protected:
// 绘制开关
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
// 大小改变事件
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
// 缺省大小
QSize sizeHint() const Q_DECL_OVERRIDE;
QSize minimumSizeHint() const Q_DECL_OVERRIDE;
signals:
// 状态改变时,发射信号
void toggled(bool checked);
private slots:
private:
bool m_bChecked; // 是否选中
QColor m_background; // 背景颜色
QColor m_checkedColor; // 选中颜色
QColor m_disabledColor; // 不可用颜色
QColor m_thumbColor; // 拇指颜色
QColor m_thumbcheckedColor;
qreal m_radius0, m_radius1; // 圆角
qint16 m_width, m_height;
qreal m_nX; // x点坐标
qreal m_nY; // y点坐标
qint16 m_nMargin; // 外边距
QPen backPen, thumbPen;
int direction; //开关方向 ,1水平,-1竖直
void TogglePosition(void);
};
#endif
qswitchbutton.cpp
#include "qswitchbutton.h"
#include
#include "ui_qswitchbutton.h"
QSwitchButton::QSwitchButton(QWidget *parent) :
QWidget(parent),
ui(new Ui::QSwitchButton),
m_width(16),
m_height(16),
m_bChecked(false),
m_radius0(8.0),
m_radius1(5.0),
m_nMargin(3),
m_checkedColor(75, 216, 99),
m_thumbcheckedColor(Qt::white),
m_thumbColor(Qt::white),
m_disabledColor(190, 190, 190),
m_background(Qt::gray),
backPen(Qt::NoPen),
thumbPen(Qt::NoPen),
direction(1)
{
ui->setupUi(this);
// 鼠标滑过光标形状 - 手型
setCursor(Qt::PointingHandCursor);
}
QSwitchButton::~QSwitchButton()
{
delete ui;
}
bool QSwitchButton::isToggled() const
{
return m_bChecked;
}
void QSwitchButton::setToggle(bool checked)
{
m_bChecked = checked;
TogglePosition();
}
void QSwitchButton::setBackgroundColor(QColor color)
{
m_background = color;
}
void QSwitchButton::setCheckedColor(QColor bcolor, QColor tcolor)
{
m_checkedColor = bcolor;
m_thumbcheckedColor = tcolor;
}
void QSwitchButton::setDisbaledColor(QColor color)
{
m_disabledColor = color;
}
void QSwitchButton::setDrawPen(QPen bpen, QPen tpen)
{
backPen = bpen;
thumbPen = tpen;
}
void QSwitchButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
backPen = QPen(QColor(Qt::black),1);
painter.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
QColor background;
QColor thumbColor;
qreal dOpacity;
if (isEnabled())
{ // 可用状态
if (m_bChecked)
{ // 打开状态
background = m_checkedColor;
thumbColor = m_thumbcheckedColor;
dOpacity = 0.600;
}
else
{ //关闭状态
background = m_background;
thumbColor = m_thumbColor;
dOpacity = 0.800;
}
}
else
{ // 不可用状态
background = m_background;
dOpacity = 0.260;
thumbColor = m_disabledColor;
}
// 绘制大椭圆
painter.setPen(backPen);
painter.setBrush(background);
painter.setOpacity(dOpacity);
path.addRoundedRect(QRectF(m_nMargin, m_nMargin, m_width, m_height), m_radius0, m_radius0);
painter.drawPath(path.simplified());
// 绘制小椭圆
painter.setPen(thumbPen);
painter.setBrush(thumbColor);
painter.setOpacity(1.0);
painter.drawEllipse(QRectF(m_nX - m_radius1, m_nY - m_radius1, 2*m_radius1, 2*m_radius1));
}
void QSwitchButton::mouseDoubleClickEvent(QMouseEvent *event)
{
if (isEnabled())
{
if (event->button() == Qt::LeftButton)
{
event->accept();
m_bChecked = !m_bChecked;
emit toggled(m_bChecked);
TogglePosition();
}
else
{
event->ignore();
}
}
}
void QSwitchButton::resizeEvent(QResizeEvent *event)
{
m_width = event->size().width() - 2*m_nMargin;
m_height = event->size().height() - 2*m_nMargin;
if(m_width < m_height)
{
m_radius0 = 1.0*m_width/2;
direction = -1;
}
else
{
m_radius0 = 1.0*m_height/2;
direction = 1;
}
m_radius1 = m_radius0 - m_nMargin;
TogglePosition();
QWidget::resizeEvent(event);
}
QSize QSwitchButton::sizeHint() const
{
return minimumSizeHint();
}
QSize QSwitchButton::minimumSizeHint() const
{
return QSize(2 * (16 + m_nMargin), 16 + 2 * m_nMargin);
}
void QSwitchButton::TogglePosition(void )
{
if(m_bChecked)
{
if(direction == 1)//水平方向
{
m_nX = m_width - m_radius1;
m_nY = 2*m_nMargin+m_radius1;
}
else if(direction == -1)//竖直方向
{
m_nX = 2*m_nMargin+m_radius1;
m_nY = m_height - m_radius1;
}
else
{
m_nX = 2*m_nMargin+m_radius1;
m_nY = 2*m_nMargin+m_radius1;
}
}
else
{
m_nX = 2*m_nMargin+m_radius1;
m_nY = 2*m_nMargin+m_radius1;
}
update();
}
创建一个Qt Widgets Application项目,并将qspinsliderplugin.lib
, qspinsliderplugin.dll
,qspinsliderplugin.h
三个文件复制到当前项目目录下,在.pro中
添加qswitchbuttonplugin
库文件
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/./ -lqswitchbuttonplugin
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/./ -lqswitchbuttonplugin
INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.
也可以将qspinsliderplugin.h
复制到Qt的Include文件夹下,将qspinsliderplugin.lib
复制到Qt的Lib文件夹下,将qspinsliderplugin.dll
复制到Qt的Bin文件下,如
C:\Qt\Qt5.9.1\5.9.1\msvc2015\include
C:\Qt\Qt5.9.1\5.9.1\msvc2015\lib
C:\Qt\Qt5.9.1\5.9.1\msvc2015\bin
这样就不必对每个项目分别进行设置了。