Qt学习笔记外观篇(五):子类化窗口部件类

来源:互联网 发布:胖胡斐 淘宝商城 编辑:程序博客网 时间:2024/05/14 18:29

 如前所述,自定义外观的第三种方法是子类化窗口部件类。子类化窗口类适用于能够经常使用的,具有鲜明特性的部件。子类化窗口类更多的适用于定制功能而非外观。

 子类化窗口部件类的过程就是重新实现事件处理函数的过程。

 下面是自定义圆形按钮类:

 

 class RoundButton : public QPushButton {    Q_OBJECT public:    RoundButton(QWidget * parent = 0);    RoundButton(const QString & text, QWidget * parent = 0);    RoundButton(const QIcon & icon,const QString & text ,QWidget * parent = 0);    virtual ~RoundButton();QSize sizeHint();QSize minimumSize();    void setColor(QColor color)         { m_color = color; }    void setHighlight(QColor highlight) { m_highlight = highlight; }    void setShadow(QColor shadow)       { m_shadow = shadow; }    //Range: 0.0 [invisible] - 1.0 [opaque]    void setOpacity(qreal opacity)        { m_opacity = opacity; }    //Range: 0 [rectangle] - 99 [oval]    void setRoundness(int roundness)      { m_roundness = roundness; } protected:    void paintEvent(QPaintEvent * pe);     //void drawButton(QPainter* pe);    void enterEvent(QEvent * e);    void leaveEvent(QEvent * e);    void mousePressEvent(QMouseEvent * e);    void mouseReleaseEvent(QMouseEvent * e); private:    QRect calculateIconPosition(QRect button_rect, QSize icon_size);void adjustGeometry(); private:    bool m_hovered;    bool m_pressed;    QColor m_color;    QColor m_highlight;    QColor m_shadow;    qreal m_opacity;    int m_roundness; };
我们需要重新实现paintEvent(),绘制按钮的时候,我们需要参考一些状态:鼠标是否悬停在按钮上,鼠标是否被按下。所以我们需要重新实现其他的一些事件处理函数,来记录这些状态的变化。

RoundButton::RoundButton(QWidget * parent)    : QPushButton(parent),    m_hovered(false),    m_pressed(false),    m_color(Qt::gray),    m_highlight(Qt::lightGray),    m_shadow(Qt::black),    m_opacity(1.0),    m_roundness(0){}RoundButton::RoundButton(const QString & text, QWidget * parent)    : QPushButton(text, parent),    m_hovered(false),    m_pressed(false),    m_color(Qt::gray),    m_highlight(Qt::lightGray),    m_shadow(Qt::black),    m_opacity(1.0),    m_roundness(0){}RoundButton::RoundButton(const QIcon & icon,const QString & text ,QWidget * parent)    : QPushButton(icon,text,parent),    m_hovered(false),    m_pressed(false),    m_color(Qt::gray),    m_highlight(Qt::lightGray),//强光(效果)    m_shadow(Qt::black),    m_opacity(1.0),// 不透明    m_roundness(0)// 圆,圆度{}RoundButton::~RoundButton(){}QSize RoundButton::sizeHint(){return QSize(200,200);}QSize RoundButton::minimumSize(){return QSize(100,100);}

上面是一些无关紧要的函数。下面是获取鼠标状态的函数:

void RoundButton::enterEvent(QEvent * e){    m_hovered = true;    this->repaint();    QPushButton::enterEvent(e);}void RoundButton::leaveEvent(QEvent * e){    m_hovered = false;    this->repaint();    QPushButton::leaveEvent(e);}void RoundButton::mousePressEvent(QMouseEvent * e){    m_pressed = true;    this->repaint();    QPushButton::mousePressEvent(e);}void RoundButton::mouseReleaseEvent(QMouseEvent * e){    m_pressed = false;    this->repaint();    QPushButton::mouseReleaseEvent(e);}

这些函数,确定了鼠标是否按下,是否悬停。下面进入我们自定义外观时最关键的函数paintEvent():

void RoundButton::paintEvent(QPaintEvent * pe)        //void RoundButton::drawButton(QPainter* pe){    Q_UNUSED(pe);    QPainter painter(this);    painter.setRenderHint(QPainter::Antialiasing);//抗锯齿处理    //test for state changes    QColor button_color;    if(this->isEnabled())    {        m_hovered ? button_color = m_highlight : button_color = m_color;        if(m_pressed)        {            button_color = m_highlight.darker(250);        }    }    else    {        button_color = QColor(50, 50, 50);    }adjustGeometry();QRect button_rect=this->rect();    //outline    painter.setPen(QPen(QBrush(Qt::red), 2.0));    //main button    QPainterPath painter_path;    //painter_path.addRoundRect(1, 1, button_rect.width() - 2, button_rect.height() - 2, m_roundness, m_roundness);    painter_path.addEllipse(0,0,button_rect.height(),button_rect.height());    painter.setClipPath(painter_path);    //icon    QString text = this->text();    QIcon icon = this->icon();    if(m_pressed==false){    if( !icon.isNull())    {        QSize icon_size =button_rect.size();        QRect icon_position = this->calculateIconPosition(button_rect,icon_size);        painter.setOpacity(1.0);        painter.drawPixmap(icon_position, QPixmap(icon.pixmap(icon_size)));    }    else    {       painter.fillPath(painter_path,button_color);   QFont font = painter.font();   QFontMetrics fm(font);   int width = fm.width(text);   int height=fm.height();   QSize text_size =QSize(width,height);   QRect text_position = this->calculateIconPosition(button_rect,text_size);       painter.setOpacity(1.0);       painter.drawText(text_position,text);    }    }}

具体的过程如下:首先是根据是否悬停,是否按下确定按钮的渲染颜色,然后将按钮的大小调整为正方形,根据正方形得到圆形按钮的轨迹,然后在圆形按钮的区域内绘制图片或者文字。下面是两个辅助函数:adjustGeometry()用于将按钮大小调整为正方形;calculateIconPosition()用于确定文字或图片的绘制位置。

QRect RoundButton::calculateIconPosition(QRect button_rect, QSize icon_size){    int x = (button_rect.width() / 2) - (icon_size.width() / 2);    int y = (button_rect.height() / 2) - (icon_size.height() / 2);    int width = icon_size.width();    int height = icon_size.height();    QRect icon_position;    icon_position.setX(x);    icon_position.setY(y);    icon_position.setWidth(width);    icon_position.setHeight(height);    return icon_position;}void RoundButton::adjustGeometry(){QRect buttonRect=this->geometry();int dx=0,dy=0;if(buttonRect.width()>buttonRect.height()){dx=(buttonRect.width()-buttonRect.height())/2;buttonRect.setX(buttonRect.x()+dx);buttonRect.setWidth(buttonRect.height());}else{dy=(buttonRect.height()-buttonRect.width())/2;buttonRect.setY(buttonRect.y()+dy);buttonRect.setHeight(buttonRect.width());}this->setGeometry(buttonRect);/*//QRect button_rect = QRect(1, 1, 40, 40);QRect button_rect =(rect().width()>rect().height())?QRect((rect().width()-rect().height())/2,0,rect().height(),rect().height()):QRect(0,(rect().height()-rect().width())/2,rect().width(),rect().width());this->setFixedSize(button_rect.width(),button_rect.height());*/}

使用:

#include <QApplication>#include<QDialog>#include<QLabel>#include<QLayout>#include"roundbutton.h"int main(int argc, char *argv[]){    QApplication app(argc, argv);    QDialog dialog;    QLabel label(QObject::tr("hello world"),&dialog);    RoundButton button(QObject::tr("hello"),&dialog);    button.setIcon(QIcon(QObject::tr(":/images/play.png")));    button.setMinimumSize(100,100);QVBoxLayout layout(&dialog);layout.addWidget(&label);layout.addWidget(&button);dialog.setLayout(&layout);    dialog.show();    return app.exec();}

至此,我们三种自定义外观的方法就总结完了,在应用程序级上自定义外观,我们选用qss,但是像圆形按钮之类这些特殊的,经常用的部件,我们可以通过子类化窗口部件来实现,如果是大型应用程序,需要自己的风格,这时候再考虑QStyle。

0 0
原创粉丝点击