最近写了一个修改头像功能的UI,布局参考了QQ目前的修改头像界面。如下图
这里主要说明一下两个地方的技术:1.头像图片上层的遮罩层,圆形外部为灰色,内部为全透明;2.上传图片宽高比例可以通过鼠标拖拽移动图片显示并通过滑动条进行图片大小放缩
遮罩层说明
遮罩层的处理主要在于怎么在一个透明灰色窗口上擦除出一个透明的圆形。之前使用了QPainter::CompositionMode里面的QPainter::CompositionMode_Clear擦除模式,但是试验后结果是,对于顶层窗口(没有父窗口)的效果是OK的,但是针对这里以显示图片的滚动区域窗口为父窗口的遮罩层,擦除只会变成完全的黑色。
重新考虑之后想到了ClipPath,剪切的绘图路径,通过在QPainterPath里增加路径获取一个剪切路径,再设置给QPainter,即可达到需要的效果,关键代码如下
m_pDivWidget->resize(ui.scrollArea->size()); QPainterPath path; path.addRect(m_pDivWidget->geometry()); path.addEllipse(m_pDivWidget->geometry().adjusted(2, 2, -2, -2)); QPainter p(m_pDivWidget); p.setRenderHint(QPainter::Antialiasing); p.setBrush(QColor(100, 100, 100, 200)); p.setClipPath(path); p.drawRect(m_pDivWidget->geometry());
如果不想子类化QWidget,可以在父窗口里注册过滤事件,捕获遮罩层的绘图事件来重绘遮罩层QEvent::Paint == event->type()。
拖拽滚动窗口
其实简单说就是拖拽来模拟滚动条拖拽的效果,拖拽的距离和滚动区域内展示窗口的大小比例,再结合滚动条的当前值可以算出滚动条应该更新的值。代码如下
DragScrollArea::DragScrollArea(QWidget *parent) : QScrollArea(parent) {
//首先,关闭显示所有滚动条 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } DragScrollArea::~DragScrollArea() { } bool DragScrollArea::event(QEvent* event) { if (widget()) //没有滚动窗口的时候,不处理 { static QPoint pos;//记录拖拽位置 if (QEvent::MouseButtonPress == event->type()) {
//开始拖拽 QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); pos = mouseEvent->pos(); } else if (QEvent::MouseMove == event->type()) { QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); if (Qt::LeftButton & mouseEvent->buttons()) {
//计算偏移量 pos = mouseEvent->pos() - pos;
//根据偏移量算出当前滚动条更新的值 horizontalScrollBar()->setValue(horizontalScrollBar()->value() - pos.x()*horizontalScrollBar()->maximum() / widget()->width()); verticalScrollBar()->setValue(verticalScrollBar()->value() - pos.y()*verticalScrollBar()->maximum() / widget()->height()); pos = mouseEvent->pos(); } } } return QScrollArea::event(event); }
最终效果如图
项目代码地址,界面重新做了简单调整
https://github.com/KaiMingPrince/QtProject/tree/master/ChangeHeader