使用QT绘制一个两侧为半圆中间为矩形的规则形状
首先 把这个形状叫做A
方便描述(因为我也不知道这是啥形状)
目标是由三个这种矩形组成的滑动条 如下图
绘制这个形状首先要知道对应A所在的矩形
然后根据这个矩形就可以通过这个函数makeSemicircleEdgeRectanglePath获取A的painterPath了
makeSemicircleEdgeRectanglePath(QRect rect)
{
int x = rect.x();
int y = rect.y();
int w = rect.width();
int h = rect.height();
int r = h/2;
QPoint leftCenter(x+r,y+r); //左侧半圆圆心
QPoint rightCenter(x+w-r,y+r); //右侧半圆圆心
QPoint leftTop(x+r,y); //左上角顶点
QPoint rightBottom(x+w-r,y+h); //右下角顶点
QRect leftSemicircleRect(x,y,h,h); //左半圆所在矩形
QRect rightSemicircleRect(x+w-h,y,h,h);//右半圆所在矩形
QPainterPath semicircleEdgeRectanglePath;
semicircleEdgeRectanglePath.moveTo(leftCenter);
semicircleEdgeRectanglePath.arcTo(leftSemicircleRect,90,180);
semicircleEdgeRectanglePath.lineTo(rightBottom);
semicircleEdgeRectanglePath.moveTo(rightCenter);
semicircleEdgeRectanglePath.arcTo(rightSemicircleRect,270,180);
semicircleEdgeRectanglePath.lineTo(leftTop);
semicircleEdgeRectanglePath.closeSubpath();
return semicircleEdgeRectanglePath;
}
//使用函数
QRect rect(x,y,w,h);
//painter.setPen(Qt::SolidLine);
painter.setPen(Qt::NoPen);
QLinearGradient linearGradient(x,y,x+w,y+h);
linearGradient.setColorAt(0.0,QColor(COLOR_LINE_BEGIN));
linearGradient.setColorAt(1.0,QColor(COLOR_LINE_END));
painter.setBrush(linearGradient);
QPainterPath linePath = makeSemicircleEdgeRectanglePath(rect);
painter.drawPath(linePath);
运行程序得到的效果却并不理想
查看官方文档知道当我从右下角moveTo到rightCenter时就已经形成了一段封闭路径
semicircleEdgeRectanglePath.moveTo(rightCenter);
The moveTo() function implicitly starts a new subpath, and closes the previous one.
解决方法1(无效):
修改填充Type
semicircleEdgeRectanglePath.setFillRule(Qt::WindingFill);
测试并没有效果
解决方案2(效果不佳):
将moveTo(rightCenter)改为lineTo(rightCenter);
效果如下:
可见lineTo的线还是被画出来了 此时在外部设置NoPen可以解决问题
painter.setPen(Qt::NoPen);
这种解决办法并不理想,因为作为一个makePath的工具函数你还必须在外部设置画笔,那必然是失败的
解决方案3:
不断的尝试发现画圆弧不需要先move到圆心,之前不知道是在那看的说明说要移到圆心坑了我,当时我就在想都已经知道矩形的位置了和起始的角度就可以绘制圆了,移动到圆心有什么意义呢?果然是不需要的,那问题就好解决了,且圆心的位置也不用设置了,省了一桩事
这样的话只要删掉semicircleEdgeRectanglePath.moveTo(rightCenter);
就可以了
运行显示正常
在设置画笔试试:
这条线出现的原因是因为起始点在左侧圆心,最后closeSubpath()时链接到了这里,吧刚开始的moveTo(leftCenter)
改成moveTo(leftTop)
就好了;
(扩展)半圆部分在上下
首先想到的是将矩形逆时针旋转90°,然后画A,画好后再顺时针旋转90°回去,结果跑去一看官方文档发现只有平移函数没有旋转函数,要旋转的话还是要对painter处理,那就只能使用又土又简单的方法了
makeSemicircleEdgeRectanglePath(QRect rect, bool isHorizontal)
{
int x = rect.x();
int y = rect.y();
int w = rect.width();
int h = rect.height();
int r = h/2;
QPainterPath semicircleEdgeRectanglePath;
semicircleEdgeRectanglePath.setFillRule(Qt::WindingFill);
QPoint leftTop(x+r,y); //左上角顶点
QPoint rightBottom(x+w-r,y+h); //右下角顶点
QRect leftSemicircleRect(x,y,h,h); //左半圆所在正方形
QRect rightSemicircleRect(x+w-h,y,h,h);
int relativeAngle = 0;
if (!isHorizontal)
{
r = w/2;
relativeAngle = 90;
rightBottom = QPoint(x,y+h-r); //vertical 情况下变成leftBottom
leftTop = QPoint(x+w,y+r); //vertical 情况下变成rightTop
leftSemicircleRect= QRect(x,y,w,w);//vertical 情况下变成上半圆所在正方形
rightSemicircleRect = QRect(x,y+h-w,w,w);//vertical 情况下变成下半圆所在正方形
}
semicircleEdgeRectanglePath.moveTo(leftTop);
semicircleEdgeRectanglePath.arcTo(leftSemicircleRect, 90 - relativeAngle, 180);
semicircleEdgeRectanglePath.lineTo(rightBottom);
semicircleEdgeRectanglePath.arcTo(rightSemicircleRect, 270 - relativeAngle, 180);
semicircleEdgeRectanglePath.lineTo(leftTop);
semicircleEdgeRectanglePath.closeSubpath();
return semicircleEdgeRectanglePath;
}