IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Qt:悬浮按钮 -> 正文阅读

[C++知识库]Qt:悬浮按钮

Qt:悬浮按钮

前言

基于QPushButton实现的悬浮按钮功能,并且加入了一些动画,目前实现了基本的功能,满足可用,其他功能细节正在完善中。实现思路计算坐标然后绘制,尽可能减少贴图的使用。
效果图如下,代码自取,请放心食用。有好的想法建议欢迎留言交流,会不定期回复。

效果图

在效果图

源码

懒得写描述了,自己看吧,直接拿去用也不是不行。

fr_floating_action_button.h

#ifndef FR_FLOATING_ACTION_BUTTON_H
#define FR_FLOATING_ACTION_BUTTON_H

#include <stdint.h>

#include <qpushbutton.h>
#include <qanimationgroup.h>
#include <qpropertyanimation.h>


class FrFloatingActionButton : public QPushButton {
  Q_OBJECT

public:
  explicit FrFloatingActionButton(QWidget *parent, uint8_t index);
  virtual ~FrFloatingActionButton();

  void set_path(const QString &path);
  void set_text(const QString &text);
  void set_icon(const QString &icon);

  void Show(bool is);
  void ReCalAnimation();

protected:
  virtual void paintEvent(QPaintEvent *event);
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
  virtual void enterEvent(QEnterEvent *event);
#else
  virtual void enterEvent(QEvent *event);
#endif
  virtual void leaveEvent(QEvent *event);

private:
  void draw_border(QPainter& painter);
  void draw_text(QPainter& painter);

private slots:
  void transpond_click_signal();

signals:
  void Clicked(QString text, QString path, quint8 index);
  void ButtonActived(quint8 index, bool is);

private:
  const uint8_t index_;
  QString path_;
  QString text_;
  QString icon_;

  QPropertyAnimation* zoom_in_;
  QPropertyAnimation* zoom_out_;

  QPropertyAnimation* float_out_;
  QPropertyAnimation* float_back_;
};

#endif // FR_FLOATING_ACTION_BUTTON_H

fr_floating_action_button.cpp

#include "fr_floating_action_button.h"

#include <math.h>

#include <qevent.h>
#include <qpainter.h>


#define DURATION 100

FrFloatingActionButton::FrFloatingActionButton(QWidget *parent, uint8_t index)
  : QPushButton(parent)
  , index_(index)
  , zoom_in_(new QPropertyAnimation(this, "geometry", this))
  , zoom_out_(new QPropertyAnimation(this, "geometry", this))
  , float_out_(new QPropertyAnimation(this, "pos", this))
  , float_back_(new QPropertyAnimation(this, "pos", this)) {

  connect(this, &FrFloatingActionButton::clicked, this, &FrFloatingActionButton::transpond_click_signal);
  connect(zoom_out_, &QPropertyAnimation::finished, this, &FrFloatingActionButton::hide);
}

FrFloatingActionButton::~FrFloatingActionButton() {
}

void FrFloatingActionButton::set_path(const QString &path) {
  path_ = path;
}

void FrFloatingActionButton::set_text(const QString &text) {
  text_ = text;
}

void FrFloatingActionButton::set_icon(const QString &icon) {
  icon_ = icon;
}

void FrFloatingActionButton::Show(bool is) {
  if (index_ == 0) {
    setVisible(is);
    return;
  }

  if (path_.isEmpty()) {
    setVisible(false);
    return;
  }

  if (is) {
    if (!isVisible()) {
      setVisible(is);
      zoom_in_->start();
    }
  } else {
    zoom_out_->start();
  }
}

void FrFloatingActionButton::ReCalAnimation() {
  zoom_in_->setStartValue(QRect(pos() * 1.25 , size() / 2.0));
  zoom_in_->setEndValue(QRect(pos(), size()));
  zoom_in_->setDuration(DURATION);

  zoom_out_->setStartValue(QRect(pos(), size()));
  zoom_out_->setEndValue(QRect(pos() * 1.25 , size() / 2.0));
  zoom_out_->setDuration(DURATION);

  QPoint offset;
  double step = width() * 0.025;

  switch (index_) {
    case 1:
      offset = QPoint(0, -step * 2);
      break;
    case 2:
      offset = QPoint(step * std::sqrt(3), -step);
      break;
    case 3:
      offset = QPoint(step * std::sqrt(3), step);
      break;
    case 4:
      offset = QPoint(0, step * 2);
      break;
    case 5:
      offset = QPoint(-step * std::sqrt(3), step);
      break;
    case 6:
      offset = QPoint(-step * std::sqrt(3), -step);
      break;
    default:
      break;
  }
  float_out_->setStartValue(pos());
  float_out_->setEndValue(pos() + offset);
  float_out_->setDuration(DURATION);

  float_back_->setStartValue(pos() + offset);
  float_back_->setEndValue(pos());
  float_back_->setDuration(DURATION);
}

void FrFloatingActionButton::paintEvent(QPaintEvent *event) {
  double side = qMin(double(width()), double(height()) / (std::sqrt(3) / 2.0));

  QPainter painter(this);

  painter.setRenderHint(QPainter::Antialiasing);
  painter.translate(width() / 2, height() / 2);
  painter.scale(side / 210.0, side / 210.0);
  painter.setPen(Qt::NoPen);
  painter.setBrush(Qt::NoBrush);

  draw_border(painter);
  draw_text(painter);
}

void FrFloatingActionButton::draw_border(QPainter &painter) {
  painter.save();

  QPen pen(Qt::darkCyan, 2);

  painter.setPen(pen);
  painter.setBrush(QColor(78, 128, 196, 128));

  static double sqtr3 = std::sqrt(3);
  QPointF* points = new QPointF[6];
  int i = 0;
  points[i++] = QPointF(50.0, sqtr3 * 50.0);
  points[i++] = QPointF(100, 0.0);
  points[i++] = QPointF(50.0, -sqtr3 * 50.0);
  points[i++] = QPointF(-50.0, -sqtr3 * 50.0);
  points[i++] = QPointF(-100.0, 0.0);
  points[i++] = QPointF(-50.0, sqtr3 * 50.0);
  painter.drawPolygon(points, 6);
  delete[] points;

  painter.restore();
}

void FrFloatingActionButton::draw_text(QPainter &painter) {
  painter.save();

  painter.setPen(Qt::black);
  painter.setFont(QFont("Times", 24));
  painter.drawText(QRectF(-100, -100, 200, 200), Qt::AlignCenter, text_);

  painter.restore();
}

void FrFloatingActionButton::transpond_click_signal() {
  emit Clicked(text_, path_, index_);
}

#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
void FrFloatingActionButton::enterEvent(QEnterEvent *event) {
#else
void FrFloatingActionButton::enterEvent(QEvent *event) {
#endif
  float_out_->start();
  emit ButtonActived(1 << index_, true);
}

void FrFloatingActionButton::leaveEvent(QEvent *event) {
  float_back_->start();
  emit ButtonActived(1 << index_, false);
}

fr_floating_action_button_panel.h

#ifndef FR_FLOATING_ACTION_BUTTON_PANEL_H
#define FR_FLOATING_ACTION_BUTTON_PANEL_H

#include <stdint.h>

#include <qwidget.h>
#include <qvariant.h>
#include <qjsondocument.h>
#include <qtimer.h>


class FrFloatingActionButton;

class FrFloatingActionButtonPanel : public QWidget
{
  Q_OBJECT

public:
  explicit FrFloatingActionButtonPanel(QWidget *parent = nullptr);
  ~FrFloatingActionButtonPanel();

protected:
  virtual void resizeEvent(QResizeEvent *event);
  virtual void showEvent(QShowEvent *event);

private:
  bool load_configuer();
  int load_buttons(const QString& path);
  void adjust_buttons_size();

private slots:
  void process_click(const QString& text, const QString& path, quint8 index);
  void active_buttons(quint8 index, bool is);
  void deactive_buttons();
  void zoom_in_button();
  void zoom_out_button();

signals:
  void Clicked(QString text, QString path);

private:
  QVariant values_;

  FrFloatingActionButton** buttons_;

  uint8_t actived_buttons_;
  QTimer* keep_timer_;

  QTimer* zoom_in_timer_;
};

#endif // FR_FLOATING_ACTION_BUTTON_PANEL_H

fr_floating_action_button_panel.cpp

#include "fr_floating_action_button_panel.h"

#include <stdint.h>
#include <math.h>

#include <qpainter.h>
#include <qevent.h>
#include <qfile.h>
#include <qstring.h>

#include <fr_floating_action_button.h>


FrFloatingActionButtonPanel::FrFloatingActionButtonPanel(QWidget *parent)
  : QWidget(parent)
  , buttons_(nullptr)
  , actived_buttons_(0)
  , keep_timer_(new QTimer(this))
  , zoom_in_timer_(new QTimer(this)) {

  setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
  setAttribute(Qt::WA_TranslucentBackground);

  buttons_ = new FrFloatingActionButton*[7];
  for (int i = 0; i < 7; ++i) {
    buttons_[i] = new FrFloatingActionButton(this, i);

    connect(buttons_[i], &FrFloatingActionButton::Clicked, this, &FrFloatingActionButtonPanel::process_click);
    connect(buttons_[i], &FrFloatingActionButton::ButtonActived, this, &FrFloatingActionButtonPanel::active_buttons);
    buttons_[i]->setVisible(i == 0);
  }

  keep_timer_->setSingleShot(true);
  connect(keep_timer_, &QTimer::timeout, this, &FrFloatingActionButtonPanel::deactive_buttons);

  bool ok = load_configuer();
  if (ok) {
    load_buttons(QString());
  } else {
    ; //配置文件错误
  }
}

FrFloatingActionButtonPanel::~FrFloatingActionButtonPanel() {
  if (nullptr != buttons_) {
    delete[] buttons_;
    buttons_ = nullptr;
  }
}

void FrFloatingActionButtonPanel::resizeEvent(QResizeEvent *event) {
  QWidget::resizeEvent(event);
  adjust_buttons_size();
}


void FrFloatingActionButtonPanel::showEvent(QShowEvent *event) {
  QWidget::showEvent(event);
  adjust_buttons_size();
}

bool FrFloatingActionButtonPanel::load_configuer() {
  QFile file("system_buttons/config.json");
  if(!file.open(QIODevice::ReadWrite)) {
    return false;
  }

  QByteArray json = file.readAll();

  QJsonParseError ok;
  values_ = QJsonDocument::fromJson(json, &ok).toVariant();

  return ok.error == QJsonParseError::NoError;
}

int FrFloatingActionButtonPanel::load_buttons(const QString &path) {
  auto values = values_.toList();
  auto tmp = path;

  QVariantMap last;
  last["index"] = QString();
  last["text"] = QString("哦吼");
  last["icon"] = QString("");

  while (!tmp.isEmpty()) {
    for (int i = 0; i < values.size(); ++i) {
      auto map = values[i].toMap();

      if(map.value("index").toString() == tmp.left(1)) {
        last = map;
        tmp.remove(0, 1);
        values = map.value("children").toList();
        continue;
      }
    }
  }

  if (values.isEmpty()) {
    return 0;
  }

  for (int i = 1; i < 7; ++i) {
    buttons_[i]->hide();
    buttons_[i]->set_path(QString());
  }

  values.insert(0, last);
  for (int i = 0; i < values.size() && i < 7; ++i) {
    auto map = values[i].toMap();
    if (i == 0) {
      buttons_[i]->set_path(path);
    } else {
      buttons_[i]->set_path(path + map.value("index").toString());
    }
    buttons_[i]->set_text(map.value("text").toString());
    buttons_[i]->set_icon(map.value("icon").toString());
    buttons_[i]->setVisible((i == 0) | !path.isEmpty());
  }

  buttons_[0]->update();

  return values.size() - 1;
}

void FrFloatingActionButtonPanel::adjust_buttons_size() {
  int margin = 0;
  bool by_witdh = double(width() - margin * 2) / 5.0 < double(height() - margin * 2) / (3 * std::sqrt(3));

  int button_width = 0, button_height = 0;
  if (by_witdh) {
    margin = width() / 20.0;
    button_width = double(width() - margin * 2) * 0.4;
    button_height = double(width() - margin * 2) * 0.2 * sqrt(3);
  } else {
    margin = height() / 20.0;
    button_width = double(height() - margin * 2) / (3.0 * sqrt(3)) * 2;
    button_height = double(height() - margin * 2) / 3.0;
  }

  QList<QPoint> poses;
  poses << QPoint(button_width * 0.75 + margin, button_height + margin)
        << QPoint(button_width * 0.75 + margin, margin)
        << QPoint(button_width * 1.50 + margin, button_height / 2 + margin)
        << QPoint(button_width * 1.50 + margin, button_height * 1.5 + margin)
        << QPoint(button_width * 0.75 + margin, button_height * 2.0 + margin)
        << QPoint(margin, button_height * 1.5 + margin)
        << QPoint(margin, button_height / 2 + margin);

  for (int i = 0; i < 7; ++i) {
    buttons_[i]->setGeometry(poses[i].x(), poses[i].y(), button_width, button_height);
    buttons_[i]->ReCalAnimation();
  }
}

void FrFloatingActionButtonPanel::process_click(const QString &text, const QString &path, quint8 index) {
  if (index == 0) {
    // 向上
    if (!path.isEmpty()) {
      load_buttons(path.left(path.size() - 1));
    } else {
      // 进入设置模式
    }
  } else {
    // 向下
    if(load_buttons(path) == 0) {
      emit Clicked(text, path);
    }
  }
}

void FrFloatingActionButtonPanel::active_buttons(quint8 index, bool is) {
  if (is) {
    if (index == 1) {
      zoom_in_timer_->start(25);

      connect(zoom_in_timer_, &QTimer::timeout, this, &FrFloatingActionButtonPanel::zoom_in_button);
      disconnect(zoom_in_timer_, &QTimer::timeout, this, &FrFloatingActionButtonPanel::zoom_out_button);
    }
    keep_timer_->stop();
  } else {
    keep_timer_->start(200);
  }
}

void FrFloatingActionButtonPanel::deactive_buttons() {
  zoom_in_timer_->start(25);
  disconnect(zoom_in_timer_, &QTimer::timeout, this, &FrFloatingActionButtonPanel::zoom_in_button);
  connect(zoom_in_timer_, &QTimer::timeout, this, &FrFloatingActionButtonPanel::zoom_out_button);
}

void FrFloatingActionButtonPanel::zoom_in_button() {
  bool is = false;
  for (int i = 1; i < 7; ++i) {
    if (!buttons_[i]->isVisible()) {
      buttons_[i]->Show(true);
      is = true;
      break;
    }
  }

  if (!is) {
    zoom_in_timer_->stop();
  }
}

void FrFloatingActionButtonPanel::zoom_out_button() {
  static int i = 1;

  buttons_[i++]->Show(false);

  i %= 7;

  if (i == 0) {
    zoom_in_timer_->stop();
    i = 1;
  }
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:37:29  更:2022-04-28 11:38:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:28:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码