八、系统托盘与配置面板

news2025/1/13 13:29:24

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

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

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

一、系统托盘

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_OBJECT

public:
    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();
    // 平移参数X
    csmInt32 translateX = settings.value("Settings/TranslateX", 170).toInt();
    // 平移参数Y
    csmInt32 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);
#endif

        LAppDelegate::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.coloradmin.cn/o/2275981.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp 之 uni-forms校验提示【提交的字段[‘xxx‘]在数据库中并不存在】解决方案

目录 场景问题代码结果问题剖析解决方案 场景 uni-forms官方组件地址 使用uniapp官方提供的组件&#xff0c;某个表单需求&#xff0c;单位性质字段如果是高校&#xff0c;那么工作单位则是高校的下拉选择格式&#xff0c;单位性质如果是其他的类型&#xff0c;工作单位则是手动…

Java面试核心知识4

公平锁与非公平锁 公平锁&#xff08;Fair&#xff09; 加锁前检查是否有排队等待的线程&#xff0c;优先排队等待的线程&#xff0c;先来先得 非公平锁&#xff08;Nonfair&#xff09; 加锁时不考虑排队等待问题&#xff0c;直接尝试获取锁&#xff0c;获取不到自动到队尾…

基于 SSH 的任务调度系统

文末附有完整项目代码 在当今科技飞速发展的时代&#xff0c;任务调度系统的重要性日益凸显。本文将详细介绍一个基于 SSH&#xff08;SpringStruts2Hibernate&#xff09;的任务调度系统的设计与实现。 一、系统概述 本系统旨在改变传统人工任务调度方式&#xff0c;通过计算…

我的128天创作之路:回顾与展望

大家好呀&#xff01;今天来和你们分享一下我的创作历程&#x1f601;。 一、机缘 最开始创作呢&#xff0c;是因为在学习 C 的 STL 时&#xff0c;像 string、list、vector 这些模板可把我折腾得够呛&#xff0c;但也让我学到了超多东西&#xff01;我就想&#xff0c;要是把我…

性能测试工具Jmeter中的FTP脚本开发

FTP文件传输协议是TCP/IP协议组织中的常用协议之一&#xff0c;主要用在internet上双向传输文件。FTP协议具有客户端和服务器端两个部分组成部分&#xff0c;具有上传与下载两种功能。Jmeter也提供了FTP请求的测试支持&#xff0c;实现了上传和下载功能测试。 对于上图的FTP请求…

【C++】string的关系运算与比较分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;基础知识&#xff1a;C 中的 string 关系运算器1. 关系运算器概述2. 字符串比较的本质 &#x1f4af;代码解析与扩展代码例一&#xff1a;相等比较代码解析输出 代码例二&a…

mysql本地安装和pycharm链接数据库操作

MySQL本地安装和相关操作 Python相关&#xff1a;基础、函数、数据类型、面向、模块。 前端开发&#xff1a;HTML、CSS、JavaScript、jQuery。【静态页面】 Java前端&#xff1b; Python前端&#xff1b; Go前端 -> 【动态页面】直观&#xff1a; 静态&#xff0c;写死了…

深度学习|表示学习|一个神经元可以干什么|02

如是我闻&#xff1a; 如果我们只有一个神经元&#xff08;即一个单一的线性或非线性函数&#xff09;&#xff0c;仍然可以完成一些简单的任务。以下是一个神经元可以实现的功能和应用&#xff1a; 1. 实现简单的线性分类 输入&#xff1a;一组特征向量 x x x 输出&#xff…

HTB:Paper[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 对靶机进行子域…

做一个 简单的Django 《股票自选助手》显示 用akshare 库(A股数据获取)

图&#xff1a; 股票自选助手 这是一个基于 Django 开发的 A 股自选股票信息查看系统。系统使用 akshare 库获取实时股票数据&#xff0c;支持添加、删除和更新股票信息。 功能特点 支持添加自选股票实时显示股票价格和涨跌幅一键更新所有股票数据支持删除不需要的股票使用中…

Unity + Firebase + GoogleSignIn 导入问题

我目前使用 Unity版本&#xff1a;2021.3.33f1 JDK版本为&#xff1a;1.8 Gradle 版本为&#xff1a;6.1.1 Firebase 版本: 9.6.0 Google Sign In 版本为&#xff1a; 1.0.1 问题1 &#xff1a;手机点击登录报错 apk转化成zip&#xff0c;解压&#xff0c;看到/lib/armeabi-v…

Django学习笔记之数据库(一)

文章目录 安装一、数据库配置二、基本操作步骤1.增加2.查看3.排序4.更新5.删除数据 三、一对多&#xff0c;多对多&#xff0c;一对一1.一对多1.一对一1.多对多 四、查询操作五、聚合操作六、F和Q操作 安装 首先就是安装Mysql和Navicat。 一、数据库配置 其实整个就是连接前端…

SpringBoot日常:集成Kafka

文章目录 1、pom.xml文件2、application.yml3、生产者配置类4、消费者配置类5、消息订阅6、生产者发送消息7、测试发送消息 本章内容主要介绍如何在springboot项目对kafka进行整合&#xff0c;最终能达到的效果就是能够在项目中通过配置相关的kafka配置&#xff0c;就能进行消息…

RK3568 Android 13 内置搜狗输入法小计

问&#xff1a;为什么写&#xff1f; 答&#xff1a;网上搜出来的都试过了&#xff0c;不行&#xff01;下面直接上代码和注意事项&#xff01; 首先到这个目录&#xff08;/RK3568/Rockchip_Android13_SDK_Release/device/rockchip/rk356x/tl3568_evm/preinstall&#xff09…

【opencv】第8章 图像轮廓与图像分割修复

8.1 查找并绘制轮廓 一个轮廓一般对应一系列的点&#xff0c;也就是图像中的一条曲线。其表示方法可能 根据不同的情况而有所不同。在OpenCV 中&#xff0c;可以用findContours()函数从二值图 像中查找轮廓 8.1.1 寻找轮廓&#xff1a; findContours() 函数 findContours) 函…

BGP 泄露

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 目录 1. BGP 是什么&#xff1f; 2. 什么是 BGP 泄露&#xff1f; 3. 今天发生了什么&#xff1f; 4. 正常和被劫持状态下的路由示意图 5. 受影响区域 6. 责任在谁&#xff1f; 7. 有办法避免这…

数据结构与算法之二叉树: LeetCode 572. 另一棵树的子树 (Ts版)

另一棵树的子树 https://leetcode.cn/problems/subtree-of-another-tree/description/ 描述 给你两棵二叉树 root 和 subRoot检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false二叉树 tree …

动植物基因表达调控

1&#xff0c; on and off状态 以及表达的量 2&#xff0c; 基因调控的生物学影响&#xff1f; 超过400多种细胞类型&#xff0c;数目上37万亿 不是所有的基因都表达 为什么多核真核细胞需要基因调控&#xff1f; 单个细胞往多个细胞逐渐进化的过程&#xff0c;形成复杂的…

FreePBX 17 on ubuntu24 with Asterisk 20

版本配置&#xff1a; FreePBX 17&#xff08;最新&#xff09; Asterisk 20&#xff08;最新Asterisk 22&#xff0c;但是FreePBX 17最新只支持Asterisk 21&#xff0c;但是21非LTS版本&#xff0c;所以选择Asterisk 20&#xff09; PHP 8.2 Maria DB (v10.11) Node J…

“AI智能服务平台系统,让生活更便捷、更智能

大家好&#xff0c;我是资深产品经理老王&#xff0c;今天咱们来聊聊一个让生活变得越来越方便的高科技产品——AI智能服务平台系统。这个系统可是现代服务业的一颗璀璨明珠&#xff0c;它究竟有哪些魅力呢&#xff1f;下面我就跟大家伙儿闲聊一下。 一、什么是AI智能服务平台系…