八、系统托盘与配置面板

没有人会把你变得越来越好,时间和经历只是陪衬。

支撑你变得越来越好的,是你自己坚强的意志、修养、品行、以及不断的反思和经验。

人生最好的贵人,就是努力向上的自己。

一、系统托盘

1、资源文件夹

新建资源文件夹,我们需要把图片相关资源都放到这里,

这里我们新建一个 icon 文件夹,并且放入一个 cloud.png 图片作为系统托盘图标。

2、代码实现

我们使用 QMenu  来创建系统托盘菜单,使用 QAction 来定义菜单项,并且绑定对应的菜单触发事件,具体代码如下: 

void MainWindow::initSysTrayIcon(){ptrSysTrayIcon = new QSystemTrayIcon(QIcon(":/icon/cloud.png"), this);// 创建托盘菜单QMenu *trayMenu = new QMenu();// 添加设置菜单项QAction *settingsAction = new QAction("设置", this);QObject::connect(settingsAction, &QAction::triggered, this, &MainWindow::openSettingsWindow);trayMenu->addAction(settingsAction);// 添加退出菜单项QAction *exitAction = new QAction("退出", this);QObject::connect(exitAction, &QAction::triggered, this, &QCoreApplication::quit);trayMenu->addAction(exitAction);// 将菜单关联到托盘图标ptrSysTrayIcon->setContextMenu(trayMenu);// 显示托盘图标ptrSysTrayIcon->show();
}

3、显示托盘

在主窗口构造方法设置系统托盘,

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);initWindowSettings();initSysTrayIcon();
}void MainWindow::initSysTrayIcon(){ptrSysTrayIcon = new QSystemTrayIcon(QIcon(":/icon/cloud.png"), this);// 创建托盘菜单QMenu *trayMenu = new QMenu();// 添加设置菜单项QAction *settingsAction = new QAction("设置", this);QObject::connect(settingsAction, &QAction::triggered, this, &MainWindow::openSettingsWindow);trayMenu->addAction(settingsAction);// 添加退出菜单项QAction *exitAction = new QAction("退出", this);QObject::connect(exitAction, &QAction::triggered, this, &QCoreApplication::quit);trayMenu->addAction(exitAction);// 将菜单关联到托盘图标ptrSysTrayIcon->setContextMenu(trayMenu);// 显示托盘图标ptrSysTrayIcon->show();
}

运行之后,我们就可以在系统托盘中看到自定义的图标,并且右键后可以显示自定义的两个菜单。

二、配置面板

通过系统托盘菜单,我们需要跳转到对应的配置面板,对模型人物进行参数调整。

1、配置面板UI

UI 设计:添加角色下拉框,用来切换角色,添加三个滑动条分别控制 X 轴、Y 轴以及模型缩放比例,

2、UI 插槽

UI 头文件添加 slots,绑定控件事件,

#ifndef SETTINGSWINDOW_H
#define SETTINGSWINDOW_H#include <QMainWindow>#include <QScreen>
#include <QGuiApplication>namespace Ui {
class SettingsWindow;
}class SettingsWindow : public QMainWindow
{Q_OBJECTpublic:explicit SettingsWindow(QWidget *parent = nullptr);~SettingsWindow();
private slots:void onComboBoxRoleIndexChanged(int index);void onScaleValueChanged(int value);void onTranslateXValueChanged(int value);void onTranslateYValueChanged(int value);
private:Ui::SettingsWindow *ui;
};#endif // SETTINGSWINDOW_H

切换人物,

void SettingsWindow::onComboBoxRoleIndexChanged(int index){qDebug() << "onComboBoxRoleIndexChanged, Selected Index:" << index;LAppLive2DManager::GetInstance()->ChangeScene(index);
}

模型缩放,

void SettingsWindow::onScaleValueChanged(int value)
{// Scale [0,1]qDebug() << "Scale Value " << value * 0.01f;LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->Scale(value*0.01f,value*0.01f);}

X轴平移,

void SettingsWindow::onTranslateXValueChanged(int value)
{// TranslateX [-2,2]qDebug() << "TranslateX Value " << value * 0.01f;LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->TranslateX(value*0.01f);}

Y轴平移,

void SettingsWindow::onTranslateYValueChanged(int value)
{// TranslateY [-2,2]qDebug() << "TranslateY Value " << value * 0.01f;LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->TranslateY(value*0.01f);
}

三、参数记忆

配置面板设置了参数,只是临时的,并没有保存到配置文件,下次启动时,还是需要重新配置,为了解决这个问题,我们引入 QSettings 实现参数记忆。

1、记录当前人物

void SettingsWindow::onComboBoxRoleIndexChanged(int index){qDebug() << "onComboBoxRoleIndexChanged, Selected Index:" << index;QSettings settings("myapp.ini", QSettings::IniFormat);settings.setValue("Settings/Role", ui->comboBoxRole->currentText());settings.setValue("Settings/Index", index);LAppLive2DManager::GetInstance()->ChangeScene(index);
}

2、记录放缩比例 

void SettingsWindow::onScaleValueChanged(int value)
{// Scale [0,1]qDebug() << "Scale Value " << value * 0.01f;QSettings settings("myapp.ini", QSettings::IniFormat);settings.setValue("Settings/ScaleX", value);settings.setValue("Settings/ScaleY", value);LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->Scale(value*0.01f,value*0.01f);
}

3、记录X轴平移

void SettingsWindow::onTranslateXValueChanged(int value)
{// TranslateX [-2,2]qDebug() << "TranslateX Value " << value * 0.01f;QSettings settings("myapp.ini", QSettings::IniFormat);settings.setValue("Settings/TranslateX", value);LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->TranslateX(value*0.01f);
}

4、记录Y轴平移

void SettingsWindow::onTranslateYValueChanged(int value)
{// TranslateY [-2,2]qDebug() << "TranslateY Value " << value * 0.01f;QSettings settings("myapp.ini", QSettings::IniFormat);settings.setValue("Settings/TranslateY", value);LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->TranslateY(value*0.01f);
}

四、启动参数

在第三步,我们记录了模型参数,接下来实现在启动时根据参数来渲染模型。

1、实现原理

通过源代码 debug,不难发现渲染逻辑是通过 LAppLive2DManager 类的构造方法调用 ChangeScene 方法渲染模型,

2、代码实现

修改构造方法, 我们先从 myapp.ini 配置文件中获取参数,如果没有参数则采用默认值,

LAppLive2DManager::LAppLive2DManager(): _viewMatrix(NULL), _sceneIndex(0)
{_viewMatrix = new CubismMatrix44();// ChangeScene(_sceneIndex);// 加载上一次的运行参数QSettings settings("myapp.ini", QSettings::IniFormat);// 模型参数 读取参数值: 0 是默认值,如果 "Index" 不存在则返回 0_sceneIndex = settings.value("Settings/Index", 0).toInt();// 放缩参数csmInt32 scalesX =  settings.value("Settings/ScaleX", 100).toInt();csmInt32 scalesY = settings.value("Settings/ScaleY", 100).toInt();// 平移参数XcsmInt32 translateX = settings.value("Settings/TranslateX", 170).toInt();// 平移参数YcsmInt32 translateY = settings.value("Settings/TranslateY", -50).toInt();// 渲染模型CustomChangeScene(_sceneIndex,scalesX,scalesY,translateX,translateY);}

 自定义实现 CustomChangeScene 方法,按指定的参数渲染模型,

void LAppLive2DManager::CustomChangeScene(Csm::csmInt32 index,Csm::csmInt32 scalesX, Csm::csmInt32 scalesY,Csm::csmInt32 translateX,Csm::csmInt32 translateY)
{_sceneIndex = index;if (DebugLogEnable){LAppPal::PrintLog("[APP]model index: %d", _sceneIndex);}// ModelDir[]に保持したディレクトリ名から// model3.jsonのパスを決定する.// ディレクトリ名とmodel3.jsonの名前を一致させておくこと.std::string model = ModelDir[index];std::string modelPath = ResourcesPath + model + "/";std::string modelJsonName = ModelDir[index];modelJsonName += ".model3.json";ReleaseAllModel();_models.PushBack(new LAppModel());_models[0]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());// 自定义参数_models[0]->GetModelMatrix()->Scale(scalesX*0.01f,scalesY*0.01f);_models[0]->GetModelMatrix()->TranslateX(translateX*0.01f);_models[0]->GetModelMatrix()->TranslateY(translateY*0.01f);/** モデル半透明表示を行うサンプルを提示する。* ここでUSE_RENDER_TARGET、USE_MODEL_RENDER_TARGETが定義されている場合* 別のレンダリングターゲットにモデルを描画し、描画結果をテクスチャとして別のスプライトに張り付ける。*/{
#if defined(USE_RENDER_TARGET)// LAppViewの持つターゲットに描画を行う場合、こちらを選択LAppView::SelectTarget useRenderTarget = LAppView::SelectTarget_ViewFrameBuffer;
#elif defined(USE_MODEL_RENDER_TARGET)// 各LAppModelの持つターゲットに描画を行う場合、こちらを選択LAppView::SelectTarget useRenderTarget = LAppView::SelectTarget_ModelFrameBuffer;
#else \// デフォルトのメインフレームバッファへレンダリングする(通常)LAppView::SelectTarget useRenderTarget = LAppView::SelectTarget_None;
#endif#if defined(USE_RENDER_TARGET) || defined(USE_MODEL_RENDER_TARGET)// モデル個別にαを付けるサンプルとして、もう1体モデルを作成し、少し位置をずらす_models.PushBack(new LAppModel());_models[1]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());_models[1]->GetModelMatrix()->TranslateX(0.2f);
#endifLAppDelegate::GetInstance()->GetView()->SwitchRenderingTarget(useRenderTarget);// 別レンダリング先を選択した際の背景クリア色float clearColor[3] = { 1.0f, 1.0f, 1.0f };LAppDelegate::GetInstance()->GetView()->SetRenderTargetClearColor(clearColor[0], clearColor[1], clearColor[2]);}
}

五、运行效果

六、更多细节

二、Live2d 简介与使用_live2d是什么-CSDN博客

三、Live2d 移植 QT_live2d源文件-CSDN博客

四、模型渲染与透明背景_opengl 透明背景-CSDN博客

五、鼠标事件与目标焦点_鼠标指向焦点-CSDN博客

六、模型显示位置与放缩-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/439.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IntelliJ IDEA中Maven项目的配置、创建与导入全攻略

大家好&#xff0c;我是袁庭新。 IntelliJ IDEA是当前最流行的Java IDE&#xff08;集成开发环境&#xff09;之一&#xff0c;也是业界公认最好用的Java开发工具之一。IntelliJ IDEA支持Maven的全部功能&#xff0c;通过它我们可以很轻松地实现创建Maven项目、导入Maven项目、…

Element-plus、Element-ui之Tree 树形控件回显Bug问题。

需求&#xff1a;提交时&#xff0c;需要把选中状态和半选中状态 的数据id提交。如图所示&#xff1a; 数据回显时&#xff0c;会出现代码如下&#xff1a; <template><el-tree ref"treeRef" :data"tree" show-checkbox node-key"id" …

C语言#define定义宏

目录 一、什么是宏以及宏的声明方式 1.宏常量&#xff1a; 2.宏函数&#xff1a; 二、宏的替换原则 三、宏设计的易犯错误 ERROR1&#xff1a;尾部加分号&#xff08;当然有些特定需要加了分号&#xff0c;这里说明一般情况&#xff09; ERROR2&#xff1a;宏函数定义时&…

第33 章 - ES 实战篇 - MySQL 与 Elasticsearch 的一致性问题

思维导图 0. 前言 MySQL 与 Elasticsearch 一致性问题是老生常谈了。网上有太多关于这方面的文章了&#xff0c;但是千篇一律&#xff0c;看了跟没看没有太大区别。 在生产中&#xff0c;我们往往会通过 DTS 工具将 binlog 导入到 Kafka&#xff0c;再通过 Kafka 消费 binlog&…

Gitlab-Runner配置

原理 Gitlab-Runner是一个非常强大的CI/CD工具。它可以帮助我们自动化执行各种任务&#xff0c;如构建、测试和部署等。Gitlab-Runner和Gitlab通过API通信&#xff0c;接收作业并提交到执行队列&#xff0c;Gitlab-Runner从队列中获取作业&#xff0c;并允许在不同环境下进行作…

STM32第6章、WWDG

一、简介 WWDG&#xff1a;全称Window watchdog&#xff0c;即窗口看门狗&#xff0c;本质上是一个能产生系统复位信号和提前唤醒中断的计数器。 特性&#xff1a; 是一个递减计数器。 看门狗被激活后&#xff0c; 当递减计数器值从 0x40减到0x3F时会产生复位&#xff08;即T6位…

【Qt】事件、qt文件

目录 Qt事件 QEvent QMouseEvent QWheelEvent QKeyEvent QTimerEvent Qt文件 QFile QFileInfo Qt事件 在Qt中用一个对象表示一个事件&#xff0c;这些事件对象都继承自抽象类QEvent。事件和信号的目的是一样的&#xff0c;都是为了响应用户的操作。有两种产生事件的方…

Jenkins触发器--在其他项目执行后构建

前言&#xff1a; jenkins中有多种触发器可用&#xff0c;可以方便的控制构建的启动 这里简单介绍下项目后构建的配置方法 1. 解释&#xff1a; Build after other projects are built Set up a trigger so that when some other projects finish building, a new build is…

OpenStack 网络服务的插件架构

OpenStack 的网络服务具有灵活的插件架构&#xff0c;可支持多种不同类型的插件以满足不同的网络需求。以下是对 OpenStack 网络服务插件架构中一些常见插件类型的介绍&#xff1a; 一、SDN 插件 Neutron 与 SDN 的集成&#xff1a;在 OpenStack 网络服务里&#xff0c;SDN 插…

牛客网刷题 ——C语言初阶(6指针)——BC105 矩阵相等判定

1. 题目描述&#xff1a;BC105 矩阵相等判定 牛客网OJ题链接 描述&#xff1a; KiKi得到了两个n行m列的矩阵&#xff0c;他想知道两个矩阵是否相等&#xff0c;请你回答他。(当两个矩阵对应数组元素都相等时两个矩阵相等)。 示例1 输入&#xff1a; 2 2 1 2 3 4 1 2 3 4 输出…

SQLAlchemy

https://docs.sqlalchemy.org.cn/en/20/orm/quickstart.htmlhttps://docs.sqlalchemy.org.cn/en/20/orm/quickstart.html 声明模型 在这里&#xff0c;我们定义模块级构造&#xff0c;这些构造将构成我们从数据库中查询的结构。这种结构被称为 声明式映射&#xff0c;它同时定…

[SMARTFORMS] 导出SMARTFORMS表单数据

当我们配置好了Smartforms表单以后&#xff0c;如何在自开发的ALV程序报表中以PDF格式导出表单数据到电脑本地&#xff1f; 效果图 选择需要进行导出的采购凭证编号行数据&#xff0c;点击PDF格式导出按钮&#xff0c;弹出导出数据的信息窗口&#xff0c;点击"允许"…

seo泛目录(seo泛目录程序)

导言&#xff1a; 在搜索引擎优化&#xff08;SEO&#xff09;的领域中&#xff0c;泛目录程序被广泛应用于提升网站的可见性和排名。本文将深入探讨SEO泛目录程序的概念和作用&#xff0c;重点介绍它在网站优化中的重要性和优势&#xff0c;帮助读者了解SEO泛目录程序的工作原…

Trimble自动化激光监测支持历史遗产实现可持续发展【沪敖3D】

故事桥&#xff08;Story Bridge&#xff09;位于澳大利亚布里斯班&#xff0c;建造于1940年&#xff0c;全长777米&#xff0c;横跨布里斯班河&#xff0c;可载汽车、自行车和行人往返于布里斯班的北部和南部郊区。故事桥是澳大利亚最长的悬臂桥&#xff0c;是全世界两座手工建…

[人工智能自学] Python包学习-pandas

紧接上篇numpy的学习教程 本篇参考&#xff1a; Pandas 教程|菜鸟教程 官方教程 - 10分钟入门pandas joyful-pandas pandas中文教程 它建立在 NumPy 库的基础之上&#xff0c;提供了高效的数据结构和数据分析工具&#xff0c;使得在 Python 中进行数据操作变得更加容易和高效。…

【2024年华为OD机试】 (A卷,100分)- 二元组个数(Java JS PythonC/C++)

一、问题描述 以下是题目描述的 Markdown 格式&#xff1a; 题目描述 给定两个数组 a 和 b&#xff0c;若 a[i] b[j]&#xff0c;则称 [i, j] 为一个二元组。求在给定的两个数组中&#xff0c;二元组的个数。 输入描述 第一行输入 m&#xff0c;表示第一个数组的长度。第二…

数据结构与算法之二叉树: LeetCode 543. 二叉树的直径 (Ts版)

二叉树的直径 https://leetcode.cn/problems/diameter-of-binary-tree/description/ 描述 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 两节点之间路径的 长度 …

C# OpenCV机器视觉:OCR产品序列号识别

在一个看似平常却又暗藏玄机的工作日&#xff0c;阿明正坐在办公室里&#xff0c;对着堆积如山的文件唉声叹气。突然&#xff0c;电话铃声如炸雷般响起&#xff0c;吓得他差点从椅子上摔下来。原来是公司老板打来的紧急电话&#xff1a;“阿明啊&#xff0c;咱们刚生产出来的那…

【Powershell】Windows大法powershell好(二)

PowerShell基础&#xff08;二&#xff09; 声明&#xff1a;该笔记为up主 泷羽的课程笔记&#xff0c;本节链接指路。 警告&#xff1a;本教程仅作学习用途&#xff0c;若有用于非法行为的&#xff0c;概不负责。 1. powershell 执行外部命令 powershell也可以执行一些外部的…

JVM之垃圾回收器概述(续)的详细解析

ParNew(并行) Par 是 Parallel 并行的缩写&#xff0c;New 是只能处理的是新生代 并行垃圾收集器在串行垃圾收集器的基础之上做了改进&#xff0c;采用复制算法&#xff0c;将单线程改为了多线程进行垃圾回收&#xff0c;可以缩短垃圾回收的时间 对于其他的行为&#xff08;…