• 44.Qt通过子类化qstyle实现自定义外观


    main.cpp

     1 #include <QtGui>
     2 
     3 #include "brozedialog.h"
     4 #include "bronzestyle.h"
     5 
     6 
     7 
     8 int main(int argc, char *argv[])
     9 {
    10     QApplication app(argc, argv);
    11     QApplication::setStyle(new BronzeStyle);
    12     BronzeDialog dialog;
    13     dialog.layout()->setSpacing(7);
    14     dialog.layout()->setMargin(7);
    15     dialog.show();
    16     return app.exec();
    17 }

    bronzestyle.h

    #ifndef BRONZESTYLE_H
    #define BRONZESTYLE_H
    
    #include <QWindowsStyle>
    
    class BronzeStyle : public QWindowsStyle
    {
        Q_OBJECT
    
    public:
        BronzeStyle() {}
    
        void polish(QPalette &palette);
        void polish(QWidget *widget);
        void unpolish(QWidget *widget);
        int styleHint(StyleHint which, const QStyleOption *option,
                      const QWidget *widget = 0,
                      QStyleHintReturn *returnData = 0) const;
        int pixelMetric(PixelMetric which, const QStyleOption *option,
                        const QWidget *widget = 0) const;
        void drawPrimitive(PrimitiveElement which,
                           const QStyleOption *option, QPainter *painter,
                           const QWidget *widget = 0) const;
        void drawComplexControl(ComplexControl which,
                                const QStyleOptionComplex *option,
                                QPainter *painter,
                                const QWidget *widget = 0) const;
        QRect subControlRect(ComplexControl whichControl,
                             const QStyleOptionComplex *option,
                             SubControl whichSubControl,
                             const QWidget *widget = 0) const;
    
    public slots:
        QIcon standardIconImplementation(StandardPixmap which,
                                         const QStyleOption *option,
                                         const QWidget *widget = 0) const;
    
    private:
        void drawBronzeFrame(const QStyleOption *option,
                             QPainter *painter) const;
        void drawBronzeBevel(const QStyleOption *option,
                             QPainter *painter) const;
        void drawBronzeCheckBoxIndicator(const QStyleOption *option,
                                         QPainter *painter) const;
        void drawBronzeSpinBoxButton(SubControl which,
                                     const QStyleOptionComplex *option,
                                     QPainter *painter) const;
    };
    
    #endif

    bronzestyle.cpp

    #include <QtGui>
    
    #include "bronzestyle.h"
    
    //通用属性
    void BronzeStyle::polish(QPalette &palette)
    {
        //设置背景
        QPixmap backgroundImage(":/images/background.png");
        //设置按钮颜色
        QColor bronze(207, 155, 95);
        //设置背景框颜色
        QColor veryLightBlue(239, 239, 247);
        //要加深的颜色
        QColor lightBlue(223, 223, 239);
        //选中后的颜色
        QColor darkBlue(95, 95, 191);
    
        //创建一个新的面板
        palette = QPalette(bronze);
        //设置背景
        palette.setBrush(QPalette::Window, backgroundImage);
        //设置背景框颜色
        palette.setBrush(QPalette::Base, veryLightBlue);
        //设置加深的颜色
        palette.setBrush(QPalette::AlternateBase, lightBlue);
        //设置选中的颜色
        palette.setBrush(QPalette::Highlight, darkBlue);
        //设置样式
        palette.setBrush(QPalette::Disabled, QPalette::Highlight,
                         Qt::darkGray);
    }
    
    //当样式应用到窗口部件时
    void BronzeStyle::polish(QWidget *widget)
    {
        //设置Qt::WA-Hover属性,鼠标进入或者离开窗口部件所在区域
        //会产生一个绘制事件
        if (qobject_cast<QAbstractButton *>(widget)
                || qobject_cast<QAbstractSpinBox *>(widget))
            widget->setAttribute(Qt::WA_Hover, true);
    }
    
    //取消polish的作用
    void BronzeStyle::unpolish(QWidget *widget)
    {
        if (qobject_cast<QAbstractButton *>(widget)
                || qobject_cast<QAbstractSpinBox *>(widget))
            widget->setAttribute(Qt::WA_Hover, false);
    }
    
    //函数返回一些关于样式外观的提示
    int BronzeStyle::styleHint(StyleHint which, const QStyleOption *option,
                               const QWidget *widget,
                               QStyleHintReturn *returnData) const
    {
        switch (which) {
        case SH_DialogButtonLayout:
            return int(QDialogButtonBox::MacLayout);
        case SH_EtchDisabledText:
            return int(true);
        case SH_DialogButtonBox_ButtonsHaveIcons:
            return int(true);
        case SH_UnderlineShortcut:
            return int(false);
        default:
            return QWindowsStyle::styleHint(which, option, widget,
                                            returnData);
        }
    }
    
    //返回一个像素值,用于用户界面元素中
    int BronzeStyle::pixelMetric(PixelMetric which,
                                 const QStyleOption *option,
                                 const QWidget *widget) const
    {
        switch (which) {
        //返回0是因为不希望在默认的按钮旁边保留额外的空间
        case PM_ButtonDefaultIndicator:
            return 0;
        //指示器大小是一个正方形
        case PM_IndicatorWidth:
        case PM_IndicatorHeight:
            return 16;
        //控制指示器和其右边的文字之间的距离
        case PM_CheckBoxLabelSpacing:
            return 8;
        //定义QFrame,QPushButton,QSpinBox以及其他的一些窗口部件的
        //线宽.
        case PM_DefaultFrameWidth:
            return 2;
        //对于其他的PM_xxx值,从基类中继承像素规格的值
        default:
            return QWindowsStyle::pixelMetric(which, option, widget);
        }
    }
    
    //绘制基本的用户界面元素
    void BronzeStyle::drawPrimitive(PrimitiveElement which,
                                    const QStyleOption *option,
                                    QPainter *painter,
                                    const QWidget *widget) const
    {
        switch (which) {
        //会被QCheckBox,QGroupBox和QItemDelegate用来绘制选择指示器
        case PE_IndicatorCheckBox:
            drawBronzeCheckBoxIndicator(option, painter);
            break;
        case PE_PanelButtonCommand:
            drawBronzeBevel(option, painter);
            break;
        case PE_Frame:
            drawBronzeFrame(option, painter);
            break;
            //对与PE_FrameDefaultButton什么都不做
            //避免在默认的按钮旁边另外再绘制一个多余的边框
        case PE_FrameDefaultButton:
            break;
        default:
            QWindowsStyle::drawPrimitive(which, option, painter, widget);
        }
    }
    
    //绘制多重辅助控制器窗口部件
    void BronzeStyle::drawComplexControl(ComplexControl which,
                                         const QStyleOptionComplex *option,
                                         QPainter *painter,
                                         const QWidget *widget) const
    {
        //重新实现了drawComplexControl
        if (which == CC_SpinBox) {
            drawBronzeSpinBoxButton(SC_SpinBoxDown, option, painter);
            drawBronzeSpinBoxButton(SC_SpinBoxUp, option, painter);
    
            QRect rect = subControlRect(CC_SpinBox, option,
                                        SC_SpinBoxEditField)
                         .adjusted(-1, 0, +1, 0);
            painter->setPen(QPen(option->palette.mid(), 1.0));
            painter->drawLine(rect.topLeft(), rect.bottomLeft());
            painter->drawLine(rect.topRight(), rect.bottomRight());
        } else {
            return QWindowsStyle::drawComplexControl(which, option, painter,
                                                     widget);
        }
    }
    
    //确认辅助控制器窗口部件的位置
    QRect BronzeStyle::subControlRect(ComplexControl whichControl,
                                      const QStyleOptionComplex *option,
                                      SubControl whichSubControl,
                                      const QWidget *widget) const
    {
        if (whichControl == CC_SpinBox) {
            int frameWidth = pixelMetric(PM_DefaultFrameWidth, option,
                                         widget);
            int buttonWidth = 16;
    
            switch (whichSubControl) {
            case SC_SpinBoxFrame:
                return option->rect;
            case SC_SpinBoxEditField:
                return option->rect.adjusted(+buttonWidth, +frameWidth,
                                             -buttonWidth, -frameWidth);
            //返回矩形区域
            case SC_SpinBoxDown:
                return visualRect(option->direction, option->rect,
                                  QRect(option->rect.x(), option->rect.y(),
                                        buttonWidth,
                                        option->rect.height()));
            case SC_SpinBoxUp:
                return visualRect(option->direction, option->rect,
                                  QRect(option->rect.right() - buttonWidth,
                                        option->rect.y(),
                                        buttonWidth,
                                        option->rect.height()));
            default:
                return QRect();
            }
        } else {
            return QWindowsStyle::subControlRect(whichControl, option,
                                                 whichSubControl, widget);
        }
    }
    
    //调用standardIconImplementation()槽获取用在用户界面上的标准图标.
    QIcon BronzeStyle::standardIconImplementation(StandardPixmap which,
            const QStyleOption *option, const QWidget *widget) const
    {
        //调用基类的standardPixmap()获取图标,并绘制浅蓝色
        QImage image = QWindowsStyle::standardPixmap(which, option, widget)
                       .toImage();
        if (image.isNull())
            return QIcon();
    
        QPalette palette;
        if (option) {
            palette = option->palette;
        } else if (widget) {
            palette = widget->palette();
        }
    
        QPainter painter(&image);
        //着色可以通过在图标上绘制25%不透明的蓝色实现
        painter.setOpacity(0.25);
        //确保原来透明的部分依然透明
        painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
        painter.fillRect(image.rect(), palette.highlight());
        painter.end();
    
        return QIcon(QPixmap::fromImage(image));
    }
    
    //会被drawPrimitive调用,用来绘制一个PE_Frame私有元素
    void BronzeStyle::drawBronzeFrame(const QStyleOption *option,
                                      QPainter *painter) const
    {
        //为了保证QPainter保存原来的状态
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing, true);
        painter->setPen(QPen(option->palette.foreground(), 1.0));
        painter->drawRect(option->rect.adjusted(+1, +1, -1, -1));
        //最后恢复
        painter->restore();
    }
    
    //用来绘制QPushButton背景
    void BronzeStyle::drawBronzeBevel(const QStyleOption *option,
                                      QPainter *painter) const
    {
        QColor buttonColor = option->palette.button().color();
        //coeff使按钮有弹起效果
        int coeff = (option->state & State_MouseOver) ? 115 : 105;
    
        //上方是亮色,下方是暗色,其间是渐变的棕色
        QLinearGradient gradient(0, 0, 0, option->rect.height());
        gradient.setColorAt(0.0, option->palette.light().color());
        gradient.setColorAt(0.2, buttonColor.lighter(coeff));
        gradient.setColorAt(0.8, buttonColor.darker(coeff));
        gradient.setColorAt(1.0, option->palette.dark().color());
    
        //Bronze样式默认按钮使用2像素宽的边框,否则使用1像素宽的边框
        double penWidth = 1.0;
        //把option强转为const   QStyleOptionButton*类型,检测其features成员变量
        if (const QStyleOptionButton *buttonOpt =
                qstyleoption_cast<const QStyleOptionButton *>(option)) {
            if (buttonOpt->features & QStyleOptionButton::DefaultButton)
                penWidth = 2.0;
        }
    
    
        QRect roundRect = option->rect.adjusted(+1, +1, -1, -1);
        if (!roundRect.isValid())
            return;
    
        int diameter = 12;
        //指定按钮的圆角程度,根据diameter计算
        int cx = 100 * diameter / roundRect.width();
        int cy = 100 * diameter / roundRect.height();
    
        //执行绘图
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(gradient);
        painter->drawRoundRect(roundRect, cx, cy);
    
        if (option->state & (State_On | State_Sunken)) {
            QColor slightlyOpaqueBlack(0, 0, 0, 63);
            painter->setBrush(slightlyOpaqueBlack);
            painter->drawRoundRect(roundRect, cx, cy);
        }
    
        painter->setRenderHint(QPainter::Antialiasing, true);
        painter->setPen(QPen(option->palette.foreground(), penWidth));
        painter->setBrush(Qt::NoBrush);
        painter->drawRoundRect(roundRect, cx, cy);
        painter->restore();
    }
    
    //绘制复选框
    void BronzeStyle::drawBronzeCheckBoxIndicator(
            const QStyleOption *option, QPainter *painter) const
    {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing, true);
    
        if (option->state & State_MouseOver) {
            painter->setBrush(option->palette.alternateBase());
        } else {
            painter->setBrush(option->palette.base());
        }
        painter->drawRoundRect(option->rect.adjusted(+1, +1, -1, -1));
    
        if (option->state & (State_On | State_NoChange)) {
            QPixmap pixmap;
            if (!(option->state & State_Enabled)) {
                pixmap.load(":/images/checkmark-disabled.png");
            } else if (option->state & State_NoChange) {
                pixmap.load(":/images/checkmark-partial.png");
            } else {
                pixmap.load(":/images/checkmark.png");
            }
    
            QRect pixmapRect = pixmap.rect()
                                     .translated(option->rect.topLeft())
                                     .translated(+2, -6);
            QRect painterRect = visualRect(option->direction, option->rect,
                                           pixmapRect);
            if (option->direction == Qt::RightToLeft) {
                painter->scale(-1.0, +1.0);
                painterRect.moveLeft(-painterRect.right() - 1);
            }
            painter->drawPixmap(painterRect, pixmap);
        }
        painter->restore();
    }
    
    //绘制微调框向上向下按钮
    void BronzeStyle::drawBronzeSpinBoxButton(SubControl which,
            const QStyleOptionComplex *option, QPainter *painter) const
    {
        PrimitiveElement arrow = PE_IndicatorArrowLeft;
        QRect buttonRect = option->rect;
        if ((which == SC_SpinBoxUp)
                != (option->direction == Qt::RightToLeft)) {
            arrow = PE_IndicatorArrowRight;
            buttonRect.translate(buttonRect.width() / 2, 0);
        }
        buttonRect.setWidth((buttonRect.width() + 1) / 2);
    
        QStyleOption buttonOpt(*option);
    
        painter->save();
        painter->setClipRect(buttonRect, Qt::IntersectClip);
        if (!(option->activeSubControls & which))
            buttonOpt.state &= ~(State_MouseOver | State_On | State_Sunken);
        drawBronzeBevel(&buttonOpt, painter);
    
        QStyleOption arrowOpt(buttonOpt);
        arrowOpt.rect = subControlRect(CC_SpinBox, option, which)
                        .adjusted(+3, +3, -3, -3);
        if (arrowOpt.rect.isValid())
            drawPrimitive(arrow, &arrowOpt, painter);
        painter->restore();
    }

    brozedialog.h

    #ifndef BRONZEDIALOG_H
    #define BRONZEDIALOG_H
    
    #include <QDialog>
    
    class QCheckBox;
    class QDateEdit;
    class QDialogButtonBox;
    class QDoubleSpinBox;
    class QLabel;
    class QSpinBox;
    class QTimeEdit;
    class QTreeWidget;
    
    class BronzeDialog : public QDialog
    {
        Q_OBJECT
    
    public:
        BronzeDialog(QWidget *parent = 0);
    
    private slots:
        void editableStateChanged(bool editable);
    
    private:
        void populateAgendaTreeWidget();
    
        //日期标签
        QLabel *dateLabel;
        //时间标签
        QLabel *timeLabel;
        //duration标签
        QLabel *durationLabel;
        //价格标签
        QLabel *priceLabel;
        //议程标签
        QLabel *agendaLabel;
        //日期编辑框
        QDateEdit *dateEdit;
        //时间编辑框
        QTimeEdit *timeEdit;
        //持续时间编辑框
        QSpinBox *durationSpinBox;
        //价格编辑框
        QDoubleSpinBox *priceSpinBox;
        //reminder选择框
        QCheckBox *reminderCheckBox;
        //可编辑选择框
        QCheckBox *editableCheckBox;
        //树形控件框
        QTreeWidget *agendaTreeWidget;
        //按钮框
        QDialogButtonBox *buttonBox;
    };
    
    #endif

    brozedialog.cpp

      1 #include <QtGui>
      2 
      3 #include "brozedialog.h"
      4 
      5 BronzeDialog::BronzeDialog(QWidget *parent)
      6     : QDialog(parent)
      7 {
      8     //日期编辑框
      9     dateEdit = new QDateEdit(QDate::currentDate());
     10     //设置居中
     11     dateEdit->setAlignment(Qt::AlignCenter);
     12 
     13     //标签
     14     dateLabel = new QLabel(tr("&Date:"));
     15     //设置为一类
     16     dateLabel->setBuddy(dateEdit);
     17 
     18     //时间编辑框
     19     timeEdit = new QTimeEdit(QTime(9, 15, 0));
     20     //设置居中
     21     timeEdit->setAlignment(Qt::AlignCenter);
     22 
     23     //时间标签
     24     timeLabel = new QLabel(tr("&Time:"));
     25     //设置为一类
     26     timeLabel->setBuddy(timeEdit);
     27 
     28     //持续时间编辑框
     29     durationSpinBox = new QSpinBox;
     30     //设置居中
     31     durationSpinBox->setAlignment(Qt::AlignCenter);
     32     //设置后面显示的值
     33     durationSpinBox->setSuffix(tr(" hour"));
     34     //设置默认的值
     35     durationSpinBox->setValue(3);
     36 
     37     //设置标签
     38     durationLabel = new QLabel(tr("D&uration:"));
     39     //设置为一类
     40     durationLabel->setBuddy(durationSpinBox);
     41 
     42     //设置价格框
     43     priceSpinBox = new QDoubleSpinBox;
     44     //设置居中显示
     45     priceSpinBox->setAlignment(Qt::AlignCenter);
     46     //设置范围
     47     priceSpinBox->setMaximum(10000.00);
     48     priceSpinBox->setValue(500.00);
     49 
     50     //设置标签
     51     priceLabel = new QLabel(tr("&Price:"));
     52     //设置为一类
     53     priceLabel->setBuddy(priceSpinBox);
     54 
     55     //创建树形控件
     56     agendaTreeWidget = new QTreeWidget;
     57     //基本属性设置
     58     agendaTreeWidget->setAlternatingRowColors(true);
     59     agendaTreeWidget->setHorizontalScrollBarPolicy(
     60             Qt::ScrollBarAlwaysOff);
     61     agendaTreeWidget->setVerticalScrollBarPolicy(
     62             Qt::ScrollBarAlwaysOff);
     63     //设置一列
     64     agendaTreeWidget->setColumnCount(1);
     65     //设置头部隐藏
     66     agendaTreeWidget->header()->hide();
     67     //设置tree控件
     68     populateAgendaTreeWidget();
     69 
     70     //设置标签
     71     agendaLabel = new QLabel(tr("&Agenda:"));
     72     //绑定
     73     agendaLabel->setBuddy(agendaTreeWidget);
     74     //设置位置
     75     agendaLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
     76 
     77     //设置复选框
     78     reminderCheckBox = new QCheckBox(tr("&Send me a reminder"));
     79     reminderCheckBox->setCheckState(Qt::PartiallyChecked);
     80 
     81     //设置复选框
     82     editableCheckBox = new QCheckBox(tr("&Item is editable"));
     83     editableCheckBox->setChecked(true);
     84 
     85     //创建按钮
     86     buttonBox = new QDialogButtonBox(QDialogButtonBox::Save
     87                                      | QDialogButtonBox::Cancel);
     88 
     89     //editable槽函数
     90     connect(editableCheckBox, SIGNAL(toggled(bool)),
     91             this, SLOT(editableStateChanged(bool)));
     92     //按钮槽函数
     93     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
     94     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
     95 
     96     //创建布局
     97     QGridLayout *mainLayout = new QGridLayout;
     98     mainLayout->addWidget(dateLabel, 0, 0);
     99     mainLayout->addWidget(dateEdit, 0, 1);
    100     mainLayout->addWidget(timeLabel, 0, 3);
    101     mainLayout->addWidget(timeEdit, 0, 4);
    102     mainLayout->addWidget(durationLabel, 1, 0);
    103     mainLayout->addWidget(durationSpinBox, 1, 1);
    104     mainLayout->addWidget(priceLabel, 1, 3);
    105     mainLayout->addWidget(priceSpinBox, 1, 4);
    106     mainLayout->addWidget(agendaTreeWidget, 2, 1, 2, 4);
    107     mainLayout->addWidget(agendaLabel, 2, 0);
    108     mainLayout->addWidget(reminderCheckBox, 4, 0, 1, 2);
    109     mainLayout->addWidget(editableCheckBox, 4, 3, 1, 2, Qt::AlignRight);
    110     mainLayout->addWidget(buttonBox, 5, 0, 1, 5);
    111 
    112     setLayout(mainLayout);
    113 
    114     setWindowTitle(tr("Bronze"));
    115 }
    116 
    117 //edit被选中
    118 void BronzeDialog::editableStateChanged(bool editable)
    119 {
    120     dateLabel->setEnabled(editable);
    121     timeLabel->setEnabled(editable);
    122     durationLabel->setEnabled(editable);
    123     priceLabel->setEnabled(editable);
    124     agendaLabel->setEnabled(editable);
    125     dateEdit->setEnabled(editable);
    126     timeEdit->setEnabled(editable);
    127     durationSpinBox->setEnabled(editable);
    128     priceSpinBox->setEnabled(editable);
    129     reminderCheckBox->setEnabled(editable);
    130     agendaTreeWidget->setEnabled(editable);
    131     buttonBox->button(QDialogButtonBox::Save)->setEnabled(editable);
    132 }
    133 
    134 void BronzeDialog::populateAgendaTreeWidget()
    135 {
    136     QTreeWidgetItem *item1 = new QTreeWidgetItem(agendaTreeWidget);
    137     item1->setText(0, tr("1. Call to order"));
    138 
    139     QTreeWidgetItem *item2 = new QTreeWidgetItem(agendaTreeWidget);
    140     item2->setText(0, tr("2. Approval of Minutes"));
    141 
    142     QTreeWidgetItem *item3 = new QTreeWidgetItem(agendaTreeWidget);
    143     item3->setText(0, tr("3. New Business"));
    144     item3->setExpanded(true);
    145 
    146     QTreeWidgetItem *item31 = new QTreeWidgetItem(item3);
    147     item31->setText(0, tr("3.1. Introduction of task force members"));
    148 
    149     QTreeWidgetItem *item32 = new QTreeWidgetItem(item3);
    150     item32->setText(0, tr("3.2. Welcome address"));
    151 
    152     QTreeWidgetItem *item33 = new QTreeWidgetItem(item3);
    153     item33->setText(0, tr("3.3. Review timeline for task force work"));
    154 
    155     QTreeWidgetItem *item4 = new QTreeWidgetItem(agendaTreeWidget);
    156     item4->setText(0, tr("4. Arrangements for future meetings"));
    157 
    158     QTreeWidgetItem *item41 = new QTreeWidgetItem(item4);
    159     item41->setText(0, tr("4.1. Dates"));
    160 
    161     QTreeWidgetItem *item42 = new QTreeWidgetItem(item4);
    162     item42->setText(0, tr("4.2. Agenda items for next meeting"));
    163 
    164     QTreeWidgetItem *item5 = new QTreeWidgetItem(agendaTreeWidget);
    165     item5->setText(0, tr("5. Ajournment"));
    166 }
  • 相关阅读:
    python模块
    Django基础
    Python __str__(self)和__unicode__(self)
    Redis基本操作
    测试面试宝典
    h5页面的测试方式
    selenium IDE的使用流程
    如何安装chrome扩展程序--selenium IDE
    Selenium 中 强制等待、显示等待、隐式等待的区别
    Selenium+Python 自动化 之八种元素定位方法
  • 原文地址:https://www.cnblogs.com/xiaochi/p/9032747.html
Copyright © 2020-2023  润新知