最近优化软件外观,做了一个很像空调遥控按钮的东西。分享一下
1.效果
2. 代码
#pragma once
#include <qwidget.h>
#include <qdebug.h>
#include <qpainter.h>
#include <QEnterEvent>
#include <QPaintEvent>
#include <QMouseEvent>
#include <QResizeEvent>
namespace mortal
{
const float PI = 3.1415926;
enum class Direction
{
without = 0b0000,
up = 0b0001,
left = 0b0010,
down = 0b0011,
right = 0b0100
};
class ControlButton : public QWidget
{
Q_OBJECT
signals:
void SignalHaveDown(Direction button);
private:
Direction now_button_down_;
Direction now_mouse_in_;
QColor in_circle_color_ , background_color_ , mouse_in_color_;
float in_circle_shadow_radius_;
QRadialGradient down_color_;
QVector<QString> button_text_;
QColor text_normal_color_, text_down_color_;
QFont text_font_;
float low_side_;
float in_radius_, out_radius_;
QPoint center_point_;
bool press_last;
QPoint GetRotatePoint(float radius, float angle)
{
return QPoint(radius * cos(angle * PI / 180), radius * sin(angle * PI / 180));
}
void DrawBackgroundCircle(QPainter &painter, float radius)
{
painter.save();
QPen pen;
pen.setColor(background_color_);
painter.setPen(pen);
QBrush brush(background_color_);
painter.setBrush(brush);
painter.drawEllipse(QPoint(0, 0), static_cast<int>(radius), static_cast<int>(radius));
painter.restore();
}
void DrawInCircle(QPainter &painter, float radius)
{
painter.save();
QPen pen;
pen.setColor(in_circle_color_);
painter.setPen(pen);
QBrush brush(in_circle_color_);
painter.setBrush(brush);
painter.drawEllipse(QPoint(0, 0), static_cast<int>(radius), static_cast<int>(radius));
painter.restore();
}
void DrawInCircleShadow(QPainter &painter, float radius)
{
painter.save();
QRadialGradient shadow_color(QPoint(0, 0), radius , QPoint(0,0));
shadow_color.setColorAt(0, Qt::black);
shadow_color.setColorAt(1, background_color_);
QPen pen;
pen.setColor(background_color_);
painter.setPen(pen);
QBrush brush(shadow_color);
painter.setBrush(brush);
painter.drawEllipse(QPoint(0, 0), static_cast<int>(radius), static_cast<int>(radius));
painter.restore();
}
QRect GetArcRect(int radius)
{
QRect rect(QPoint(-radius , -radius) , QSize(2*radius,2*radius));
return rect;
}
void DrawButton(QPainter& painter ,const QRect &rect,int radius , Direction should_draw)
{
painter.save();
if (should_draw != now_button_down_)
{
QPen pen;
if (should_draw == now_mouse_in_)
{
pen.setColor(mouse_in_color_);
}
else
{
pen.setColor(in_circle_color_);
}
pen.setWidth(0.5 * radius);
pen.setCapStyle(Qt::PenCapStyle::FlatCap);
painter.setPen(pen);
int begine_angle = 45 + (static_cast<int>(should_draw) - 1)*90;
int arc_long = 90;
painter.drawArc(rect, begine_angle * 16, arc_long * 16);
}
else
{
QBrush brush(down_color_);
painter.setBrush(brush);
int begine_angle = 45 + (static_cast<int>(should_draw) - 1) * 90;
int pie_long = 90;
int true_radius = radius ;
QRect down_rect(QPoint(- true_radius , - true_radius),QSize(true_radius*2 , true_radius*2));
painter.drawPie(down_rect, begine_angle * 16, pie_long * 16);
}
painter.restore();
}
void DrawLine(QPainter& painter, float out_radius, float in_radius, float width)
{
painter.save();
int begin_angle = 45;
QPen pen;
pen.setColor(background_color_);
pen.setWidth(width);
pen.setCapStyle(Qt::PenCapStyle::FlatCap);
painter.setPen(pen);
for (int i = 0; i < 4; i++)
{
painter.drawLine(GetRotatePoint(in_radius, begin_angle), GetRotatePoint(out_radius, begin_angle));
begin_angle += 90;
}
painter.drawEllipse(QPoint(0, 0), int(out_radius), int(out_radius));
painter.restore();
}
void DrawTriangle(QPainter &painter, Direction should_draw)
{
painter.save();
QPoint one , two , three;
float should_rotate = 90 * static_cast<int>(should_draw);
float rotate_angle = 3;
one = GetRotatePoint(470, - should_rotate);
two = GetRotatePoint(446, - (should_rotate + rotate_angle));
three = GetRotatePoint(446,-(should_rotate - rotate_angle));
QBrush brush(down_color_);
QPolygon local_poly;
local_poly << one << two << three;
QPainterPath linshi;
linshi.addPolygon(local_poly);
painter.fillPath(linshi, brush);
painter.restore();
}
void DrawButtonText(QPainter& painter, Direction should_draw)
{
painter.save();
QPen pen;
if (should_draw == now_button_down_)
{
pen.setColor(text_down_color_);
}
else
{
pen.setColor(text_normal_color_);
}
painter.setPen(pen);
painter.setFont(text_font_);
float should_rotate = -90 * static_cast<int>(should_draw);
QRect rect(GetRotatePoint(0.75 * 450, should_rotate), QSize(200, 100));
rect.adjust(-100, -50, -100, -50);
painter.drawText(rect, Qt::AlignCenter, button_text_[static_cast<int>(should_draw) - 1]);
painter.restore();
}
protected:
void paintEvent(QPaintEvent *event)override
{
QPainter painter(this);
painter.translate(this->rect().width() / 2, this->rect().height() / 2);
painter.scale(low_side_ / 1000, low_side_ / 1000);
painter.setRenderHint(QPainter::Antialiasing);
int radius = 450;
float in_circle_radius = 0.25;
QRect rect = GetArcRect(0.75 * radius);
for (int i = 1; i <= 4; i++)
{
this->DrawButton(painter, rect, radius, static_cast<Direction>(i));
}
this->DrawBackgroundCircle(painter, 0.5 * radius);
this->DrawInCircleShadow(painter, (in_circle_shadow_radius_ + in_circle_radius) * radius);
this->DrawInCircle(painter, radius * in_circle_radius);
this->DrawLine(painter, radius, 0.5 * radius, 10);
if (now_button_down_ != Direction::without)
{
this->DrawTriangle(painter, now_button_down_);
}
for (int i = 1; i <= 4; i++)
{
this->DrawButtonText(painter, static_cast<Direction>(i));
}
}
void enterEvent(QEvent* event)override
{
this->setMouseTracking(true);
}
void leaveEvent(QEvent* event)override
{
this->setMouseTracking(false);
}
void resizeEvent(QResizeEvent* event)override
{
low_side_ = (this->width() < this->height() ? this->width() : this->height());
in_radius_ = pow(low_side_ /4 ,2) ;
out_radius_ = pow(low_side_/2 * 0.9,2);
center_point_ = QPoint(this->width() / 2, this->height() / 2);
;//TODO
}
void mousePressEvent(QMouseEvent* event)override
{
if (now_mouse_in_ != Direction::without)
{
if (press_last == false)
{
now_button_down_ = now_mouse_in_;
}
else
{
if (now_button_down_ == now_mouse_in_)
{
now_button_down_ = Direction::without;
}
else
{
now_button_down_ = now_mouse_in_;
}
}
this->repaint();
}
}
void mouseReleaseEvent(QMouseEvent* event)override
{
if (now_mouse_in_ == now_button_down_)
{
if (press_last == false)
{
emit SignalHaveDown(now_button_down_);
now_button_down_ = Direction::without;
}
else
{
emit SignalHaveDown(now_button_down_);
}
}
else
{
now_button_down_ = Direction::without;
}
this->repaint();
}
void mouseMoveEvent(QMouseEvent* event)override
{
QPoint mouse_pos = event->pos();
float distance;
QPoint linshi = mouse_pos - center_point_;
distance = pow(linshi.x(), 2) + pow(linshi.y(), 2);
int flags = 0;
if (distance < out_radius_ && distance > in_radius_)
{
float cos_angle = QPoint::dotProduct(linshi, QPoint(1, 0)) /sqrt((pow(linshi.x(),2)+pow(linshi.y() ,2)));
float angle = (acos(cos_angle) * 180.0 /PI);
if (linshi.y() > 0)
{
angle = 360 - angle;
}
if (angle > 315 || angle < 45)
{
flags = 4;
}
else if (angle < 315 && angle > 225)
{
flags = 3;
}
else if (angle < 225 && angle > 135)
{
flags = 2;
}
else if (angle < 135 && angle > 45)
{
flags = 1;
}
}
if (now_mouse_in_ != static_cast<Direction>(flags))
{
now_mouse_in_ = static_cast<Direction>(flags);
this->repaint();
}
;//TODO
}
public:
ControlButton()
: button_text_{"上","左","下","右"}
{
now_button_down_ = Direction::without;
now_mouse_in_ = Direction::without;
background_color_ = QColor("#CEDAE8");
in_circle_color_ = Qt::white;
in_circle_shadow_radius_ = 0.075;
mouse_in_color_ = QColor("#E8EDF3");
down_color_ = QRadialGradient(0, 0, 500, 0, 0);
down_color_.setColorAt(0.5, QColor("#4392CB"));
down_color_.setColorAt(1, QColor("#00f2fe"));
text_normal_color_ = Qt::black;
text_down_color_ = Qt::white;
text_font_ = QFont("Hei", 50);
press_last = false;
}
~ControlButton() {}
void SetFLoatColor(const QColor& color = QColor("#E8EDF3")) { mouse_in_color_ = color; }
void SetBackgroundColor(const QColor& color = QColor("#CEDAE8")) { background_color_ = color; }
void SetNormalColor(const QColor& color = Qt::white) { in_circle_color_ = color; }
void SetInCircleShadowRadius(float radius = 0.075) { in_circle_shadow_radius_ = radius; }
void SetDownColor(QColor begin_color = QColor("#4392CB"), QColor end_color = QColor("#00f2fe"))
{
down_color_.setColorAt(0.5, begin_color);
down_color_.setColorAt(1, end_color);
}
void SetTextString(const QVector<QString>& text)
{
button_text_.clear();
for (auto i : text)
{
button_text_.append(i);
}
}
void SetTextColor(QColor normal = Qt::black, QColor down = Qt::white)
{
text_normal_color_ = normal;
text_down_color_ = down;
}
void SetTextFont(QFont font = QFont("Hei", 50))
{
text_font_ = font;
}
void SetPressKeep(bool keep = false) { press_last = keep; }
};
};