1. 新增模型区域点击接口,同时为Windows添加了完美的透明区域鼠标透穿功能,以及Linux的基本点击区域识别功能(即非完美透传)
2. 更新了LICENSE
This commit is contained in:
@@ -80,7 +80,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
void StopLipSync();
|
void StopLipSync();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模型是否有命中区域定义
|
||||||
|
* @return 是否有命中区域
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool HasHitAreas() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检测点是否在模型的任何可见部分上
|
||||||
|
* @param x 视图坐标X
|
||||||
|
* @param y 视图坐标Y
|
||||||
|
* @return 是否命中
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool IsPointOnModel(Csm::csmFloat32 x, Csm::csmFloat32 y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief model3.jsonが置かれたディレクトリとファイルパスからモデルを生成する \n
|
* @brief model3.jsonが置かれたディレクトリとファイルパスからモデルを生成する \n
|
||||||
@@ -177,6 +189,15 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void DoDraw();
|
void DoDraw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief 使用Drawable检测(当没有命中区域时使用)
|
||||||
|
* @param x 视图坐标X
|
||||||
|
* @param y 视图坐标Y
|
||||||
|
* @return 是否命中
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool IsPointOnDrawable(Csm::csmFloat32 x, Csm::csmFloat32 y);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief model3.jsonからモデルを生成する。<br>
|
* @brief model3.jsonからモデルを生成する。<br>
|
||||||
|
|||||||
@@ -82,6 +82,76 @@ LAppModel::~LAppModel()
|
|||||||
}
|
}
|
||||||
delete(_modelSetting);
|
delete(_modelSetting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LAppModel::HasHitAreas() const {
|
||||||
|
return _modelSetting && _modelSetting->GetHitAreasCount() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LAppModel::IsPointOnModel(const csmFloat32 x, const csmFloat32 y)
|
||||||
|
{
|
||||||
|
if (_model == nullptr || _opacity < 0.1f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 如果有命中区域,使用HitTest(是否存在命中区域,这取决于模型是否定义这两部分信息)
|
||||||
|
/* 通常是这样的信息,在.model3.json当中
|
||||||
|
"HitAreas": [
|
||||||
|
{
|
||||||
|
"Id": "HitAreaHead",
|
||||||
|
"Name": "Head"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "HitAreaBody",
|
||||||
|
"Name": "Body"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
if (HasHitAreas())
|
||||||
|
{
|
||||||
|
// 检查常用命中区域
|
||||||
|
const bool hit = HitTest(LAppDefine::HitAreaNameHead, x, y) ||
|
||||||
|
HitTest(LAppDefine::HitAreaNameBody, x, y);
|
||||||
|
if (_debugMode && hit)
|
||||||
|
{
|
||||||
|
LAppPal::PrintLogLn("[APP]Hit model via HitArea at (%.2f, %.2f)", x, y);
|
||||||
|
}
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
// 如果没有命中区域,使用Drawable检测
|
||||||
|
return IsPointOnDrawable(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LAppModel::IsPointOnDrawable(const csmFloat32 x, const csmFloat32 y)
|
||||||
|
{
|
||||||
|
if (_model == nullptr || _opacity < 0.01f) // 接近完全透明
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取所有Drawable的数量
|
||||||
|
const csmInt32 drawableCount = _model->GetDrawableCount();
|
||||||
|
// 遍历所有Drawable
|
||||||
|
for (csmInt32 i = 0; i < drawableCount; ++i)
|
||||||
|
{
|
||||||
|
// 获取Drawable的ID
|
||||||
|
const CubismIdHandle drawableId = _model->GetDrawableId(i);
|
||||||
|
// 检查Drawable是否可见
|
||||||
|
if (_model->GetDrawableDynamicFlagIsVisible(i))
|
||||||
|
{
|
||||||
|
// 使用CubismUserModel提供的IsHit函数检测
|
||||||
|
if (IsHit(drawableId, x, y))
|
||||||
|
{
|
||||||
|
if (_debugMode)
|
||||||
|
{
|
||||||
|
const csmChar* drawableName = _model->GetDrawableId(i)->GetString().GetRawString();
|
||||||
|
LAppPal::PrintLogLn("[APP]Hit drawable: %s at (%.2f, %.2f)",
|
||||||
|
drawableName, x, y);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void LAppModel::LoadAssets(const csmChar* dir, const csmChar* fileName)
|
void LAppModel::LoadAssets(const csmChar* dir, const csmChar* fileName)
|
||||||
{
|
{
|
||||||
|
|||||||
+11
-23
@@ -269,35 +269,23 @@ float LAppView::TransformScreenY(float deviceY) const
|
|||||||
#include "Id/CubismIdManager.hpp"
|
#include "Id/CubismIdManager.hpp"
|
||||||
bool LAppView::IsModelHit(const float deviceX, const float deviceY) const {
|
bool LAppView::IsModelHit(const float deviceX, const float deviceY) const {
|
||||||
const LAppLive2DManager* live2DManager = LAppLive2DManager::GetInstance();
|
const LAppLive2DManager* live2DManager = LAppLive2DManager::GetInstance();
|
||||||
if (!live2DManager || live2DManager->GetModelNum() == 0) {
|
if (!live2DManager || live2DManager->GetModelNum() == 0)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 坐标转换(设备坐标 -> Live2D View 坐标)
|
// 转换到视图坐标
|
||||||
const csmFloat32 viewX = _deviceToScreen->TransformX(deviceX);
|
const csmFloat32 viewX = TransformViewX(deviceX);
|
||||||
const csmFloat32 viewY = _deviceToScreen->TransformY(deviceY);
|
const csmFloat32 viewY = TransformViewY(deviceY);
|
||||||
|
|
||||||
// 正确获取 ID Handle(在 SDK 初始化后调用)
|
// 遍历所有模型
|
||||||
static const Csm::CubismId* bodyId = nullptr;
|
LAppModel* model = live2DManager->GetModel(0);
|
||||||
static const Csm::CubismId* headId = nullptr;
|
if (model && model->IsPointOnModel(viewX, viewY)) // 调用二次封装的IsPointOnModel函数
|
||||||
if (!bodyId) {
|
{
|
||||||
bodyId = CubismFramework::GetIdManager()->GetId("Body");
|
return true;
|
||||||
headId = CubismFramework::GetIdManager()->GetId("Head");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历所有模型进行碰撞检测
|
return false;
|
||||||
const csmUint32 modelCount = live2DManager->GetModelNum();
|
|
||||||
for (csmUint32 i = 0; i < modelCount; ++i) {
|
|
||||||
LAppModel* model = live2DManager->GetModel(i);
|
|
||||||
if (!model || !model->GetModel()) continue;
|
|
||||||
|
|
||||||
// 检查命中区域(修正:使用 SDK 提供的 ID)
|
|
||||||
if (model->IsHit(bodyId, viewX, viewY) || model->IsHit(headId, viewX, viewY)) {
|
|
||||||
return true; // 击中模型
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // 未击中模型
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LAppView::PreModelDraw(LAppModel& refModel)
|
void LAppView::PreModelDraw(LAppModel& refModel)
|
||||||
|
|||||||
@@ -1,6 +1,21 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2025 Misakiotoha
|
Copyright (c) 2025 Misakiotoha
|
||||||
|
This application contains the Live2D Cubism SDK developed by Live2D Inc.
|
||||||
|
of which the copyrights are held by Live2D Inc.
|
||||||
|
If this application is utilized as a primary element of a business* and its annual sales made directly or indirectly by this application exceed 20 million JPY,
|
||||||
|
you shall be obliged to execute a Publication License Agreement with Live2D Inc.
|
||||||
|
and pay required license fees. You shall also be obliged to immediately notify Live2D Inc.
|
||||||
|
when the annual sales exceed 20 million JPY.
|
||||||
|
Any violation of these obligations means the utilization of Live2D Cubism SDK beyond the scope permitted by Live2D Inc.
|
||||||
|
with regard to this application and the infringement of intellectual property rights of Live2D Inc.,
|
||||||
|
and you may receive legal claims from Live2D Inc.
|
||||||
|
|
||||||
|
*"Utilizing this application as a primary element of a business" includes but is not limited to operating a VTuber streaming business.
|
||||||
|
It does not include streaming video contents for sales promotion.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
本项目使用CMake构建,基于C++Qt6以及Live2D官方SDK实现桌面宠物
|
本项目使用CMake构建,基于C++Qt6.6.3以及Live2D官方SDK(CubismSdkForNative-5-r.4.1)实现Live2D桌面宠物
|
||||||
(本项目由Yosuga[Qt5] 发展更新而来,项目架构与代码都有所不同,最显著的特点是本项目支持多平台)
|
(本项目由Yosuga[Qt5] 发展更新而来,项目架构与代码都有所不同,最显著的特点是本项目支持多平台)
|
||||||
环境为:
|
环境为:
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ make
|
|||||||
```
|
```
|
||||||
|
|
||||||
注意:本项目只是Yosuga的客户端部分,完整的还包括服务端
|
注意:本项目只是Yosuga的客户端部分,完整的还包括服务端
|
||||||
- 服务端项目地址:
|
- 服务端项目地址见:
|
||||||
|
|
||||||
当前支持平台(已测试过的):
|
当前支持平台(已测试过的):
|
||||||
- Windows: Windows 10
|
- Windows: Windows 10
|
||||||
@@ -46,3 +46,25 @@ make
|
|||||||
相关教程见BiliBili:https://www.bilibili.com/video/BV1TtkHYpEDA/?spm_id_from=333.1387.homepage.video_card.click&vd_source=d66e155c7b27c10078bc67965ea1989e
|
相关教程见BiliBili:https://www.bilibili.com/video/BV1TtkHYpEDA/?spm_id_from=333.1387.homepage.video_card.click&vd_source=d66e155c7b27c10078bc67965ea1989e
|
||||||
|
|
||||||
实现效果:
|
实现效果:
|
||||||
|
|
||||||
|
|
||||||
|
关于授权 <br>
|
||||||
|
本项目采用多重授权结构:
|
||||||
|
|
||||||
|
1. 原创代码部分:MIT License
|
||||||
|
src/*.*
|
||||||
|
|
||||||
|
2. 依赖库:
|
||||||
|
- Qt 6.6.3:LGPLv3 License
|
||||||
|
(提供源码获取方式:https://www.qt.io/download)
|
||||||
|
Qt部分采用动态链接方式
|
||||||
|
- Live2D Cubism SDK:Live2D Proprietary Software License
|
||||||
|
(需遵守销售额限制及授权协议)
|
||||||
|
Live2D部分采用静态链接 + 动态链接方式
|
||||||
|
本应用程序包含由Live2D Inc.开发的Live2D Cubism SDK,其版权由Live2D Inc.持有。
|
||||||
|
如果本应用程序被用作业务的主要元素*,并且其直接或间接产生的年销售额超过2000万日元,您需与Live2D Inc.签订单独的出版许可协议并支付许可费。
|
||||||
|
此外,当您的年销售额超过2000万日元时,请您尽快与我们联系。
|
||||||
|
请注意,如果您违反该条款,您将超出本应用程序允许的使用范围,这会造成对Live2D Inc.的知识产权侵犯,可能会导致公司的法律索赔。
|
||||||
|
*本应用程序作为业务的主要元素使用时,包括但不限于虚拟主播的直播业务。
|
||||||
|
这不包括应用软件用于发布产品宣传视频的情况。
|
||||||
|
3. 整体项目:受上述所有许可证约束
|
||||||
@@ -80,5 +80,10 @@ private:
|
|||||||
bool isLeftPressed; /// 鼠标左键是否按下
|
bool isLeftPressed; /// 鼠标左键是否按下
|
||||||
bool isRightPressed; /// 鼠标右键是否按下
|
bool isRightPressed; /// 鼠标右键是否按下
|
||||||
QPoint currentPos; /// 当前鼠标位置
|
QPoint currentPos; /// 当前鼠标位置
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <windows.h>
|
||||||
|
private:
|
||||||
|
HWND hwnd; // Windows窗口句柄
|
||||||
|
void setWindowTransparentForMouse(bool transparent);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
+77
-19
@@ -48,7 +48,6 @@ GLCore::GLCore(int w, int h, QWidget *parent)
|
|||||||
QFontDatabase::addApplicationFont("Resources/Font/ElaAwesome.ttf");
|
QFontDatabase::addApplicationFont("Resources/Font/ElaAwesome.ttf");
|
||||||
QApplication::setFont(QFont("Microsoft YaHei", 13));
|
QApplication::setFont(QFont("Microsoft YaHei", 13));
|
||||||
|
|
||||||
|
|
||||||
// new一些必要的对象
|
// new一些必要的对象
|
||||||
contextMenu = new Menu(this);
|
contextMenu = new Menu(this);
|
||||||
|
|
||||||
@@ -74,6 +73,10 @@ GLCore::GLCore(int w, int h, QWidget *parent)
|
|||||||
});
|
});
|
||||||
frameTimer->start(static_cast<int>((1.0 / frameRate) * 1000)); // 使用成员变量计算间隔
|
frameTimer->start(static_cast<int>((1.0 / frameRate) * 1000)); // 使用成员变量计算间隔
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// 保存窗口句柄
|
||||||
|
hwnd = reinterpret_cast<HWND>(this->winId());
|
||||||
|
#endif
|
||||||
|
|
||||||
// 启用鼠标跟踪,不启用的话鼠标按下才会回调mouseMoveEvent函数
|
// 启用鼠标跟踪,不启用的话鼠标按下才会回调mouseMoveEvent函数
|
||||||
this->setMouseTracking(true);
|
this->setMouseTracking(true);
|
||||||
@@ -160,14 +163,37 @@ void GLCore::closeEvent(QCloseEvent* event)
|
|||||||
event->accept(); // 确保关闭事件被接受
|
event->accept(); // 确保关闭事件被接受
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
void GLCore::setWindowTransparentForMouse(bool transparent)
|
||||||
|
{
|
||||||
|
if (!hwnd) return;
|
||||||
|
|
||||||
|
LONG exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||||
|
|
||||||
|
if (transparent) {
|
||||||
|
// 启用鼠标穿透
|
||||||
|
exStyle |= WS_EX_TRANSPARENT;
|
||||||
|
exStyle |= WS_EX_LAYERED;
|
||||||
|
} else {
|
||||||
|
// 禁用鼠标穿透
|
||||||
|
exStyle &= ~WS_EX_TRANSPARENT;
|
||||||
|
exStyle &= ~WS_EX_LAYERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle);
|
||||||
|
// 刷新窗口
|
||||||
|
SetWindowPos(hwnd, 0, 0, 0, 0, 0,
|
||||||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void GLCore::mouseMoveEvent(QMouseEvent* event)
|
void GLCore::mouseMoveEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
LAppDelegate::GetInstance()->GetView()->OnTouchesMoved(
|
const float x = static_cast<float>(event->position().x());
|
||||||
static_cast<float>(event->position().x()),
|
const float y = static_cast<float>(event->position().y());
|
||||||
static_cast<float>(event->position().y())
|
LAppDelegate::GetInstance()->GetView()->OnTouchesMoved(x, y); // 将当前鼠标位置传递给LAppDelegate
|
||||||
);
|
|
||||||
|
|
||||||
if (isLeftPressed) {
|
if (isLeftPressed) { // 鼠标左键按下
|
||||||
const QPoint newPos = event->globalPos() - currentPos;
|
const QPoint newPos = event->globalPos() - currentPos;
|
||||||
this->move(newPos);
|
this->move(newPos);
|
||||||
}
|
}
|
||||||
@@ -175,32 +201,65 @@ void GLCore::mouseMoveEvent(QMouseEvent* event)
|
|||||||
|
|
||||||
void GLCore::mousePressEvent(QMouseEvent* event)
|
void GLCore::mousePressEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
LAppDelegate::GetInstance()->GetView()->OnTouchesBegan(
|
const float x = static_cast<float>(event->position().x());
|
||||||
static_cast<float>(event->position().x()),
|
const float y = static_cast<float>(event->position().y());
|
||||||
static_cast<float>(event->position().y())
|
// 检测是否在模型上
|
||||||
);
|
bool onModel = false;
|
||||||
|
if (LAppDelegate::GetInstance() && LAppDelegate::GetInstance()->GetView()) {
|
||||||
|
onModel = LAppDelegate::GetInstance()->GetView()->IsModelHit(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
this->isLeftPressed = true;
|
LAppDelegate::GetInstance()->GetView()->OnTouchesBegan(x, y);
|
||||||
this->currentPos = event->globalPos() - this->frameGeometry().topLeft();
|
this->currentPos = event->globalPos() - this->frameGeometry().topLeft();
|
||||||
|
if (onModel) {
|
||||||
|
// 窗口拖动
|
||||||
|
this->isLeftPressed = true;
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// 确保窗口不穿透
|
||||||
|
setWindowTransparentForMouse(false);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// 透明区域:透传(只有WIndows完美实现了,Linux由于平台差异,只是简单实现,并没有完美透传功能)
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// 设置窗口为鼠标穿透
|
||||||
|
setWindowTransparentForMouse(true);
|
||||||
|
|
||||||
|
// 发送鼠标按下事件到底层窗口
|
||||||
|
POINT pt = { event->globalPos().x(), event->globalPos().y() };
|
||||||
|
HWND hWndBelow = WindowFromPoint(pt);
|
||||||
|
if (hWndBelow && hWndBelow != hwnd) {
|
||||||
|
// 转换坐标
|
||||||
|
ScreenToClient(hWndBelow, &pt);
|
||||||
|
|
||||||
|
// 发送鼠标按下消息
|
||||||
|
PostMessage(hWndBelow, WM_LBUTTONDOWN,
|
||||||
|
MK_LBUTTON, MAKELPARAM(pt.x, pt.y));
|
||||||
|
PostMessage(hWndBelow, WM_LBUTTONUP,
|
||||||
|
0, MAKELPARAM(pt.x, pt.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复窗口不穿透状态(下一次鼠标移动时会重新检测)
|
||||||
|
QTimer::singleShot(100, this, [this]() {
|
||||||
|
setWindowTransparentForMouse(false);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
this->isLeftPressed = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: 右键菜单等
|
// TODO: 右键菜单等
|
||||||
if (event->button() == Qt::RightButton) {
|
if (event->button() == Qt::RightButton) {
|
||||||
|
|
||||||
// 在鼠标右键点击的位置创建菜单,显示自定义右键菜单
|
// 在鼠标右键点击的位置创建菜单,显示自定义右键菜单
|
||||||
contextMenu->showMenu(event->globalPos());
|
contextMenu->showMenu(event->globalPos());
|
||||||
this->isRightPressed = true;
|
this->isRightPressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCore::mouseReleaseEvent(QMouseEvent* event)
|
void GLCore::mouseReleaseEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
LAppDelegate::GetInstance()->GetView()->OnTouchesEnded(
|
const float x = static_cast<float>(event->position().x());
|
||||||
static_cast<float>(event->position().x()),
|
const float y = static_cast<float>(event->position().y());
|
||||||
static_cast<float>(event->position().y())
|
LAppDelegate::GetInstance()->GetView()->OnTouchesEnded(x, y);
|
||||||
);
|
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
isLeftPressed = false;
|
isLeftPressed = false;
|
||||||
@@ -208,7 +267,6 @@ void GLCore::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
if (event->button() == Qt::RightButton) {
|
if (event->button() == Qt::RightButton) {
|
||||||
isRightPressed = false;
|
isRightPressed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCore::initializeGL()
|
void GLCore::initializeGL()
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ ModelPage::ModelPage(QWidget *parent)
|
|||||||
|
|
||||||
// 创建滑块控件和标签
|
// 创建滑块控件和标签
|
||||||
ElaText *modelSizeText = new ElaText("模型大小比例设置", this);
|
ElaText *modelSizeText = new ElaText("模型大小比例设置", this);
|
||||||
|
modelSizeText->setToolTip("实时调整模型大小");
|
||||||
modelSizeText->setTextPixelSize(15);
|
modelSizeText->setTextPixelSize(15);
|
||||||
modelSlider = new ElaSlider(this); // 滑块(用于设置模型实时大小)
|
modelSlider = new ElaSlider(this); // 滑块(用于设置模型实时大小)
|
||||||
modelSlider->setRange(0, 99); // 设置范围
|
modelSlider->setRange(0, 99); // 设置范围
|
||||||
|
|||||||
Reference in New Issue
Block a user