如何创建一个自定义的QWidget控件并导入Qt Designer 中进行使用?
根据向导创建控件工程,并填写控件类名称、说明、以及docxml默认添加的属性信息
Qt Designer自定义控件主要是集成、实现QDesignerCustomWidgetInterface接口,在Qt Designer设计器加载ui的时候,会加载环境中这些实现了该接口的特殊图形控件。
这个工程创建后,会生成myclockplugin类,其中domXml、name、group可以根据自己的需求进行修改,默认也可以。
然后,MyClock类才是真正实现自己定义的QWidget,可以重新绘制图形控件,也可以添加新的属性、方法等等。
这里以MyClock是参照Qt 例子中Analog Clock example做的一个钟表,主要就是在paintEvent函数中重新绘制了钟表图形,具体可以参照Analog Clock的代码。
编译构建自定义控件工程,会生成自定义控件的动态库文件
将myclockplugin.dll安装到Qt环境中,也就是C:\Qt\Qt5.9.1\Tools\QtCreator\bin\plugins\designer路径下。
重启Qt Creator工程后,打开Qt Designer工具就能在左侧列表中找到自定义的控件加载到设计器列表中。
所有集成QObject的Qt类对象,都通过Qt的元对象系统查询到它,获取对象的属性、方法、信号等等,这里想要给自定义的控件追加一个属性,并想显示到设计器的列表中,需要给控件类追加Q_PROPERTY属性,具体如下:
class QDESIGNER_WIDGET_EXPORT MyClock : public QWidget
{
Q_OBJECT
Q_ENUMS(InputMode)
Q_PROPERTY(InputMode inputMode READ inputMode WRITE setInputMode
public:
MyClock(QWidget *parent = 0);
enum InputMode{
ZONE_0 = 0, //float number mode
ZONE_1,
ZONE_2//Degree second minute mode
};
InputMode inputMode()const;
void setInputMode(const InputMode mode);
public slots:
void setTimeZone(int hourOffset);
signals:
void updated(QTime currentTime);
protected:
void paintEvent(QPaintEvent *event) override;
private:
int timeZoneOffset;
InputMode m_Mode;
};
MyClock::MyClock(QWidget *parent) :
QWidget(parent)
,timeZoneOffset(0)
,m_Mode(ZONE_0)
{
//! [3] //! [4]
QTimer *timer = new QTimer(this);
//! [4] //! [5]
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
//! [5] //! [6]
timer->start(1000);
//! [6]
setWindowTitle(tr("Analog Clock"));
resize(400, 400);
//! [7]
}
void MyClock::paintEvent(QPaintEvent *)
//! [8] //! [10]
{
static const QPoint hourHand[3] = {
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -40)
};
static const QPoint minuteHand[3] = {
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -70)
};
QColor hourColor(127, 0, 127);
QColor minuteColor(0, 127, 127, 191);
int side = qMin(width(), height());
QTime time = QTime::currentTime();
time = time.addSecs(timeZoneOffset);
//! [10]
//! [11]
QPainter painter(this);
//! [11] //! [12]
painter.setRenderHint(QPainter::Antialiasing);
//! [12] //! [13]
painter.translate(width() / 2, height() / 2);
//! [13] //! [14]
painter.scale(side / 200.0, side / 200.0);
//! [9] //! [14]
//! [15]
painter.setPen(Qt::NoPen);
//! [15] //! [16]
painter.setBrush(hourColor);
//! [16]
//! [17] //! [18]
painter.save();
//! [17] //! [19]
painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
painter.drawConvexPolygon(hourHand, 3);
painter.restore();
//! [18] //! [19]
//! [20]
painter.setPen(hourColor);
//! [20] //! [21]
for (int i = 0; i < 12; ++i) {
painter.drawLine(88, 0, 96, 0);
painter.rotate(30.0);
}
//! [21]
//! [22]
painter.setPen(Qt::NoPen);
//! [22] //! [23]
painter.setBrush(minuteColor);
//! [24]
painter.save();
painter.rotate(6.0 * (time.minute() + time.second() / 60.0));
painter.drawConvexPolygon(minuteHand, 3);
painter.restore();
//! [23] //! [24]
//! [25]
painter.setPen(minuteColor);
//! [25] //! [26]
//! [27]
for (int j = 0; j < 60; ++j) {
if ((j % 5) != 0)
painter.drawLine(92, 0, 96, 0);
painter.rotate(6.0);
}
//! [27]
}
void MyClock::setTimeZone(int hourOffset)
{
setInputMode(InputMode(hourOffset));
}
MyClock::InputMode MyClock::inputMode() const
{
return m_Mode;
}
void MyClock::setInputMode(const InputMode mode)
{
timeZoneOffset = qMin(qMax(-12, int(mode)), 12) * 3600;
update();
}
Q_PROPERTY 追加一个修改时区的属性值,编译完成后,安装到Qt Tool中,重启就可以在设计器中修改该属性。
创建一个工程,把MyClock添加到自己的ui中,注意需要把MyClock插件的lib、头文件引到工程内,方便运行调试
inputMode也在右侧属性列表中,可以在设计器里直接设置属性值
在声明MyClock类的时候,追加了QDESIGNER_WIDGET_EXPORT,这样能够保证MyClock类内的信号、槽函数等能够正确地被Qt Designer进入进去,比如:
public slots:
void setTimeZone(int hourOffset);
signals:
void updated(QTime currentTime);
setTimeZone和updated就可以在设计器中操作信号、操处理。
运行demo,当更改时区后,钟表和timeEdit也跟着更新,这就是通过设计器内绑定的信号槽关系处理的,这些都不需要再在demo工程中去重新代码来实现了。