太原建站培训,莱州建设局网站,办公室装饰设计,想美团这样的网站怎么做0 环境
Windows 11Qt 5.15.2 MinGW x64
1 系列文章
简介#xff1a;本系列文章#xff0c;是以纯代码方式实现 Qt 控件的重构#xff0c;尽量不使用 Qss 方式。
《[Qt]QListView 重绘实例之一#xff1a;背景重绘》
《[Qt]QListView 重绘实例之二#xff1a;列表项覆…0 环境
Windows 11Qt 5.15.2 MinGW x64
1 系列文章
简介本系列文章是以纯代码方式实现 Qt 控件的重构尽量不使用 Qss 方式。
《[Qt]QListView 重绘实例之一背景重绘》
《[Qt]QListView 重绘实例之二列表项覆盖的问题处理》
《[Qt]QListView 重绘实例之三滚动条覆盖的问题处理》
《[Qt]QListView 重绘实例之四效果一讲解》
《[Qt]QListView 重绘实例之四效果二讲解》
2 问题开始
继上文《之一》绘制圆角矩形背景时遗留了两个主要问题
列表项覆盖破坏背景效果滚动条覆盖破坏背景效果
其中对于滚动条的问题留作下一文《之三》讲解。参考《[Qt]QListView 重绘实例之三滚动条的处理》。
本文先解决列表项覆盖的问题。 至少有两个思路解决列表项的覆盖问题
使用委托。如子类化 QItemDelegate然后进行列表项的重绘使用代理样式。如子类化 QProxyStyle然后进行列表项的重绘
本文选择第二种思路原因有二
其一承接上文《之一》已经使用了子类化 QProxyStyle 的方法继续实现对列表项的重绘功能即可没有必要再另外添加一个新委托子类实现其二样式 QStyle /代理样式 QProxyStyle本身即包含委托实现的功能。而且它们更多强大可以对某类或全局样式进行控件
具体的重绘过程分为两个部分
对于视口最上行/最下行需要处理上半部分/下半部分的圆角绘制对于视口的其它中间行则进行默认绘制或按期望样式绘制
→→→ 解决方案直达 ←←←
3 重绘列表项背景
代理样式中与列表项相关的主要有一个样式类和两个元素类型
样式类QStyleOptionViewItem元素类型 QStyle::CE_ItemViewItem - void drawControl() constQStyle::PE_PanelItemViewItem - void drawPrimitive() const
Qt 文档关于 QStyle 类有如下说明 Styles in Item Views … The primitive element PE_PanelItemViewItem is responsible for painting the background of items, and is called from QCommonStyle’s implementation of CE_ItemViewItem. 译QCommonStyle 子类实现中的控制类型 CE_ItemViewItem 会调用原始类型 PE_PanelItemViewItem其中原始类型 PE_PanelItemViewItem 负责绘制列表项的背景。 … 即在 QStyle::PE_PanelItemViewItem 中绘制列表项的背景在 QStyle::CE_ItemViewItem 中绘制列表项的内容。
3.1 保存视口大小信息 Qt 明确说明 QListView 是垂直型的列表。 首先需要判断视口中的最上/最下行位置。而判断位置则需要知道整个列表的高度。具体实现是在绘制 QFrame 时保存数据。
/* .h */
class PListViewStyle : public QListView
{
public:// ...
private:mutable QRect mRect; // Need mutable
}/* .cpp */
void PListViewStyle::drawControl(QStyle::ControlElement element,const QStyleOption *option,QPainter *painter,const QWidget *widget) const
{switch(element){case QStyle::CE_ShapedFrame:{const QStyleOptionFrame *opt qstyleoption_castconst QStyleOptionFrame *(option);if(nullptr opt) { return; }mRect opt-rect;//...return;}default:break;}QProxyStyle::drawControl(element, option, painter, widget);
}注意变量 mRect 必须使用 mutable 修饰。
3.2 判断视口中的最上/最下行位置
判断视口中的最上行位置
if(0 opt-rect.y())如果没有设置内填充最上行位置的 y 坐标应该等于 0因此使用此条件进行判断。
判断视口中的最下行位置
bool PListViewStyle::isLastRow(const QRect rect, int rowHeight) const
{/* 列表可显示行数 */int rowCount mRect.height() / rect.height();/* 由 y 坐标与行高计算行索引 */int index rect.y() / rect.height();if(rowCount index){rowHeight mRect.height() - index * rect.height();return true;}return false;
}3.3 绘制列表项背景
/* 添加常量定义需要添加到 cpp 文件开头位置 */
const int Radius 15;void PListViewStyle::drawPrimitive(QStyle::PrimitiveElement element,const QStyleOption *option,QPainter *painter,const QWidget *widget) const
{switch(element){/* PE_PanelItemViewItem 主要负责绘制列表项的背景选中背景/高亮背景*/case QStyle::PE_PanelItemViewItem:{const QStyleOptionViewItem *opt qstyleoption_castconst QStyleOptionViewItem *(option);if(nullptr opt) { break; }QColor c(Qt::lightGray);if(QStyle::State_MouseOver opt-state){c QColor(0, 0, 255, 255 * 0.2);}else if(QStyle::State_Selected opt-state){c QColor(0, 0, 255, 255 * 0.5);}int x, y, w, h;opt-rect.getRect(x, y, w, h);QPainterPath path;int rowHeight 0;/* 最上一行 */if(0 y){/* 创建最上一行带圆的角矩形路径 */path.moveTo(x, y h);path.arcTo(QRect(x, y, 2 * Radius, 2 * Radius), 180, -90);path.lineTo(x w, y);path.lineTo(x w, y h);path.closeSubpath();}/* 最下一行 */else if(isLastRow(opt-rect, rowHeight)){/* 创建最下一行带圆角的矩形路径 */path.moveTo(x, y);path.lineTo(x w, y);path.lineTo(x w, y rowHeight);path.arcTo(QRect(x, y rowHeight - 2 * Radius, 2 * Radius, 2 * Radius), 270, -90);path.closeSubpath();}else{path.addRect(QRect(x, y, w, h));}painter-save();painter-setRenderHint(QPainter::Antialiasing);painter-setPen(Qt::NoPen);painter-setBrush(QBrush(c));painter-drawPath(path);painter-restore();return;}default:break;}QProxyStyle::drawPrimitive(element, option, painter, widget);
}为了显示绘图的效果这里特地将列表项的默认白色背景改成了浅灰色。
其中的重点是对视口最上行和最下行进行了圆角处理通过 QPainterPaht 实现。
效果图如下 从上图中可以看到绘制列表项的圆角效果确实出来了高亮效果也正确。说明至少这样的处理方案没有问题。
但是还是发现背景上有一个白色直角矩形仍然破坏了圆角矩形背景。
这也同样说明这个白色直角矩形并不是由于列表项产生的影响。
3.4 视口 viewport()
好了现在问题好像又回到 QListView 的里层了。
很明显列表项应该是表层的因为用户是可以直接看到的。
接下来结合上一文《之一》的内容来看一下以下这张图。 这里有一个层级关系
最底层QFrame。在《之一》中使用 paintEvent() 进行重绘时正是设置的这个直接设置成了 QFrame::NoFrame上一层viewpotr()。在《之一》中也验证过这点而且viewport() 区域是不包含滚动条的。如上图中列表项底下的白色矩形最上层列表项。上文已有说明。
现在基本上可以确定问题应该聚焦在 viewport() 上。
查看 Qt 帮助文档与视口相关的有两个接口
QWidget *QAbstractScrollArea::viewport() const;
void QAbstractScrollArea::setViewport(QWidget *widget);可知视口即是一个 QWidget 控件。
那么再来验证一下重新设置视口控件然后设置其背景色为蓝色
PListView::PListView(QWidget *parent) : QListView(parent)
{auto *widget new QWidget;widget-setStyleSheet(background: blue);setViewport(widget);
}效果图如下 由此可知确认了之前的推论。 补充内容 解决方法只需要一条语句setViewport(new QWidget)而且做过一些深入的尝试但没有理解具体的原因。 既然视口是一个 QWidget那么对 QWidget 进行绘制是不是应该也可以当作背景使用实际上的情况是子类化 QWidget 后重写 paintEvent() 方法再设置为新的视口控件重绘函数根本不会被调用。经实测可以改变这个视口控件的方式只有通过设置 Qss 才有效。也没明白是为什么。然后设置 QWidget 对象为新的视口控件该对象的调色板或者说对象样式是会影响列表项的默认样式的。例如 QWidget 通过 Qss 设置背景颜色为蓝色则列表项的默认背景色也会变为蓝色。当然这也可能是 Qss 设置影响了子对象。 此外之所以只要设置一个默认的 QWidget 对象作为新视口即可猜测原因是默认 QWidget 本身是一个透明的或者是统一风格背景色的控制在 QListView 中即表现为透明的一层所以不会影响圆角背景的效果。 虽然实际原因不知但能解决问题。 4 解决方案
添加新的视口控件
PListView::PListView(QWidget *parent) : QListView(parent)
{setViewport(new QWidget);setFrameStyle(QFrame::NoFrame); // Must//...
}绘制列表项背景
void PListViewStyle::drawPrimitive(QStyle::PrimitiveElement element,const QStyleOption *option,QPainter *painter,const QWidget *widget) const
{switch(element){/* PE_PanelItemViewItem 主要负责绘制列表项的背景以及选中背景/高亮背景 */case QStyle::PE_PanelItemViewItem:{const QStyleOptionViewItem *opt qstyleoption_castconst QStyleOptionViewItem *(option);if(nullptr opt) { break; }QColor c(Qt::white); /* 默认背景色 */if(QStyle::State_MouseOver opt-state){c QColor(0, 0, 255, 255 * 0.2);}else if(QStyle::State_Selected opt-state){c QColor(0, 0, 255, 255 * 0.5);}int x, y, w, h;opt-rect.getRect(x, y, w, h);QPainterPath path;int rowHeight 0;/* 最上一行 */if(0 y){/* 创建最上一行带圆角的矩形路径 */path.moveTo(x, y h);path.arcTo(QRect(x, y, 2 * Radius - 5, 2 * Radius - 5), 180, -90);path.lineTo(x w, y);path.lineTo(x w, y h);path.closeSubpath();}/* 最下一行 */else if(isLastRow(opt-rect, rowHeight)){/* 创建最下一行带圆角的矩形路径 */path.moveTo(x, y);path.lineTo(x w, y);path.lineTo(x w, y rowHeight);path.arcTo(QRect(x, y rowHeight - 2 * Radius, 2 * Radius, 2 * Radius), 270, -90);path.closeSubpath();}else{path.addRect(QRect(x, y, w, h));}painter-save();painter-setRenderHint(QPainter::Antialiasing);painter-setPen(Qt::NoPen);painter-setBrush(QBrush(c));painter-drawPath(path);painter-restore();return;}default:break;}QProxyStyle::drawPrimitive(element, option, painter, widget);
}最后来看一下效果图达到了预期的效果目标。
文章转载自: http://www.morning.dangaw.com.gov.cn.dangaw.com http://www.morning.yprjy.cn.gov.cn.yprjy.cn http://www.morning.sqqkr.cn.gov.cn.sqqkr.cn http://www.morning.lbgfz.cn.gov.cn.lbgfz.cn http://www.morning.qlsyf.cn.gov.cn.qlsyf.cn http://www.morning.rjcqb.cn.gov.cn.rjcqb.cn http://www.morning.qmwzz.cn.gov.cn.qmwzz.cn http://www.morning.xpqsk.cn.gov.cn.xpqsk.cn http://www.morning.cpfx.cn.gov.cn.cpfx.cn http://www.morning.jcfg.cn.gov.cn.jcfg.cn http://www.morning.rynq.cn.gov.cn.rynq.cn http://www.morning.pznnt.cn.gov.cn.pznnt.cn http://www.morning.ttcmdsg.cn.gov.cn.ttcmdsg.cn http://www.morning.qbfs.cn.gov.cn.qbfs.cn http://www.morning.msmtf.cn.gov.cn.msmtf.cn http://www.morning.dxpqd.cn.gov.cn.dxpqd.cn http://www.morning.cmqrg.cn.gov.cn.cmqrg.cn http://www.morning.dcmnl.cn.gov.cn.dcmnl.cn http://www.morning.wsxxq.cn.gov.cn.wsxxq.cn http://www.morning.drfcj.cn.gov.cn.drfcj.cn http://www.morning.zlnkq.cn.gov.cn.zlnkq.cn http://www.morning.c7497.cn.gov.cn.c7497.cn http://www.morning.kgslc.cn.gov.cn.kgslc.cn http://www.morning.qqzdr.cn.gov.cn.qqzdr.cn http://www.morning.hmpxn.cn.gov.cn.hmpxn.cn http://www.morning.rppf.cn.gov.cn.rppf.cn http://www.morning.sfdky.cn.gov.cn.sfdky.cn http://www.morning.rczrq.cn.gov.cn.rczrq.cn http://www.morning.plqhb.cn.gov.cn.plqhb.cn http://www.morning.nyqxy.cn.gov.cn.nyqxy.cn http://www.morning.fnxzk.cn.gov.cn.fnxzk.cn http://www.morning.sgcdr.com.gov.cn.sgcdr.com http://www.morning.plxhq.cn.gov.cn.plxhq.cn http://www.morning.xflwq.cn.gov.cn.xflwq.cn http://www.morning.mlycx.cn.gov.cn.mlycx.cn http://www.morning.bpwdc.cn.gov.cn.bpwdc.cn http://www.morning.dpdr.cn.gov.cn.dpdr.cn http://www.morning.ccyjt.cn.gov.cn.ccyjt.cn http://www.morning.mxhys.cn.gov.cn.mxhys.cn http://www.morning.brqjs.cn.gov.cn.brqjs.cn http://www.morning.jrlxz.cn.gov.cn.jrlxz.cn http://www.morning.ebpz.cn.gov.cn.ebpz.cn http://www.morning.jhqcr.cn.gov.cn.jhqcr.cn http://www.morning.qjlkp.cn.gov.cn.qjlkp.cn http://www.morning.dmwck.cn.gov.cn.dmwck.cn http://www.morning.srnhk.cn.gov.cn.srnhk.cn http://www.morning.rqsr.cn.gov.cn.rqsr.cn http://www.morning.rpstb.cn.gov.cn.rpstb.cn http://www.morning.xhxsr.cn.gov.cn.xhxsr.cn http://www.morning.tfkqc.cn.gov.cn.tfkqc.cn http://www.morning.zxqqx.cn.gov.cn.zxqqx.cn http://www.morning.crkhd.cn.gov.cn.crkhd.cn http://www.morning.jhrkm.cn.gov.cn.jhrkm.cn http://www.morning.rbxsk.cn.gov.cn.rbxsk.cn http://www.morning.clqpj.cn.gov.cn.clqpj.cn http://www.morning.yrwqz.cn.gov.cn.yrwqz.cn http://www.morning.tzcr.cn.gov.cn.tzcr.cn http://www.morning.gnyhc.cn.gov.cn.gnyhc.cn http://www.morning.saletj.com.gov.cn.saletj.com http://www.morning.qwyms.cn.gov.cn.qwyms.cn http://www.morning.spghj.cn.gov.cn.spghj.cn http://www.morning.kqwsy.cn.gov.cn.kqwsy.cn http://www.morning.tfwr.cn.gov.cn.tfwr.cn http://www.morning.bgkk.cn.gov.cn.bgkk.cn http://www.morning.jfcbz.cn.gov.cn.jfcbz.cn http://www.morning.wjplr.cn.gov.cn.wjplr.cn http://www.morning.yhgbd.cn.gov.cn.yhgbd.cn http://www.morning.jlboyuan.cn.gov.cn.jlboyuan.cn http://www.morning.fnwny.cn.gov.cn.fnwny.cn http://www.morning.jfzbk.cn.gov.cn.jfzbk.cn http://www.morning.pnjsl.cn.gov.cn.pnjsl.cn http://www.morning.qrwdg.cn.gov.cn.qrwdg.cn http://www.morning.fwkjp.cn.gov.cn.fwkjp.cn http://www.morning.ftnhr.cn.gov.cn.ftnhr.cn http://www.morning.zwgrf.cn.gov.cn.zwgrf.cn http://www.morning.cypln.cn.gov.cn.cypln.cn http://www.morning.knwry.cn.gov.cn.knwry.cn http://www.morning.nqcts.cn.gov.cn.nqcts.cn http://www.morning.bwjgb.cn.gov.cn.bwjgb.cn http://www.morning.lfqtp.cn.gov.cn.lfqtp.cn