Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08f3890ac4 | ||
|
|
21d8ef8c34 |
+21
-3
@@ -24,17 +24,35 @@
|
|||||||
{
|
{
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
"name": "Qt-Default",
|
"name": "Qt-Default",
|
||||||
"inherits": null,
|
"inherits": "allenv_qt5",
|
||||||
"vendor": {
|
"vendor": {
|
||||||
"qt-project.org/Default": {
|
"qt-project.org/Default": {
|
||||||
"checksum": "VoalogTkyWuFomeO1TLFx0olLJ4="
|
"checksum": "Z8G/I2NiO/EJ3GcqVEvZ0lSrMzM="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": true,
|
||||||
|
"name": "allenv_qt5",
|
||||||
|
"inherits": "Qt",
|
||||||
|
"environment": {
|
||||||
|
"QTDIR": "G:/detSystem/allenv/qt5"
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
"strategy": "external",
|
||||||
|
"value": "x64"
|
||||||
|
},
|
||||||
|
"generator": "Ninja",
|
||||||
|
"vendor": {
|
||||||
|
"qt-project.org/Version": {
|
||||||
|
"checksum": "fGB5SKr330WkMcI+0sxuX59JXuA="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"vendor": {
|
"vendor": {
|
||||||
"qt-project.org/Presets": {
|
"qt-project.org/Presets": {
|
||||||
"checksum": "DiAwp+JKAQXqWc2tOPE/U9qg77Y="
|
"checksum": "yQDlwrq4/xeG9pH9UtkSbCWd0/o="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
@@ -17,6 +17,11 @@
|
|||||||
#include <nlohmannjson.hpp>
|
#include <nlohmannjson.hpp>
|
||||||
#include <global.h>
|
#include <global.h>
|
||||||
#include <uiModule/components/fancyButton.h>
|
#include <uiModule/components/fancyButton.h>
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
|
#include <uiModule/components/sliderSwitch.h>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
class JsonParamTableEditor : public QDialog {
|
class JsonParamTableEditor : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -35,12 +40,24 @@ public:
|
|||||||
: QDialog(parent) {
|
: QDialog(parent) {
|
||||||
this->setWindowTitle("JSON 表格编辑器");
|
this->setWindowTitle("JSON 表格编辑器");
|
||||||
this->resize(700, 450);
|
this->resize(700, 450);
|
||||||
setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint); // 去掉边框 //现在、、
|
setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);// 去掉边框
|
||||||
//setAttribute(Qt::WA_TranslucentBackground); // 背景透明
|
//setAttribute(Qt::WA_TranslucentBackground); // 背景透明
|
||||||
this->setObjectName("JsonParamTableEditor");
|
this->setObjectName("JsonParamTableEditor");
|
||||||
this->setStyleSheet(QString("QDialog#JsonParamTableEditor {background-color: rgb(%1);border: 2px solid #000000;border-radius: 6px;}").arg(sColor_Blue));
|
this->setStyleSheet(QString("QDialog#JsonParamTableEditor {background-color: rgb(%1);border: 2px solid #000000;border-radius: 6px;}").arg(sColor_Blue));
|
||||||
m_tableWidget = new QTableWidget(0, 2, this);
|
|
||||||
m_tableWidget->setHorizontalHeaderLabels({ "选项", "值" });
|
m_tableView = new QTableView(this);
|
||||||
|
m_tableModel = new QStandardItemModel(0, 2, this);// 2列:选项、值
|
||||||
|
m_tableView->setModel(m_tableModel);
|
||||||
|
|
||||||
|
//设置表头
|
||||||
|
m_tableModel->setHorizontalHeaderLabels({ "选项", "值" });
|
||||||
|
|
||||||
|
//设置表格属性
|
||||||
|
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
m_tableView->setAlternatingRowColors(true);
|
||||||
|
m_tableView->horizontalHeader()->setStretchLastSection(true);
|
||||||
|
m_tableView->setColumnWidth(1, 200);// 选项列宽度
|
||||||
|
|
||||||
|
|
||||||
fancyButtonText* okBtn = new fancyButtonText("保存", 70, 22, "");
|
fancyButtonText* okBtn = new fancyButtonText("保存", 70, 22, "");
|
||||||
fancyButtonText* cancelBtn = new fancyButtonText("取消", 70, 22, "");
|
fancyButtonText* cancelBtn = new fancyButtonText("取消", 70, 22, "");
|
||||||
@@ -54,65 +71,94 @@ public:
|
|||||||
btnLayout->addWidget(cancelBtn);
|
btnLayout->addWidget(cancelBtn);
|
||||||
|
|
||||||
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
||||||
mainLayout->addWidget(m_tableWidget);
|
mainLayout->addWidget(m_tableView);
|
||||||
mainLayout->addLayout(btnLayout);
|
mainLayout->addLayout(btnLayout);
|
||||||
|
|
||||||
// 设置表格样式和属性
|
|
||||||
m_tableWidget->setAlternatingRowColors(true);
|
|
||||||
m_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
||||||
m_tableWidget->horizontalHeader()->setStretchLastSection(true);
|
|
||||||
m_tableWidget->setColumnWidth(0, 200); // 选项列宽度
|
|
||||||
|
|
||||||
m_tableWidget->setStyleSheet(QString(R"(
|
m_tableView->setStyleSheet(QString(R"(
|
||||||
QTableWidget {
|
QTableView {
|
||||||
background-color: rgb(%1);
|
background-color: rgb(%1);
|
||||||
font-family: "Microsoft YaHei";
|
font-family: "Microsoft YaHei";
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
gridline-color: #555555;
|
gridline-color: #555555;
|
||||||
|
alternate-background-color: #3a3a3a;
|
||||||
}
|
}
|
||||||
QHeaderView::section {
|
QHeaderView::section {
|
||||||
background-color: #0078d7;
|
background-color: #0078d7;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
QTableWidget::item:selected {
|
QTableView::item {
|
||||||
|
background-color: #2d2d2d;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
QTableView::item:selected {
|
||||||
background-color: #0078d7;
|
background-color: #0078d7;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
QTableView::item:alternate {
|
||||||
|
background-color: #3a3a3a;
|
||||||
}
|
}
|
||||||
)").arg(sColor_Blue));
|
)").arg(sColor_Blue));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setJsonObject(const nlohmann::json& json) {
|
void setJsonObject(const nlohmann::json& json) {
|
||||||
m_tableWidget->setRowCount(0);
|
m_tableModel->setRowCount(0);
|
||||||
m_originalJson = json; // 保存原始JSON
|
m_originalJson = json; // 保存原始JSON
|
||||||
m_originalTypes.clear(); // 清空原始类型映射
|
m_originalTypes.clear(); // 清空原始类型映射
|
||||||
|
m_editorWidgets.clear();
|
||||||
|
|
||||||
if (!json.is_object()) return;
|
if (!json.is_object()) return;
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
for (auto it = json.begin(); it != json.end(); ++it) {
|
for (auto it = json.begin(); it != json.end(); ++it) {
|
||||||
int row = m_tableWidget->rowCount();
|
m_tableModel->insertRow(row);
|
||||||
m_tableWidget->insertRow(row);
|
|
||||||
|
|
||||||
const std::string& key = it.key();
|
const std::string& key = it.key();
|
||||||
const nlohmann::json& value = it.value();
|
const nlohmann::json& value = it.value();
|
||||||
|
|
||||||
|
//// 设置行号(不可编辑)
|
||||||
|
//QStandardItem* rowItem = new QStandardItem(QString::number(row + 1));
|
||||||
|
//rowItem->setEditable(false);
|
||||||
|
//rowItem->setBackground(QColor(60, 60, 60));
|
||||||
|
//rowItem->setForeground(QColor(255, 255, 255));
|
||||||
|
//m_tableModel->setItem(row, 0, rowItem);
|
||||||
|
|
||||||
// 设置键名(不可编辑)
|
// 设置键名(不可编辑)
|
||||||
QTableWidgetItem* keyItem = new QTableWidgetItem(QString::fromStdString(key));
|
QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key));
|
||||||
keyItem->setFlags(keyItem->flags() & ~Qt::ItemIsEditable);
|
keyItem->setEditable(false);
|
||||||
keyItem->setBackground(QColor(80, 80, 80));
|
keyItem->setBackground(QColor(60, 60, 60));
|
||||||
m_tableWidget->setItem(row, 0, keyItem);
|
keyItem->setForeground(QColor(255, 255, 255));
|
||||||
|
m_tableModel->setItem(row, 0, keyItem);
|
||||||
|
|
||||||
// 确定类型(内部使用,不显示)
|
// 确定类型(内部使用,不显示)
|
||||||
JsonValueType valueType = getJsonValueType(value);
|
JsonValueType valueType = getJsonValueType(value);
|
||||||
m_originalTypes[key] = valueType;
|
m_originalTypes[key] = valueType;
|
||||||
|
|
||||||
// 设置值(可编辑,但需要类型验证)
|
////为所有类型都创建数据项
|
||||||
QString valueText = formatValueForDisplay(value, valueType);
|
//QString valueText = formatValueForDisplay(value, valueType);
|
||||||
QTableWidgetItem* valueItem = new QTableWidgetItem(valueText);
|
//QStandardItem* valueItem = new QStandardItem(valueText);
|
||||||
valueItem->setToolTip(generateTypeHint(valueType));
|
//valueItem->setToolTip(generateTypeHint(valueType));
|
||||||
m_tableWidget->setItem(row, 1, valueItem);
|
//valueItem->setBackground(QColor(60, 60, 60));
|
||||||
|
//valueItem->setForeground(QColor(255, 255, 255));
|
||||||
|
//m_tableModel->setItem(row, 1, valueItem);
|
||||||
|
|
||||||
|
//为特定类型创建专用编辑器控件
|
||||||
|
QWidget* editorWidget = createEditorWidget(value, valueType);
|
||||||
|
if (editorWidget) {
|
||||||
|
m_tableView->setIndexWidget(m_tableModel->index(row, 1), editorWidget);
|
||||||
|
m_editorWidgets[key] = editorWidget;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 默认为文本显示
|
||||||
|
QString valueText= formatValueForDisplay(value, valueType);
|
||||||
|
QStandardItem* valueItem = new QStandardItem(valueText);
|
||||||
|
valueItem->setToolTip(generateTypeHint(valueType));
|
||||||
|
m_tableModel->setItem(row, 1, valueItem);
|
||||||
|
}
|
||||||
|
row++;
|
||||||
}
|
}
|
||||||
m_tableWidget->resizeColumnsToContents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -122,24 +168,20 @@ private slots:
|
|||||||
void onAccept() {
|
void onAccept() {
|
||||||
nlohmann::json result = nlohmann::json::object();
|
nlohmann::json result = nlohmann::json::object();
|
||||||
|
|
||||||
for (int row = 0; row < m_tableWidget->rowCount(); ++row) {
|
for (int row = 0; row < m_tableModel->rowCount(); ++row) {
|
||||||
auto* keyItem = m_tableWidget->item(row, 0);
|
QStandardItem* keyItem = m_tableModel->item(row, 0);
|
||||||
auto* valItem = m_tableWidget->item(row, 1);
|
if (!keyItem) {
|
||||||
|
|
||||||
if (!keyItem || !valItem) {
|
|
||||||
QMessageBox::warning(this, "错误", QString("第 %1 行数据不完整").arg(row + 1));
|
QMessageBox::warning(this, "错误", QString("第 %1 行数据不完整").arg(row + 1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString key = keyItem->text().trimmed();
|
QString key = keyItem->text().trimmed();
|
||||||
QString valStr = valItem->text().trimmed();
|
|
||||||
|
|
||||||
if (key.isEmpty()) {
|
if (key.isEmpty()) {
|
||||||
QMessageBox::warning(this, "错误", QString("第 %1 行 key 为空").arg(row + 1));
|
QMessageBox::warning(this, "错误", QString("第 %1 行 key 为空").arg(row + 1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取原始类型
|
//获取原始类型
|
||||||
std::string keyStd = key.toStdString();
|
std::string keyStd = key.toStdString();
|
||||||
if (m_originalTypes.find(keyStd) == m_originalTypes.end()) {
|
if (m_originalTypes.find(keyStd) == m_originalTypes.end()) {
|
||||||
QMessageBox::warning(this, "错误", QString("第 %1 行找不到原始类型信息").arg(row + 1));
|
QMessageBox::warning(this, "错误", QString("第 %1 行找不到原始类型信息").arg(row + 1));
|
||||||
@@ -148,26 +190,160 @@ private slots:
|
|||||||
|
|
||||||
JsonValueType expectedType = m_originalTypes[keyStd];
|
JsonValueType expectedType = m_originalTypes[keyStd];
|
||||||
|
|
||||||
// 验证并转换值
|
//从编辑器获取值
|
||||||
nlohmann::json convertedValue;
|
nlohmann::json convertedValue;
|
||||||
QString errorMsg;
|
QString errorMsg;
|
||||||
if (!validateAndConvertValue(valStr, expectedType, convertedValue, errorMsg)) {
|
if (!getValueFromEditor(keyStd, expectedType, convertedValue, errorMsg)) {
|
||||||
QMessageBox::critical(this, "类型验证失败",
|
QMessageBox::critical(this, "类型验证失败",QString("第 %1 行值验证失败:\n%2").arg(row + 1).arg(errorMsg));
|
||||||
QString("第 %1 行值验证失败:\n%2").arg(row + 1).arg(errorMsg));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
result[keyStd] = convertedValue;
|
result[keyStd] = convertedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug() << "Result JSON: " << QString::fromStdString(result.dump(4));
|
||||||
|
|
||||||
emit jsonAccepted(result);
|
emit jsonAccepted(result);
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTableWidget* m_tableWidget;
|
QTableView* m_tableView;
|
||||||
|
QStandardItemModel* m_tableModel;
|
||||||
nlohmann::json m_originalJson; // 保存原始JSON以便类型检查
|
nlohmann::json m_originalJson; // 保存原始JSON以便类型检查
|
||||||
std::map<std::string, JsonValueType> m_originalTypes; // 保存每个键的原始类型
|
std::map<std::string, JsonValueType> m_originalTypes;// 保存每个键的原始类型
|
||||||
|
std::map<std::string, QWidget*> m_editorWidgets;// 保存每个键对应的编辑器控件
|
||||||
|
|
||||||
|
// 根据类型创建不同的编辑器控件
|
||||||
|
QWidget* createEditorWidget(const nlohmann::json& value, JsonValueType type) {
|
||||||
|
switch (type) {
|
||||||
|
case JsonValueType::Boolean: {
|
||||||
|
CircularSwitch* switchBtn = new CircularSwitch();
|
||||||
|
switchBtn->setChecked(value.get<bool>());
|
||||||
|
switchBtn->setToolTip(generateTypeHint(type));
|
||||||
|
return switchBtn;
|
||||||
|
}
|
||||||
|
case JsonValueType::Number: {
|
||||||
|
QDoubleSpinBox* spinBox = new QDoubleSpinBox();
|
||||||
|
spinBox->setRange(-1e18, 1e18);
|
||||||
|
spinBox->setDecimals(3);//显示小位数
|
||||||
|
|
||||||
|
if (value.is_number_integer()) {
|
||||||
|
spinBox->setValue(value.get<int64_t>());
|
||||||
|
spinBox->setDecimals(0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spinBox->setValue(value.get<double>());
|
||||||
|
}
|
||||||
|
|
||||||
|
spinBox->setToolTip(generateTypeHint(type));
|
||||||
|
return spinBox;
|
||||||
|
}
|
||||||
|
case JsonValueType::String: {
|
||||||
|
QLineEdit* lineEdit = new QLineEdit();
|
||||||
|
lineEdit->setText(QString::fromStdString(value.get<std::string>()));
|
||||||
|
lineEdit->setToolTip(generateTypeHint(type));
|
||||||
|
return lineEdit;
|
||||||
|
}
|
||||||
|
// 其他类型仍使用文本显示
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getValueFromEditor(const std::string& key, JsonValueType expectedType, nlohmann::json& result, QString& errorMsg) {
|
||||||
|
auto it = m_editorWidgets.find(key);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (it != m_editorWidgets.end()) {
|
||||||
|
// 有专用编辑器控件
|
||||||
|
QWidget* widget = it->second;
|
||||||
|
switch (expectedType) {
|
||||||
|
case JsonValueType::Boolean: {
|
||||||
|
CircularSwitch* switchBtn = qobject_cast<CircularSwitch*>(widget);
|
||||||
|
if (switchBtn) {
|
||||||
|
bool value = switchBtn->isChecked();
|
||||||
|
result = value;
|
||||||
|
// 更新模型数据
|
||||||
|
updateModelData(key, value ? "true" : "false");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
errorMsg = "布尔值控件类型错误";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case JsonValueType::Number: {
|
||||||
|
QDoubleSpinBox* spinBox = qobject_cast<QDoubleSpinBox*>(widget);
|
||||||
|
if (spinBox) {
|
||||||
|
double value = spinBox->value();
|
||||||
|
// 检查是否为整数
|
||||||
|
if (spinBox->decimals() == 0 && value == floor(value)) {
|
||||||
|
result = static_cast<int64_t>(value);
|
||||||
|
updateModelData(key, QString::number(static_cast<int64_t>(value)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = value;
|
||||||
|
updateModelData(key, QString::number(value));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
errorMsg = "数字控件类型错误";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case JsonValueType::String: {
|
||||||
|
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(widget);
|
||||||
|
if (lineEdit) {
|
||||||
|
QString value = lineEdit->text().trimmed();
|
||||||
|
result = value.toStdString();
|
||||||
|
updateModelData(key, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
errorMsg = "字符串控件类型错误";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// 其他类型使用默认文本处理
|
||||||
|
return validateAndConvertValue(getTextFromCell(key), expectedType, result, errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 没有专用编辑器控件,使用默认文本处理
|
||||||
|
return validateAndConvertValue(getTextFromCell(key), expectedType, result, errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
errorMsg = QString("获取值错误: %1").arg(e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新模型中的数据项
|
||||||
|
void updateModelData(const std::string& key, const QString& value) {
|
||||||
|
for (int row = 0; row < m_tableModel->rowCount(); ++row) {
|
||||||
|
QStandardItem* keyItem = m_tableModel->item(row, 0);
|
||||||
|
if (keyItem && keyItem->text().toStdString() == key) {
|
||||||
|
QStandardItem* valueItem = m_tableModel->item(row, 1);
|
||||||
|
if (valueItem) {
|
||||||
|
valueItem->setText(value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从单元格获取文本值(用于没有专用编辑器的类型)
|
||||||
|
QString getTextFromCell(const std::string& key) {
|
||||||
|
//查找键对应的行
|
||||||
|
for (int row = 0; row < m_tableModel->rowCount(); ++row) {
|
||||||
|
QStandardItem* keyItem = m_tableModel->item(row, 0);
|
||||||
|
if (keyItem && keyItem->text().toStdString() == key) {
|
||||||
|
QStandardItem* valueItem = m_tableModel->item(row, 1);
|
||||||
|
if (valueItem) {
|
||||||
|
return valueItem->text();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
// 获取JSON值的类型
|
// 获取JSON值的类型
|
||||||
JsonValueType getJsonValueType(const nlohmann::json& value) {
|
JsonValueType getJsonValueType(const nlohmann::json& value) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <qwidget.h>
|
#include <qwidget.h>
|
||||||
#include <qlayout.h>
|
#include <qlayout.h>
|
||||||
#include <qlabel.h>
|
#include <qlabel.h>
|
||||||
#include <qpushbutton.h>
|
#include <qpushbutton.h>
|
||||||
|
|||||||
@@ -0,0 +1,287 @@
|
|||||||
|
#ifndef CIRCULARSWITCH_H
|
||||||
|
#define CIRCULARSWITCH_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QEasingCurve>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
class CircularSwitch : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int knobPosition READ knobPosition WRITE setKnobPosition NOTIFY knobPositionChanged)
|
||||||
|
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CircularSwitch(QWidget* parent = nullptr)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_checked(false)
|
||||||
|
, m_knobPosition(0)
|
||||||
|
, m_animationDuration(200)
|
||||||
|
, m_onColor(QColor("#4CD964"))
|
||||||
|
, m_offColor(QColor("#E5E5EA"))
|
||||||
|
, m_knobColor(Qt::white)
|
||||||
|
, m_borderColor(QColor("#CCCCCC"))
|
||||||
|
, m_textColor(Qt::white)
|
||||||
|
, m_knobDiameter(0)
|
||||||
|
, m_padding(3)
|
||||||
|
, m_borderWidth(1)
|
||||||
|
, m_showText(true)
|
||||||
|
, m_trueText("true")
|
||||||
|
, m_falseText("false")
|
||||||
|
{
|
||||||
|
m_animation = new QPropertyAnimation(this, "knobPosition", this);
|
||||||
|
m_animation->setEasingCurve(QEasingCurve::OutCubic);
|
||||||
|
m_animation->setDuration(m_animationDuration);
|
||||||
|
|
||||||
|
setFixedSize(70, 34); // 稍微加宽以容纳文字
|
||||||
|
setCursor(Qt::PointingHandCursor);
|
||||||
|
updateKnobGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取和设置开关状态
|
||||||
|
bool isChecked() const { return m_checked; }
|
||||||
|
|
||||||
|
void setChecked(bool checked) {
|
||||||
|
if (m_checked == checked) return;
|
||||||
|
|
||||||
|
m_checked = checked;
|
||||||
|
update();
|
||||||
|
|
||||||
|
// 启动动画
|
||||||
|
m_animation->stop();
|
||||||
|
m_animation->setStartValue(m_knobPosition);
|
||||||
|
m_animation->setEndValue(checked ? width() - m_knobDiameter - m_padding : m_padding);
|
||||||
|
m_animation->start();
|
||||||
|
|
||||||
|
// 延迟发射信号,让动画先执行
|
||||||
|
QTimer::singleShot(10, this, [this, checked]() {
|
||||||
|
emit toggled(checked);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 颜色设置
|
||||||
|
QColor onColor() const { return m_onColor; }
|
||||||
|
void setOnColor(const QColor& color) {
|
||||||
|
m_onColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor offColor() const { return m_offColor; }
|
||||||
|
void setOffColor(const QColor& color) {
|
||||||
|
m_offColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor knobColor() const { return m_knobColor; }
|
||||||
|
void setKnobColor(const QColor& color) {
|
||||||
|
m_knobColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor borderColor() const { return m_borderColor; }
|
||||||
|
void setBorderColor(const QColor& color) {
|
||||||
|
m_borderColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor textColor() const { return m_textColor; }
|
||||||
|
void setTextColor(const QColor& color) {
|
||||||
|
m_textColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor backgroundColor() const {
|
||||||
|
return m_checked ? m_onColor : m_offColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBackgroundColor(const QColor& color) {
|
||||||
|
if (m_checked) {
|
||||||
|
m_onColor = color;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_offColor = color;
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动画设置
|
||||||
|
int animationDuration() const { return m_animationDuration; }
|
||||||
|
void setAnimationDuration(int duration) {
|
||||||
|
m_animationDuration = duration;
|
||||||
|
m_animation->setDuration(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 边框设置
|
||||||
|
int borderWidth() const { return m_borderWidth; }
|
||||||
|
void setBorderWidth(int width) {
|
||||||
|
m_borderWidth = width;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文字设置
|
||||||
|
bool showText() const { return m_showText; }
|
||||||
|
void setShowText(bool show) {
|
||||||
|
m_showText = show;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString trueText() const { return m_trueText; }
|
||||||
|
void setTrueText(const QString& text) {
|
||||||
|
m_trueText = text;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString falseText() const { return m_falseText; }
|
||||||
|
void setFalseText(const QString& text) {
|
||||||
|
m_falseText = text;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent* event) override {
|
||||||
|
Q_UNUSED(event)
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
// 绘制背景
|
||||||
|
QRect backgroundRect = rect().adjusted(m_padding, m_padding, -m_padding, -m_padding);
|
||||||
|
QPainterPath backgroundPath;
|
||||||
|
backgroundPath.addRoundedRect(backgroundRect, backgroundRect.height() / 2, backgroundRect.height() / 2);
|
||||||
|
|
||||||
|
// 绘制边框
|
||||||
|
if (m_borderWidth > 0) {
|
||||||
|
painter.setPen(QPen(m_borderColor, m_borderWidth));
|
||||||
|
painter.setBrush(Qt::NoBrush);
|
||||||
|
painter.drawPath(backgroundPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制填充背景
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.setBrush(m_checked ? m_onColor : m_offColor);
|
||||||
|
painter.drawPath(backgroundPath);
|
||||||
|
|
||||||
|
// 绘制背景文字
|
||||||
|
if (m_showText) {
|
||||||
|
painter.setPen(m_textColor);
|
||||||
|
QFont font = painter.font();
|
||||||
|
font.setPointSize(8);
|
||||||
|
font.setBold(true);
|
||||||
|
painter.setFont(font);
|
||||||
|
|
||||||
|
// 计算文字位置
|
||||||
|
QRect textRect = backgroundRect;
|
||||||
|
|
||||||
|
if (m_checked) {
|
||||||
|
// 打开状态,文字在左侧
|
||||||
|
textRect.setRight(width() / 2);
|
||||||
|
painter.drawText(textRect, Qt::AlignCenter, m_trueText);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 关闭状态,文字在右侧
|
||||||
|
textRect.setLeft(width() / 2);
|
||||||
|
painter.drawText(textRect, Qt::AlignCenter, m_falseText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制滑块
|
||||||
|
int knobY = height() / 2;
|
||||||
|
QRect knobRect(m_knobPosition, knobY - m_knobDiameter / 2,
|
||||||
|
m_knobDiameter, m_knobDiameter);
|
||||||
|
|
||||||
|
QPainterPath knobPath;
|
||||||
|
knobPath.addEllipse(knobRect);
|
||||||
|
|
||||||
|
// 滑块阴影效果
|
||||||
|
QRadialGradient gradient(knobRect.center(), m_knobDiameter / 2);
|
||||||
|
gradient.setColorAt(0, m_knobColor.lighter(110));
|
||||||
|
gradient.setColorAt(1, m_knobColor);
|
||||||
|
|
||||||
|
painter.setPen(QPen(m_borderColor, 1));
|
||||||
|
painter.setBrush(gradient);
|
||||||
|
painter.drawPath(knobPath);
|
||||||
|
|
||||||
|
// 滑块内阴影效果
|
||||||
|
if (m_checked) {
|
||||||
|
QRect innerKnobRect = knobRect.adjusted(3, 3, -3, -3);
|
||||||
|
QPainterPath innerKnobPath;
|
||||||
|
innerKnobPath.addEllipse(innerKnobRect);
|
||||||
|
|
||||||
|
QRadialGradient innerGradient(innerKnobRect.center(), innerKnobRect.width() / 2);
|
||||||
|
innerGradient.setColorAt(0, QColor(255, 255, 255, 100));
|
||||||
|
innerGradient.setColorAt(1, QColor(255, 255, 255, 0));
|
||||||
|
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.setBrush(innerGradient);
|
||||||
|
painter.drawPath(innerKnobPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event) override {
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
event->accept();
|
||||||
|
setChecked(!m_checked);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent* event) override {
|
||||||
|
Q_UNUSED(event)
|
||||||
|
updateKnobGeometry();
|
||||||
|
// 更新滑块位置
|
||||||
|
setKnobPosition(m_checked ? width() - m_knobDiameter - m_padding : m_padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int knobPosition() const { return m_knobPosition; }
|
||||||
|
|
||||||
|
void setKnobPosition(int position) {
|
||||||
|
if (m_knobPosition != position) {
|
||||||
|
m_knobPosition = position;
|
||||||
|
update();
|
||||||
|
emit knobPositionChanged(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateKnobGeometry() {
|
||||||
|
m_knobDiameter = height() - 2 * m_padding - 2 * m_borderWidth;
|
||||||
|
// 确保滑块是圆形
|
||||||
|
if (m_knobDiameter > width() / 2 - m_padding) {
|
||||||
|
m_knobDiameter = width() / 2 - m_padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_checked;
|
||||||
|
int m_knobPosition;
|
||||||
|
int m_animationDuration;
|
||||||
|
|
||||||
|
QColor m_onColor;
|
||||||
|
QColor m_offColor;
|
||||||
|
QColor m_knobColor;
|
||||||
|
QColor m_borderColor;
|
||||||
|
QColor m_textColor;
|
||||||
|
|
||||||
|
QPropertyAnimation* m_animation;
|
||||||
|
|
||||||
|
int m_knobDiameter;
|
||||||
|
int m_padding;
|
||||||
|
int m_borderWidth;
|
||||||
|
|
||||||
|
// 文字相关属性
|
||||||
|
bool m_showText;
|
||||||
|
QString m_trueText;
|
||||||
|
QString m_falseText;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void toggled(bool checked);
|
||||||
|
void knobPositionChanged(int position);
|
||||||
|
void backgroundColorChanged(const QColor& color);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIRCULARSWITCH_H
|
||||||
Reference in New Issue
Block a user