44.Qt通过子类化qstyle实现自定义外观
main.cpp
#include <QtGui> #include "brozedialog.h"
#include "bronzestyle.h" int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QApplication::setStyle(new BronzeStyle);
BronzeDialog dialog;
dialog.layout()->setSpacing();
dialog.layout()->setMargin();
dialog.show();
return app.exec();
}
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 = ,
QStyleHintReturn *returnData = ) const;
int pixelMetric(PixelMetric which, const QStyleOption *option,
const QWidget *widget = ) const;
void drawPrimitive(PrimitiveElement which,
const QStyleOption *option, QPainter *painter,
const QWidget *widget = ) const;
void drawComplexControl(ComplexControl which,
const QStyleOptionComplex *option,
QPainter *painter,
const QWidget *widget = ) const;
QRect subControlRect(ComplexControl whichControl,
const QStyleOptionComplex *option,
SubControl whichSubControl,
const QWidget *widget = ) const; public slots:
QIcon standardIconImplementation(StandardPixmap which,
const QStyleOption *option,
const QWidget *widget = ) 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(, , );
//设置背景框颜色
QColor veryLightBlue(, , );
//要加深的颜色
QColor lightBlue(, , );
//选中后的颜色
QColor darkBlue(, , ); //创建一个新的面板
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 ;
//指示器大小是一个正方形
case PM_IndicatorWidth:
case PM_IndicatorHeight:
return ;
//控制指示器和其右边的文字之间的距离
case PM_CheckBoxLabelSpacing:
return ;
//定义QFrame,QPushButton,QSpinBox以及其他的一些窗口部件的
//线宽.
case PM_DefaultFrameWidth:
return ;
//对于其他的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(-, , +, );
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 = ; 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(+, +, -, -));
//最后恢复
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) ? : ; //上方是亮色,下方是暗色,其间是渐变的棕色
QLinearGradient gradient(, , , 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(+, +, -, -);
if (!roundRect.isValid())
return; int diameter = ;
//指定按钮的圆角程度,根据diameter计算
int cx = * diameter / roundRect.width();
int cy = * 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(, , , );
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(+, +, -, -)); 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(+, -);
QRect painterRect = visualRect(option->direction, option->rect,
pixmapRect);
if (option->direction == Qt::RightToLeft) {
painter->scale(-1.0, +1.0);
painterRect.moveLeft(-painterRect.right() - );
}
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() / , );
}
buttonRect.setWidth((buttonRect.width() + ) / ); 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(+, +, -, -);
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 = ); 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
#include <QtGui> #include "brozedialog.h" BronzeDialog::BronzeDialog(QWidget *parent)
: QDialog(parent)
{
//日期编辑框
dateEdit = new QDateEdit(QDate::currentDate());
//设置居中
dateEdit->setAlignment(Qt::AlignCenter); //标签
dateLabel = new QLabel(tr("&Date:"));
//设置为一类
dateLabel->setBuddy(dateEdit); //时间编辑框
timeEdit = new QTimeEdit(QTime(, , ));
//设置居中
timeEdit->setAlignment(Qt::AlignCenter); //时间标签
timeLabel = new QLabel(tr("&Time:"));
//设置为一类
timeLabel->setBuddy(timeEdit); //持续时间编辑框
durationSpinBox = new QSpinBox;
//设置居中
durationSpinBox->setAlignment(Qt::AlignCenter);
//设置后面显示的值
durationSpinBox->setSuffix(tr(" hour"));
//设置默认的值
durationSpinBox->setValue(); //设置标签
durationLabel = new QLabel(tr("D&uration:"));
//设置为一类
durationLabel->setBuddy(durationSpinBox); //设置价格框
priceSpinBox = new QDoubleSpinBox;
//设置居中显示
priceSpinBox->setAlignment(Qt::AlignCenter);
//设置范围
priceSpinBox->setMaximum(10000.00);
priceSpinBox->setValue(500.00); //设置标签
priceLabel = new QLabel(tr("&Price:"));
//设置为一类
priceLabel->setBuddy(priceSpinBox); //创建树形控件
agendaTreeWidget = new QTreeWidget;
//基本属性设置
agendaTreeWidget->setAlternatingRowColors(true);
agendaTreeWidget->setHorizontalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
agendaTreeWidget->setVerticalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
//设置一列
agendaTreeWidget->setColumnCount();
//设置头部隐藏
agendaTreeWidget->header()->hide();
//设置tree控件
populateAgendaTreeWidget(); //设置标签
agendaLabel = new QLabel(tr("&Agenda:"));
//绑定
agendaLabel->setBuddy(agendaTreeWidget);
//设置位置
agendaLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); //设置复选框
reminderCheckBox = new QCheckBox(tr("&Send me a reminder"));
reminderCheckBox->setCheckState(Qt::PartiallyChecked); //设置复选框
editableCheckBox = new QCheckBox(tr("&Item is editable"));
editableCheckBox->setChecked(true); //创建按钮
buttonBox = new QDialogButtonBox(QDialogButtonBox::Save
| QDialogButtonBox::Cancel); //editable槽函数
connect(editableCheckBox, SIGNAL(toggled(bool)),
this, SLOT(editableStateChanged(bool)));
//按钮槽函数
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); //创建布局
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(dateLabel, , );
mainLayout->addWidget(dateEdit, , );
mainLayout->addWidget(timeLabel, , );
mainLayout->addWidget(timeEdit, , );
mainLayout->addWidget(durationLabel, , );
mainLayout->addWidget(durationSpinBox, , );
mainLayout->addWidget(priceLabel, , );
mainLayout->addWidget(priceSpinBox, , );
mainLayout->addWidget(agendaTreeWidget, , , , );
mainLayout->addWidget(agendaLabel, , );
mainLayout->addWidget(reminderCheckBox, , , , );
mainLayout->addWidget(editableCheckBox, , , , , Qt::AlignRight);
mainLayout->addWidget(buttonBox, , , , ); setLayout(mainLayout); setWindowTitle(tr("Bronze"));
} //edit被选中
void BronzeDialog::editableStateChanged(bool editable)
{
dateLabel->setEnabled(editable);
timeLabel->setEnabled(editable);
durationLabel->setEnabled(editable);
priceLabel->setEnabled(editable);
agendaLabel->setEnabled(editable);
dateEdit->setEnabled(editable);
timeEdit->setEnabled(editable);
durationSpinBox->setEnabled(editable);
priceSpinBox->setEnabled(editable);
reminderCheckBox->setEnabled(editable);
agendaTreeWidget->setEnabled(editable);
buttonBox->button(QDialogButtonBox::Save)->setEnabled(editable);
} void BronzeDialog::populateAgendaTreeWidget()
{
QTreeWidgetItem *item1 = new QTreeWidgetItem(agendaTreeWidget);
item1->setText(, tr("1. Call to order")); QTreeWidgetItem *item2 = new QTreeWidgetItem(agendaTreeWidget);
item2->setText(, tr("2. Approval of Minutes")); QTreeWidgetItem *item3 = new QTreeWidgetItem(agendaTreeWidget);
item3->setText(, tr("3. New Business"));
item3->setExpanded(true); QTreeWidgetItem *item31 = new QTreeWidgetItem(item3);
item31->setText(, tr("3.1. Introduction of task force members")); QTreeWidgetItem *item32 = new QTreeWidgetItem(item3);
item32->setText(, tr("3.2. Welcome address")); QTreeWidgetItem *item33 = new QTreeWidgetItem(item3);
item33->setText(, tr("3.3. Review timeline for task force work")); QTreeWidgetItem *item4 = new QTreeWidgetItem(agendaTreeWidget);
item4->setText(, tr("4. Arrangements for future meetings")); QTreeWidgetItem *item41 = new QTreeWidgetItem(item4);
item41->setText(, tr("4.1. Dates")); QTreeWidgetItem *item42 = new QTreeWidgetItem(item4);
item42->setText(, tr("4.2. Agenda items for next meeting")); QTreeWidgetItem *item5 = new QTreeWidgetItem(agendaTreeWidget);
item5->setText(, tr("5. Ajournment"));
}
44.Qt通过子类化qstyle实现自定义外观的更多相关文章
- 【QT】子类化QThread实现多线程
<QThread源码浅析> 子类化QThread来实现多线程, QThread只有run函数是在新线程里的,其他所有函数都在QThread生成的线程里.正确启动线程的方法是调用QThrea ...
- 【QT】子类化QObject+moveToThread实现多线程
往期链接: <QThread源码浅析> <子类化QThread实现多线程> 从往期<QThread源码浅析>可知,在Qt4.4之前,run 是纯虚函数,必须子类化Q ...
- Qt子类化后qss设置背景色无效的问题
1.问题背景 在某个类中,用到了一个组合的widget,有按钮进度条等,类似于视频播放器按钮控制区和精度条(参考了很多feiyangqingyun的文章,感谢),调试正常后整理代码,为了提高代码可读性 ...
- 从以往子类化跟踪MouseLeave深入讨论VB6的自定义Hook类
一.关于起因 之前发过一篇博文,是关于VB6中跟踪鼠标移出事件的示例(http://www.cnblogs.com/alexywt/p/5891827.html) 随着业务状况的不断发展,提出了更多的 ...
- 深入理解MFC子类化
子类化,通俗来讲就是用自己的窗口处理函数来处理特定消息,并将自己其他消息还给标准(默认)窗口处理函数.在SDK中,通过SetWindowLong来指定一个自定义窗口处理函数:SetWindowLong ...
- 子类化GetOpenFileName/GetSaveFileName, 以及钩子函数OFNHookProc的使用的简要说明
昨天, 群里面有一个人问起: 要怎么让"文件打开对话框"居中显示, 有人说子类. 而我告诉他的方法是用钩子函数OFNHookProc, 不知道这是不是所谓的子类?相信看了我今天这篇 ...
- python 继承机制(子类化内置类型)
1. 如果想实现与某个内置类型具有类似行为的类时,最好的方法就是将这个内置类型子类化. 2. 内置类型子类化,其实就是自定义一个新类,使其继承有类似行为的内置类,通过重定义这个新类实现指定的功能. c ...
- VB6史无前例的子类化之透明按钮
[原创文章,转发请保留版权信息] 作者:mezstd 文章地址:http://www.cnblogs.com/imez/p/3299728.html 效果图: 请原谅笔者无耻地称之为史无前例,至少在笔 ...
- C++ 中超类化和子类化常用API
在windows平台上,使用C++实现子类化和超类化常用的API并不多,由于这些API函数的详解和使用方法,网上一大把.本文仅作为笔记,简单的记录一下. 子类化:SetWindowLong,GetWi ...
随机推荐
- Ad hoc polymorphism
与面向对象中的接口类或抽象类中定义的函数组类似: 函数的具体执行依赖与函数医用的类型. In programming languages, ad-hoc polymorphism[1] is a ki ...
- node jsonwebtoken
jsonwebtoken是node版本的JWT(JSON Web Tokens)的实现.1.什么是JWT?Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于J ...
- 用Python来实现斐波那契数列.
1).递归 def fib_recur(n): assert n >= 0, "n > 0" if n <= 1: return n return fib_rec ...
- PHP stream_socket_server
stream_socket_server - 创建一个Internet或Unix域服务器套接字 描述 资源stream_socket_server(字符串local_socket [摘要和错误号[,串 ...
- BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...
- Windows数字代码签名的作用和流程
什么是数字代码签名?数字签名代码是一种技术,它使用数字证书来识别软件的发布商和使用hash算法来确保软件的完整性.数字签名使用公共密匙签名书法被创建,它使用两种不同的密匙:公共密匙和私有密匙,我们称其 ...
- 在vue中写一个跟着鼠标跑的div,div里面动态显示数据
1.div应该放在body里面,这是我放在body中的一个div里面的div <!-- 信息查看层 --> <div class="floatDiv" :styl ...
- vue 路由跳转传参
<li v-for="article in articles" @click="getDescribe(article.id)"> getDescr ...
- Appium的ios配置
automationName text XCUITest platformName text iOS platformVersion ...
- [kernel学习]----好文章梳理
内存相关 Linux的内存回收和交换 Linux内核分析:页回收导致的cpu load瞬间飙高的问题分析与思考 认识Linux物理内存回收机制 认真分析mmap:是什么 为什么 怎么用 kernel排 ...