八、系统托盘与配置面板

news/2025/1/16 20:32:52/

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

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

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

一、系统托盘

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.ppmy.cn/news/1563705.html

相关文章

Hive集群的安装准备

Hive的安装与集群部署详细指南 一、环境与软件准备 在开始Hive的安装与集群部署之前&#xff0c;确保您准备好以下环境和软件&#xff1a; 虚拟机软件&#xff1a; VMware Workstation 17.5&#xff1a;用于创建和管理虚拟机&#xff0c;确保可以在其上安装Linux操作系统。 …

神经网络基础-网络优化方法

文章目录 1. 梯度下降算法1.1 什么是梯度下降算法1.2 模型训练中的三个基础概念1.3 三种梯度下降方式对比 2. 反向传播[BP算法]了解2.1 什么是反向传播2.2 python实现反向传播 3 . 梯度下降的优化方法3.1 梯度下降为什么需要优化3.2 梯度下降优化方法3.2.1 指数加权平均3.2.2 动…

C++实现设计模式---模板方法模式 (Template Method)

模板方法模式 (Template Method) 模板方法模式 是一种行为型设计模式&#xff0c;它定义了一个操作中的算法骨架&#xff0c;将某些步骤的实现延迟到子类。通过模板方法&#xff0c;子类可以在不改变算法结构的情况下重新定义算法的某些步骤。 意图 在一个方法中定义算法的骨…

备战蓝桥杯:树的存储与遍历(dfs和bfs)

树的概念 树的逻辑结构是树形结构&#xff0c;和我们之前的线性结构又不太一样了&#xff0c;是一种一对多的关系 树的结点分为根节点&#xff0c;叶子结点&#xff08;没有分支的结点&#xff09; 以及分支结点 从上往下看&#xff0c;每个结点都有0个或多个后继 从下往上…

[读书日志]从零开始学习Chisel 第十二篇:Scala的抽象成员(敏捷硬件开发语言Chisel与数字系统设计)

9. Scala的抽象成员 9.1 抽象成员 Scala有4种抽象成员&#xff0c;分别是抽象val字段&#xff0c;抽象var字段&#xff0c;抽象方法和抽象类型。声明如下&#xff1a; scala> trait Abstract {| type T //抽象类型| def transform(x: T): T //抽象方法| val in…

未来十年:科技重塑生活的全景展望

在科技发展的浪潮中&#xff0c;过去十年我们目睹了智能手机、移动支付、共享经济等创新成果对生活的巨大改变。而未来十年&#xff0c;科技的步伐将迈得更大、更快&#xff0c;它将全方位地重塑人们的生活&#xff0c;从日常出行、健康管理到工作模式、社交互动&#xff0c;每…

面试之《web安全问题》

1. csrf攻击 &#xff08;Cross-site request forgery) 跨站请求伪造。利用用户的cookie&#xff0c;伪造用户操作接口。 案例 用户登陆了a网站&#xff0c;cookie已经生成。用户打开了钓鱼网站b&#xff0c;黑客在b网站中调用了a网站的接口&#xff0c;就可以用用户在a网站中的…

C++实现设计模式---抽象工厂模式 (Abstract Factory)

抽象工厂模式 (Abstract Factory) 抽象工厂模式 是一种创建型设计模式&#xff0c;提供一个接口&#xff0c;用于创建一组相关或互相依赖的对象&#xff0c;而无需指定它们的具体类。 意图 提供一个创建一组相关对象的接口&#xff0c;而无需指定它们的具体类。解决产品对象之…