Qt写的指南针demo.
运行结果
滑动调整指针角度
实现代码
h文件
#ifndef COMPASS_H
#define COMPASS_H
#include <QWidget>
#include <QColor>
class Compass : public QWidget
{
Q_OBJECT
// 可自定义属性
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
Q_PROPERTY(QColor needleColor READ needleColor WRITE setNeedleColor)
Q_PROPERTY(QColor directionColor READ directionColor WRITE setDirectionColor)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
Q_PROPERTY(double angle READ angle WRITE setAngle)
Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth)
public:
explicit Compass(QWidget *parent = nullptr);
// 获取和设置属性
QColor backgroundColor() const;
void setBackgroundColor(const QColor &color);
QColor borderColor() const;
void setBorderColor(const QColor &color);
QColor needleColor() const;
void setNeedleColor(const QColor &color);
QColor directionColor() const;
void setDirectionColor(const QColor &color);
QColor textColor() const;
void setTextColor(const QColor &color);
double angle() const;
void setAngle(double angle);
int borderWidth() const;
void setBorderWidth(int width);
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
protected:
void paintEvent(QPaintEvent *event) override;
private:
void drawCompassCircle(QPainter &painter);
void drawDirectionMarkers(QPainter &painter);
void drawNeedle(QPainter &painter);
void drawTechRing(QPainter &painter);
QColor m_backgroundColor;
QColor m_borderColor;
QColor m_needleColor;
QColor m_directionColor;
QColor m_textColor;
double m_angle;
int m_borderWidth;
};
#endif // COMPASS_H
c文件
#include "widget.h"
#include <QPainter>
#include <QPainterPath>
#include <QtMath>
#include <QLinearGradient>
Compass::Compass(QWidget *parent) : QWidget(parent),
m_backgroundColor(QColor(30, 30, 40)),
m_borderColor(QColor(80, 160, 255)),
m_needleColor(QColor(255, 80, 80)),
m_directionColor(QColor(80, 255, 160)),
m_textColor(QColor(220, 220, 220)),
m_angle(0),
m_borderWidth(3)
{
setMinimumSize(100, 100);
}
QColor Compass::backgroundColor() const { return m_backgroundColor; }
void Compass::setBackgroundColor(const QColor &color) { m_backgroundColor = color; update(); }
QColor Compass::borderColor() const { return m_borderColor; }
void Compass::setBorderColor(const QColor &color) { m_borderColor = color; update(); }
QColor Compass::needleColor() const { return m_needleColor; }
void Compass::setNeedleColor(const QColor &color) { m_needleColor = color; update(); }
QColor Compass::directionColor() const { return m_directionColor; }
void Compass::setDirectionColor(const QColor &color) { m_directionColor = color; update(); }
QColor Compass::textColor() const { return m_textColor; }
void Compass::setTextColor(const QColor &color) { m_textColor = color; update(); }
double Compass::angle() const { return m_angle; }
void Compass::setAngle(double angle) { m_angle = angle; update(); }
int Compass::borderWidth() const { return m_borderWidth; }
void Compass::setBorderWidth(int width) { m_borderWidth = width; update(); }
QSize Compass::sizeHint() const { return QSize(200, 200); }
QSize Compass::minimumSizeHint() const { return QSize(100, 100); }
void Compass::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
// 绘制指南针背景
drawCompassCircle(painter);
// 绘制方向标记
drawDirectionMarkers(painter);
// 绘制科技感圆环
drawTechRing(painter);
// 绘制指针
drawNeedle(painter);
}
void Compass::drawCompassCircle(QPainter &painter)
{
int side = qMin(width(), height());
QRectF outerRect(0, 0, side, side);
outerRect.moveCenter(rect().center());
// 绘制背景
painter.setPen(Qt::NoPen);
painter.setBrush(m_backgroundColor);
painter.drawEllipse(outerRect);
// 绘制边框
QPen borderPen(m_borderColor);
borderPen.setWidth(m_borderWidth);
painter.setPen(borderPen);
painter.setBrush(Qt::NoBrush);
painter.drawEllipse(outerRect);
// 绘制内圆
QRectF innerRect = outerRect.adjusted(side*0.1, side*0.1, -side*0.1, -side*0.1);
QRadialGradient gradient(innerRect.center(), innerRect.width()/2);
gradient.setColorAt(0, QColor(50, 50, 60));
gradient.setColorAt(1, QColor(20, 20, 30));
painter.setPen(Qt::NoPen);
painter.setBrush(gradient);
painter.drawEllipse(innerRect);
}
void Compass::drawDirectionMarkers(QPainter &painter)
{
int side = qMin(width(), height());
QRectF outerRect(0, 0, side, side);
outerRect.moveCenter(rect().center());
painter.save();
painter.translate(outerRect.center());
QFont font = painter.font();
font.setPixelSize(side * 0.08);
font.setBold(true);
painter.setFont(font);
painter.setPen(m_textColor);
QStringList directions = {"N", "E", "S", "W"};
QStringList subDirections = {"NE", "SE", "SW", "NW"};
// 绘制主要方向标记
for (int i = 0; i < 4; ++i) {
painter.save();
painter.rotate(i * 90);
// 绘制刻度线
QPen pen(m_directionColor);
pen.setWidth(side * 0.01);
painter.setPen(pen);
painter.drawLine(0, -outerRect.height()*0.45, 0, -outerRect.height()*0.35);
// 绘制方向文字
painter.translate(0, -outerRect.height()*0.3);
painter.rotate(-i * 90);
painter.drawText(QRect(-side*0.1, -side*0.1, side*0.2, side*0.2),
Qt::AlignCenter, directions[i]);
painter.restore();
}
// 绘制次要方向标记
for (int i = 0; i < 4; ++i) {
painter.save();
painter.rotate(45 + i * 90);
// 绘制刻度线
QPen pen(m_directionColor);
pen.setWidth(side * 0.005);
painter.setPen(pen);
painter.drawLine(0, -outerRect.height()*0.45, 0, -outerRect.height()*0.38);
// 绘制方向文字
painter.translate(0, -outerRect.height()*0.33);
painter.rotate(-45 - i * 90);
painter.drawText(QRect(-side*0.1, -side*0.1, side*0.2, side*0.2),
Qt::AlignCenter, subDirections[i]);
painter.restore();
}
// 绘制更小的刻度
for (int i = 0; i < 36; ++i) {
if (i % 9 == 0) continue; // 跳过主要方向
painter.save();
painter.rotate(i * 10);
QPen pen(m_textColor);
pen.setWidth(side * 0.003);
painter.setPen(pen);
if (i % 3 == 0) {
// 中等刻度
painter.drawLine(0, -outerRect.height()*0.45, 0, -outerRect.height()*0.4);
} else {
// 小刻度
painter.drawLine(0, -outerRect.height()*0.45, 0, -outerRect.height()*0.42);
}
painter.restore();
}
painter.restore();
}
void Compass::drawNeedle(QPainter &painter)
{
int side = qMin(width(), height());
QRectF outerRect(0, 0, side, side);
outerRect.moveCenter(rect().center());
painter.save();
painter.translate(outerRect.center());
painter.rotate(m_angle);
// 创建科技感指针形状
QPainterPath needlePath;
// 主指针
needlePath.moveTo(0, -outerRect.height()*0.35);
needlePath.lineTo(-outerRect.width()*0.05, -outerRect.height()*0.05);
needlePath.lineTo(0, 0);
needlePath.lineTo(outerRect.width()*0.05, -outerRect.height()*0.05);
needlePath.closeSubpath();
// 尾翼
needlePath.moveTo(0, outerRect.height()*0.1);
needlePath.lineTo(-outerRect.width()*0.03, outerRect.height()*0.2);
needlePath.lineTo(0, outerRect.height()*0.25);
needlePath.lineTo(outerRect.width()*0.03, outerRect.height()*0.2);
needlePath.closeSubpath();
// 绘制指针
QLinearGradient gradient(0, -outerRect.height()*0.35, 0, outerRect.height()*0.25);
gradient.setColorAt(0, m_needleColor.lighter(150));
gradient.setColorAt(1, m_needleColor.darker(150));
painter.setPen(QPen(m_needleColor.darker(200), side*0.005));
painter.setBrush(gradient);
painter.drawPath(needlePath);
// 绘制中心圆点
QRadialGradient centerGradient(0, 0, side*0.05);
centerGradient.setColorAt(0, Qt::white);
centerGradient.setColorAt(1, m_needleColor);
painter.setPen(Qt::NoPen);
painter.setBrush(centerGradient);
painter.drawEllipse(QRectF(-side*0.05, -side*0.05, side*0.1, side*0.1));
painter.restore();
}
void Compass::drawTechRing(QPainter &painter)
{
int side = qMin(width(), height());
QRectF outerRect(0, 0, side, side);
outerRect.moveCenter(rect().center());
painter.save();
painter.translate(outerRect.center());
// 绘制外环科技感装饰
QPen techPen(m_borderColor);
techPen.setWidth(side * 0.01);
painter.setPen(techPen);
// 绘制分段圆环
for (int i = 0; i < 8; ++i) {
painter.save();
painter.rotate(i * 45);
QRectF segmentRect(-side*0.5, -side*0.5, side, side);
segmentRect.adjust(side*0.05, side*0.05, -side*0.05, -side*0.05);
int startAngle = 10 * 16;
int spanAngle = 25 * 16;
painter.drawArc(segmentRect, startAngle, spanAngle);
painter.restore();
}
// 绘制内环科技感装饰
QRectF innerRingRect(-side*0.3, -side*0.3, side*0.6, side*0.6);
techPen.setColor(m_directionColor);
techPen.setWidth(side * 0.005);
painter.setPen(techPen);
painter.setBrush(Qt::NoBrush);
painter.drawEllipse(innerRingRect);
// 绘制内环点阵
for (int i = 0; i < 36; ++i) {
painter.save();
painter.rotate(i * 10);
QPointF point(0, -side*0.25);
painter.setPen(Qt::NoPen);
painter.setBrush(m_directionColor);
painter.drawEllipse(point, side*0.005, side*0.005);
painter.restore();
}
painter.restore();
}
main.c
#include "widget.h"
#include <QApplication>
#include <QVBoxLayout>
#include <QSlider>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建指南针控件
Compass *compass = new Compass();
compass->setBackgroundColor(QColor(20, 25, 35));
compass->setBorderColor(QColor(0, 200, 255));
compass->setNeedleColor(QColor(255, 60, 60));
compass->setDirectionColor(QColor(0, 255, 180));
compass->setTextColor(Qt::white);
compass->setBorderWidth(4);
// 创建滑块控制方向
QSlider *slider = new QSlider(Qt::Horizontal);
slider->setRange(0, 360);
slider->setValue(0);
QObject::connect(slider, &QSlider::valueChanged, [compass](int value) {
compass->setAngle(value);
});
layout->addWidget(compass, 1);
layout->addWidget(slider);
window.resize(400, 450);
window.show();
return a.exec();
}