自定义 Widget 子类 QmyBattery
Qt 的 UI 设计器提供了很多 GUI 设计的界面组件,可以满足常见的界面设计需求。但是某些时候需要设计一些特殊的界面组件,而在 UI 设计器的组件面板里根本没有合适的组件,这时就需要设计自定义的界面组件。
所有界面组件的基类是 QWidget,要设计自定义的界面组件,可以从 QWidget 继承一个自定义的类,重定义其 paintEvent()
事件,利用 Qt 的绘图功能绘制组件外观,并实现需要的其他功能。
例如,假设需要设计一个如图所示的电池电量显示组件,用于电池使用或充电时显示电量,但是在 UI 设计器的组件面板没有现成的组件。这就需要设计一个自定义的 Widget 组件。
为此,设计一个从 QWidget 继承的类 QmyBattery。创建 C++类,可以单击 Qt Creator 的"File"->"New File or Project"菜单选项,在出现的对话框选择 C++组里面的 C++Class,在向导中设置类的名称,并选择基类为 QWidget。定义 QmyBattery 类的头文件如下:
cpp
#include <QWidget>
#include <QColor>
class QmyBattery : public QWidget
{
Q_OBJECT
//自定义属性
Q_PROPERTY(int powerLevel READ powerLevel WRITE setPowerLevel NOTIFY powerLevelChanged)
private:
QColor mColorBack=Qt::white;//背景颜色
QColor mColorBorder=Qt::black;//电池边框颜色
QColor mColorPower=Qt::green;//电量柱颜色
QColor mColorWarning=Qt::red;//电量短缺时的颜色
int mPowerLevel=60;//电量0-100
int mWarnLevel=20;//电量低警示阈值
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
public:
explicit QmyBattery(QWidget *parent = 0);
void setPowerLevel(int pow);//设置当前电量
int powerLevel();
void setWarnLevel(int warn);//设置电量低阈值
int warnLevel();
QSize sizeHint();//报告缺省大小
signals:
void powerLevelChanged(int );
public slots:
};
在 private 部分定义了几个私有变量,主要是各种颜色的定义,当前电量值 mPowerLevel 和电量低阈值 mWarnLevel;protected 部分重定义了 patinEvent()
事件;public 部分定义了用来读取和设置当前电量值、电量低阈值的好函数,还定义了 sizeHint()
函数,用于返回组件缺省大小。
定义了一个信号 powerLevelChanged(int)
,在当前电量值改变的时候发射该信号,使用 QmyBattery 类时可以设计槽函数对此信号做处理。下面是具体的实现代码,复杂的部分是 paintEvent()
事件函数里绘制界面功能实现,这里设置了窗口逻辑坐标,所以当组件大小变化时,绘制的电池大小也会自动变化。
cpp
void QmyBattery::paintEvent(QPaintEvent *event)
{ //界面组件的绘制
Q_UNUSED(event);
QPainter painter(this);
QRect rect(0,0,width(),height()); //viewport矩形区
painter.setViewport(rect);//设置Viewport
painter.setWindow(0,0,120,50); // 设置窗口大小,逻辑坐标
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
//绘制电池边框
QPen pen;//设置画笔
pen.setWidth(2); //线宽
pen.setColor(mColorBorder); //划线颜色
pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等
pen.setCapStyle(Qt::FlatCap);//线端点样式
pen.setJoinStyle(Qt::BevelJoin);//线的连接点样式
painter.setPen(pen);
QBrush brush;//设置画刷
brush.setColor(mColorBack); //画刷颜色
brush.setStyle(Qt::SolidPattern); //画刷填充样式
painter.setBrush(brush);
rect.setRect(1,1,109,48);
painter.drawRect(rect);//绘制电池边框
brush.setColor(mColorBorder); //画刷颜色
painter.setBrush(brush);
rect.setRect(110,15,10,20);
painter.drawRect(rect); //画电池正极头
//画电池柱
if (mPowerLevel>mWarnLevel)
{ //正常颜色电量柱
brush.setColor(mColorPower); //画刷颜色
pen.setColor(mColorPower); //划线颜色
}
else
{ //电量低电量柱
brush.setColor(mColorWarning); //画刷颜色
pen.setColor(mColorWarning); //划线颜色
}
painter.setBrush(brush);
painter.setPen(pen);
if (mPowerLevel>0)
{
rect.setRect(5,5,mPowerLevel,40);
painter.drawRect(rect);//画电池柱
}
//绘制电量百分比文字
QFontMetrics textSize(this->font());
QString powStr=QString::asprintf("%d%%",mPowerLevel);
QRect textRect=textSize.boundingRect(powStr);//得到字符串的rect
painter.setFont(this->font());
pen.setColor(mColorBorder); //划线颜色
painter.setPen(pen);
painter.drawText(55-textRect.width()/2,
23+textRect.height()/2,
powStr);
}
QmyBattery::QmyBattery(QWidget *parent) : QWidget(parent)
{
// setPalette(QPalette(mColorBack));
// setAutoFillBackground(true);
// this->resize(120,50);
}
void QmyBattery::setPowerLevel(int pow)
{ //设置当前电量值
mPowerLevel=pow;
emit powerLevelChanged(pow); //触发信号
repaint();
}
int QmyBattery::powerLevel()
{ //读取当前电量值
return mPowerLevel;
}
void QmyBattery::setWarnLevel(int warn)
{//设置电量低阈值
mWarnLevel=warn;
repaint();
}
int QmyBattery::warnLevel()
{//读取电量低阈值
return mWarnLevel;
}
QSize QmyBattery::sizeHint()
{//报告缺省大小,调整比例
int H=this->height();
int W=H*12/5;
QSize size(W,H);
return size;
}
自定义 Widget 组件的使用
实现了自定义类后,如果是使用代码创建 QmyBattery 类对象,其使用与一般的组件类是一样的;如果是在 UI 设计器中使用 QmyBattery,则需要采用提升的方法(promotion)。
拖一个 QWidget 组件在窗口上,右击选择"提升为(Promote to)",就会出现如下所示对话框:
在基类名称的下来列表里选择 QWidget,将提升后的类名设置为 QmyBattery,头文件名会自动生成。可以将设置添加到已提升的列表里,以便重复使用。在提供组件之后,虽然 QWidget 已经被提升为 QmyBattery 类,但是在这个组件的"Go to slot"对话框没有 QmyBattery 类的 powerLevelChanged(int)
信号,无法采用可视化方法生成信号的槽函数。在主窗口上放置一个 QSlider 组件和一个 QLabel 组件。华东标尺改变数据时,设置为 battery 的当前电量,其 valueChanged()信号的槽函数代码如下:
cpp
void Widget::on_horizontalSlider_valueChanged(int value)
{
ui->battery->setPowerLevel(value);
QString str=QStringLiteral("当前电量:")+QString::asprintf("%d %%",value);
ui->LabInfo->setText(str);
}
下一篇文章说说如何创建 Qt Designer 的插件,可以直接在 UI 设计器中拖动使用。