QT 使用QPixmap自定义光标 缩放图像模糊问题
QT中定义光标可以使用 Qt::CursorShape 预定义 的光标,也可以使用 QBitmap 和 QPixmap 自己绘制光标。QBitmap 只有黑白2色,QPixmap可以绘制彩色光标。使用QPixmap绘制光标时会出现光标边界模糊的情况,尤其是显示器设置缩放比例时,光标更是模糊。
出现模糊的原因有2个:
- QPixmap 投射到屏幕时自动进行了缩放,出现了图像缩放失真;
- 缩放时默认采用的算法导致图像信息丢失;
解决办法:
- 获取屏幕的缩放比例。
// 获取主屏幕的缩放比例
qreal screenRatio = QGuiApplication::primaryScreen()->devicePixelRatio();
qreal width = 32;
qreal height = 32;
// 创建位图,根据屏幕缩放比例调整图形大小
QPixmap pixmap(width*screenRatio, height*screenRatio);
pixmap.fill(Qt::transparent);
pixmap.setDevicePixelRatio(screenRatio);
- 选择更平滑的图像缩放算法。
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
// 出现缩放时选择更平滑的缩放算法
painter.setRenderHint(QPainter::SmoothPixmapTransform);
完整的自定义光标代码:
/**
* @brief 绘制光标
* @param width 光标宽带
* @param height 光标高度
*/
void AdjustPoint::createCursor(qreal angleOffset)
{
qreal width = 32;
qreal height = 32;
// 创建位图,根据屏幕缩放比例调整图形大小
QPixmap pixmap(width*screenRatio, height*screenRatio);
pixmap.fill(Qt::transparent);
pixmap.setDevicePixelRatio(screenRatio);
// 绘制
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setRenderHint(QPainter::VerticalSubpixelPositioning);
painter.setRenderHint(QPainter::LosslessImageRendering);
qreal winWidth = 20;
qreal winHeight = 8;
painter.setViewport((width - winWidth) / 2,(height - winHeight) / 2,
winWidth,winHeight);
painter.setWindow(-winWidth / 2,-winHeight / 2,winWidth,winHeight);
// 旋转光标图像到指定位置
painter.rotate(cursorAngle + angleOffset);
QPen pen(Qt::NoPen);
painter.setPen(pen);
QBrush brush(Qt::SolidPattern);
brush.setColor(QColor(borderColor));
painter.setBrush(brush);
painter.drawPath(createArrowPath(winHeight+2, winWidth+1));
brush.setColor(QColor(cursorColor));
painter.setBrush(brush);
painter.drawPath(createArrowPath(winHeight, winWidth));
painter.end();
// 创建光标,并设置
QCursor customCursor(pixmap);
setCursor(customCursor);
}
QPainterPath AdjustPoint::createArrowPath(qreal winHeight, qreal winWidth)
{
QPainterPath path;
qreal x1 = -winWidth / 2;
qreal x2 = x1 + winHeight / 2;
qreal x3 = -x2;
qreal x4 = -x1;
qreal y1 = -winHeight / 2;
qreal y2 = -winHeight * 1 /8;
qreal y3 = -y2;
qreal y4 = -y1;
path.moveTo(x1, 0);
path.lineTo(x2,y1);
path.lineTo(x2, y2);
path.lineTo(x3, y2);
path.lineTo(x3,y1);
path.lineTo(x4, 0);
path.lineTo(x3, y4);
path.lineTo(x3, y3);
path.lineTo(x2, y3);
path.lineTo(x2, y4);
path.lineTo(x1, 0);
path.closeSubpath();
return path;
}