使用 Qt 和 C++ 实现一个异形窗口和自定义颜色选择器的过程。
1. CustomShapeWidgetUi
类
该类实现了一个具有自定义形状和颜色选择功能的窗口。
构造函数 CustomShapeWidgetUi
CustomShapeWidgetUi::CustomShapeWidgetUi(const QString &imagePath, QDialog *parent): QDialog(parent), backgroundPixmap(imagePath), ui(new Ui::CustomShapeWidgetUi)
{ui->setupUi(this);// 设置窗口无边框,透明背景setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);setAttribute(Qt::WA_TranslucentBackground);// 设置窗口形状setWindowShape(imagePath);resize(backgroundPixmap.size()); // 调整窗口大小为图片大小// 设置颜色选择器的响应connect(ui->colorPicker, &CustomColorPicker::colorChanged, [=](QColor color) {ui->colorEdit->setText(color.name());});// 设置关闭和确认按钮的功能connect(ui->cancelButton, &QToolButton::clicked, this, &QDialog::reject);connect(ui->okButton, &QToolButton::clicked, this, &QDialog::accept);
}
- 无边框和透明背景:
Qt::FramelessWindowHint
移除窗口边框,Qt::WA_TranslucentBackground
设置背景透明,配合异形窗口实现。 - 形状设置:调用
setWindowShape
,根据图片的非透明区域设置窗口形状。 - 颜色选择:
colorChanged
信号和槽函数更新colorEdit
显示颜色的十六进制值。 - 按钮功能:关闭按钮和确认按钮使用
reject
和accept
信号关闭对话框。
重写 paintEvent
void CustomShapeWidgetUi::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.drawPixmap(0, 0, backgroundPixmap);QWidget::paintEvent(event); // 调用基类的 paintEvent 保持设计师元素的绘制
}
使用 QPainter
绘制背景图片,并调用基类的 paintEvent
保持其他 UI 元素的正常绘制。
setWindowShape
方法
void CustomShapeWidgetUi::setWindowShape(const QString &imagePath)
{QPixmap pixmap(imagePath);QRegion region;// 根据图片的透明区域生成 QRegionfor (int y = 0; y < pixmap.height(); ++y) {for (int x = 0; x < pixmap.width(); ++x) {if (QColor(pixmap.toImage().pixel(x, y)).alpha() > 0) {region += QRegion(x, y, 1, 1);}}}setMask(region);
}
这里通过遍历图片像素点,判断每个像素的透明度,以生成自定义窗口形状的 QRegion
,并将该 QRegion
应用到窗口的遮罩 (setMask
) 上。
2. CustomColorPicker
类
CustomColorPicker
类实现了一个自定义颜色选择器。
构造函数 CustomColorPicker
CustomColorPicker::CustomColorPicker(QWidget *parent): QWidget(parent), brightness(255), updatingBrightness(false)
{setFixedSize(220, 220); // 设置控件大小color = QColor::fromHsv(0, 255, brightness);hueSatPoint = QPoint(0, height());
}
- 固定大小:颜色选择器被设置为 220x220。
- 初始颜色:默认颜色设置为最大亮度的红色,亮度设为 255。
- 位置初始化:
hueSatPoint
定位到左下角。
paintEvent
方法
void CustomColorPicker::paintEvent(QPaintEvent *event)
{QPainter painter(this);// 绘制色相-饱和度选择区域QImage hueSatImage(width() - 30, height(), QImage::Format_RGB32);for (int x = 0; x < hueSatImage.width(); ++x) {for (int y = 0; y < hueSatImage.height(); ++y) {int hue = static_cast<int>((360.0 * x) / hueSatImage.width());int saturation = static_cast<int>((255.0 * (hueSatImage.height() - y)) / hueSatImage.height());QColor tempColor = QColor::fromHsv(hue, saturation, brightness);hueSatImage.setPixelColor(x, y, tempColor);}}painter.drawImage(0, 0, hueSatImage);// 绘制亮度滑条QLinearGradient gradient(0, 0, 0, height());gradient.setColorAt(0, QColor::fromHsv(color.hue(), color.saturation(), 255));gradient.setColorAt(1, QColor::fromHsv(color.hue(), color.saturation(), 0));painter.fillRect(width() - 20, 0, 20, height(), gradient);// 绘制选中点指示器painter.setPen(QPen(Qt::black, 2));painter.setBrush(Qt::NoBrush);painter.drawRect(hueSatPoint.x() - 10, hueSatPoint.y() - 10, 20, 20);// 绘制亮度滑条上的指示器int brightnessY = height() - (brightness * height() / 255);painter.drawRect(width() - 20, brightnessY - 5, 20, 10);
}
- 色相-饱和度区域:通过
QImage
绘制 2D 色相-饱和度区域,亮度保持不变。 - 亮度滑条:设置渐变颜色,用当前色相和饱和度生成亮度变化效果。
- 指示器:指示器在色相-饱和度区域和亮度滑条上,展示当前选中的颜色。
鼠标事件处理
void CustomColorPicker::mousePressEvent(QMouseEvent *event) {if (event->x() < width() - 30) {hueSatPoint = event->pos();updatingBrightness = false;updateColorFromHueSat();} else {updatingBrightness = true;updateColorFromBrightness(event->y());}
}void CustomColorPicker::mouseMoveEvent(QMouseEvent *event) {if (event->buttons() & Qt::LeftButton) {if (updatingBrightness) {updateColorFromBrightness(event->y());} else if (event->x() < width() - 30) {hueSatPoint = event->pos();updateColorFromHueSat();}}
}
- 点击:判断点击的位置,是色相-饱和度区域还是亮度滑条。
- 拖动:在点击的区域内拖动时,更新相应的颜色。
更新颜色的方法
void CustomColorPicker::updateColorFromHueSat()
{int hue = static_cast<int>((360.0 * hueSatPoint.x()) / (width() - 30));int saturation = static_cast<int>((255.0 * (height() - hueSatPoint.y())) / height());hue = qBound(0, hue, 359);saturation = qBound(0, saturation, 255);color.setHsv(hue, saturation, brightness);emit colorChanged(color);update();
}void CustomColorPicker::updateColorFromBrightness(int y)
{brightness = qBound(0, 255 * (height() - y) / height(), 255);color.setHsv(color.hue(), color.saturation(), brightness);emit colorChanged(color);update();
}
- 色相和饱和度更新:根据
hueSatPoint
计算色相和饱和度,确保其在合理范围内 (qBound
)。 - 亮度更新:根据鼠标在亮度滑条上的位置更新亮度。