在某些时候需要设计特殊的界面组件,而在UI设计器的组件面板里没有合适的组件,这时候就需要设计自定义的界面组件。
所有的界面组件的基类是QWidget,要设计自定义的界面组件,可以从QWidget继承一个自定义的类,重定义它的paintEvent()事件,用Qt的绘图功能绘制组件外观,并实现需要的功能。
例如我们需要设计一个电池电量显示的组件,如下图所示。
1. 设计一个从QWidget继承的QmyBattery类。
类QmyBattery.h文件的完整代码如下
#pragma once
#include
#include
class QmyBattery : public QWidget
{
Q_OBJECT
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);
};
下面是QmyBattery类的实现代码,主要是paintEvent()事件函数的绘制功能。
void QmyBattery::paintEvent(QPaintEvent *event)
{
//界面组件的绘制
Q_UNUSED(event);
QPainter painter(this);
QRect rect(0, 0, width(), height());
painter.setViewport(rect);
painter.setWindow(0, 0, 140, 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, 129, 48);
painter.drawRect(rect); //绘制电池边框
brush.setColor(mColorBorder);
painter.setBrush(brush);
rect.setRect(130, 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 /*= 0*/):QWidget(parent)
{
}
void QmyBattery::setPowerLevel(int pow)
{
mPowerLevel = pow;
emit powerLevelChanged(pow);
repaint();
}
int QmyBattery::powerLevel()
{
return mPowerLevel;
}
void QmyBattery::setWarnLevel(int warn)
{
mWarnLevel = warn;
}
int QmyBattery::warnLevel()
{
return mWarnLevel;
}
QSize QmyBattery::sizeHint()
{
int H = this->height();
int W = this->width();
QSize size(W, H);
return size;
}
2. 自定义Widget组件的使用
实现了QmyBattery类之后,如果是用代码创建QmyBattery类对象,它的使用和一般的组件类是一样的;若是在UI设计器中使用QmyBattery,则要用提升法。
先在窗体上放置一个QWidget类组件,然后右击,点击“提升为...”菜单,出现如下对话框。
在提升的类名称处填写刚刚创建的类名QmyBattery,头文件会自动生成,这是点击“添加”按钮,再点击“提升”,此时QWidget组件提升为QmyBattery类。右侧对象查看器可以看到类名的变化。
在主窗口放置一个QSlider组件和QLabel组件,当滑动标尺改变数值时,设置battery当前的电量值,其valueChanged()信号的槽函数如下。
void MainWindow::on_slider_valueChanged(int value)
{
ui.battery->setPowerLevel(value);
QString str = QString("当前电量: ") + QString::asprintf("%d %", value);
ui.label->setText(str);
}
编译运行后效果如下图所示。