在实际的项目开发中,通常情况下使用QSS即可改变原生控件外观,而QSS是通过Qt的样式引擎解析并设置样式参数,在paintEvent中通过这些样式参数绘制的。尽管如此,Qt的原生控件或许仍旧满足不了我们的需求,所以经常会遇到需要自定义控件的场合。例如需要一个开关样式的按钮,Qt中并没有提供。下面就分享一下Qt自定义控件的一些方法。
在Qt中自定义控件的方法有多种,常用的方法有:
顾名思义,组合控件就是将多个控件元素组合为一个整体,然后以这个整体为单位进行界面编程。
下面是一个非常简单的组合控件的示例,他将一个标签控件和按钮控件组合为一个整体:
#include
class MyCustomWidget : public QWidget {
public:
MyCustomWidget(QWidget *parent = nullptr) : QWidget(parent) {
QLabel *label = new QLabel("Hello, World!");
QPushButton *button = new QPushButton("Click Me");
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(label);
layout->addWidget(button);
setLayout(layout);
connect(button, &QPushButton::clicked, this, &MyCustomWidget::onButtonClicked);
}
private slots:
void onButtonClicked() {
qDebug() << "Button clicked!";
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyCustomWidget widget;
widget.show();
return app.exec();
}
以上代码,是一个非常简单的组合控件示例,在点击按钮时可以更改标签控件的文字。如果做更复杂的组合控件,或许需要将内部控件的一些公共方法提取到该组合控件中,或者需要自定义信号等等。
自行绘制控件相较于组合控件稍微复杂些,至少需要自行实现绘图事件。根据实际情况选择需要继承的基类,一般情况下继承QWidget,QWidget是所有界面类的基类。当然,也可以继承QPushButton、QLabel等等控件,根据实际情况而定。
下面是通过继承QWidget自定义电池的示例代码。
头文件:
class PowerFrame:public QWidget{
Q_OBJECT
public:
explicit PowerFrame(QWidget* parent=nullptr);
~PowerFrame();
void setPower(int power);
void setCharge(bool isCharging);
protected:
void paintEvent(QPaintEvent *) override;
private:
ColorChange* colorChange;
QString _startColor="#FF0000";
QString _endColor="#00FF00";
QString _borderColor = "#818181";
QString _charingColor = "#FFFFFF";
int _min=0;
int _max=100;
int _currentNum;
RGB_COLOR _currentColor;
bool _isCharging = false;
};
源文件
PowerFrame::PowerFrame(QWidget* parent):QWidget(parent){
colorChange = new ColorChange();
colorChange->setRange(_min,_max);
colorChange->setStartColor(_startColor);
colorChange->setEndColor(_endColor);
}
PowerFrame::~PowerFrame(){
delete colorChange;
}
void PowerFrame::setPower(int currentNum){
if(currentNum>=0&¤tNum<=100){
_currentNum = currentNum;
_currentColor = colorChange->getColor(currentNum);
update();
}
}
void PowerFrame::setCharge(bool isCharging){
_isCharging = isCharging;
update();
}
void PowerFrame::paintEvent(QPaintEvent *){
setFixedSize(height()*2.3,height());
QPainter painter(this);
painter.save();
painter.setRenderHint(QPainter::Antialiasing,true);
QPen pen;
pen.setColor(QColor(_borderColor));
pen.setWidthF(2);
painter.setPen(pen);
QRectF re(1,1,rect().width()-5,rect().height()-2);
painter.drawRoundedRect(re,2,2);
painter.setBrush(QBrush(QColor(_borderColor)));
painter.setPen(Qt::NoPen);
QRectF re1(rect().width()-4,(height()-10)/2.0,4,10);
painter.drawRoundedRect(re1,2,2);
painter.setBrush(QBrush(QColor(_currentColor.r,_currentColor.g,_currentColor.b)));
QRectF re2(3,3,(rect().width()-9)/100.0*_currentNum,rect().height()-6);
painter.drawRoundedRect(re2,2,2);
if(_isCharging){
double w = width()-5;
QPointF robotArrow[6]={
QPointF(w/4.0*2,height()/5.0),
QPointF(w/4.0*2,height()/5.0*2),
QPointF(w/4.0*3,height()/5.0),
QPointF(w/4.0*2,height()/5.0*4),
QPointF(w/4.0*2,height()/5.0*3),
QPointF(w/4.0,height()/5.0*4),
};
painter.setBrush(QBrush(QColor(_charingColor)));
painter.drawPolygon(robotArrow,6);
}
painter.restore();
}
上面是一个非常简单的绘制电池电量控件的代码。比较遗憾的是,该示例中并没有自定义信号,并发射它。通常来说,自定义控件都会需要定义至少一个信号,用于向外界传递该控件一些状态的变化。另外该类的成员变量ColorChange指针,为颜色渐变类的指针;RGB_COLOR为存储RGB值的结构体。
可以参考自定义标题栏文章:
链接:【Qt】自定义标题栏_qmainwindow自定义标题栏_卡钦斯基的博客-CSDN博客