[feature] 新增配置选择按钮
This commit is contained in:
parent
bdc2bd9ba7
commit
ae09c4f5be
BIN
data/database.db
BIN
data/database.db
Binary file not shown.
Binary file not shown.
@ -121,6 +121,40 @@ class DatabaseManager:
|
||||
|
||||
def save_config(self, name: str, channel_id: int, params: ParamData, filters: List[FilterData]) -> int:
|
||||
with self.get_connection() as conn:
|
||||
# 检查是否存在相同的配置
|
||||
cursor = conn.execute(
|
||||
"SELECT id FROM configs WHERE name = ? AND channel_id = ?",
|
||||
(name, channel_id)
|
||||
)
|
||||
existing_config = cursor.fetchone()
|
||||
|
||||
if existing_config:
|
||||
# 更新现有配置
|
||||
config_id = existing_config[0]
|
||||
|
||||
# 更新参数
|
||||
params.config_id = config_id
|
||||
self.update_params(config_id, params)
|
||||
|
||||
# 删除旧的滤波器
|
||||
conn.execute("DELETE FROM filters WHERE config_id = ?", (config_id,))
|
||||
|
||||
# 插入新的滤波器
|
||||
for filter_data in filters:
|
||||
filter_data.config_id = config_id
|
||||
cursor = conn.execute(
|
||||
"""INSERT INTO filters
|
||||
(config_id, channel_id, filter_type, freq, q, gain, slope, enabled, position)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
(filter_data.config_id, filter_data.channel_id, filter_data.filter_type,
|
||||
filter_data.freq, filter_data.q, filter_data.gain, filter_data.slope,
|
||||
filter_data.enabled, filter_data.position)
|
||||
)
|
||||
filter_data.id = cursor.lastrowid
|
||||
|
||||
return config_id
|
||||
else:
|
||||
# 创建新配置(原有的插入逻辑)
|
||||
cursor = conn.execute(
|
||||
"INSERT INTO configs (name, channel_id) VALUES (?, ?)",
|
||||
(name, channel_id)
|
||||
|
||||
BIN
widget_file_list.zip
Normal file
BIN
widget_file_list.zip
Normal file
Binary file not shown.
303
widget_file_list/QtWidgetsApplication4.cpp
Normal file
303
widget_file_list/QtWidgetsApplication4.cpp
Normal file
@ -0,0 +1,303 @@
|
||||
#include "QtWidgetsApplication4.h"
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMenu>
|
||||
#include <QDate>
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
//#include <QTextCodec>
|
||||
#include <QFileInfo>
|
||||
|
||||
CardData::CardData(const QString& name, const QString& date, const QString& description)
|
||||
: name(name), date(date), description(description), activated(false)
|
||||
{
|
||||
}
|
||||
|
||||
CardItemDelegate::CardItemDelegate(QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void CardItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->save();
|
||||
|
||||
// 获取数据
|
||||
CardData data = index.data(Qt::UserRole).value<CardData>();
|
||||
|
||||
// 绘制卡片背景
|
||||
QRect rect = option.rect;
|
||||
rect.adjust(8, 4, -8, -4);
|
||||
|
||||
// 创建圆角路径
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(rect, 8, 8);
|
||||
|
||||
// 绘制阴影
|
||||
QColor shadowColor(0, 0, 0, 30);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
QRect shadowRect = rect.adjusted(0, i, 0, i);
|
||||
QPainterPath shadowPath;
|
||||
shadowPath.addRoundedRect(shadowRect, 8, 8);
|
||||
painter->fillPath(shadowPath, shadowColor);
|
||||
}
|
||||
|
||||
// 绘制卡片背景
|
||||
QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
|
||||
if (data.activated) {
|
||||
gradient.setColorAt(0, QColor(40, 70, 45));
|
||||
gradient.setColorAt(1, QColor(45, 80, 50));
|
||||
painter->fillPath(path, gradient);
|
||||
painter->setPen(QPen(QColor(60, 180, 90), 2));
|
||||
}
|
||||
else if (option.state & QStyle::State_Selected) {
|
||||
gradient.setColorAt(0, QColor(45, 45, 55));
|
||||
gradient.setColorAt(1, QColor(55, 55, 65));
|
||||
painter->fillPath(path, gradient);
|
||||
painter->setPen(QPen(QColor(70, 130, 180), 2));
|
||||
}
|
||||
else {
|
||||
painter->fillPath(path, QColor(35, 35, 40));
|
||||
painter->setPen(QPen(QColor(60, 60, 65)));
|
||||
}
|
||||
|
||||
painter->drawPath(path);
|
||||
|
||||
// 设置字体
|
||||
QFont nameFont("Microsoft YaHei", 10);
|
||||
nameFont.setBold(true);
|
||||
|
||||
QFont normalFont("Microsoft YaHei", 9);
|
||||
|
||||
// 计算文本区域
|
||||
int padding = 15;
|
||||
QRect nameRect = rect.adjusted(padding, padding, -padding, 0);
|
||||
nameRect.setHeight(25);
|
||||
|
||||
QRect dateRect = nameRect;
|
||||
dateRect.translate(0, nameRect.height());
|
||||
|
||||
QRect descRect = dateRect;
|
||||
descRect.translate(0, dateRect.height());
|
||||
descRect.setHeight(40);
|
||||
|
||||
// 绘制文本
|
||||
painter->setFont(nameFont);
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(nameRect, Qt::AlignLeft | Qt::AlignVCenter, data.name);
|
||||
|
||||
painter->setFont(normalFont);
|
||||
painter->setPen(QColor(180, 180, 180));
|
||||
painter->drawText(dateRect, Qt::AlignLeft | Qt::AlignVCenter, data.date);
|
||||
|
||||
painter->setPen(QColor(160, 160, 160));
|
||||
painter->drawText(descRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
|
||||
data.description);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QSize CardItemDelegate::sizeHint(const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(index);
|
||||
return QSize(380, 130);
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setupUI();
|
||||
setupStyle();
|
||||
|
||||
// 添加示例数据
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
CardData data(
|
||||
QString("项目 %1").arg(i),
|
||||
QDate::currentDate().toString("yyyy-MM-dd"),
|
||||
QString("这是项目 %1 的详细描述信息,可以包含多行文本内容。这是一个较长的描述,用于测试换行效果。").arg(i)
|
||||
);
|
||||
addCardItem(data);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setupUI()
|
||||
{
|
||||
setWindowTitle(tr("卡片列表示例"));
|
||||
resize(400, 600);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(10, 10, 10, 10);
|
||||
layout->setSpacing(0);
|
||||
|
||||
listWidget = new QListWidget(this);
|
||||
listWidget->setSpacing(10);
|
||||
listWidget->setResizeMode(QListWidget::Adjust);
|
||||
listWidget->setUniformItemSizes(false);
|
||||
listWidget->setViewMode(QListWidget::ListMode);
|
||||
listWidget->setVerticalScrollMode(QListWidget::ScrollPerPixel);
|
||||
listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
CardItemDelegate* delegate = new CardItemDelegate(listWidget);
|
||||
listWidget->setItemDelegate(delegate);
|
||||
|
||||
// 连接信号
|
||||
connect(listWidget, &QListWidget::itemDoubleClicked,
|
||||
this, &MainWindow::onItemDoubleClicked);
|
||||
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(listWidget, &QListWidget::customContextMenuRequested,
|
||||
this, &MainWindow::showContextMenu);
|
||||
|
||||
layout->addWidget(listWidget);
|
||||
}
|
||||
|
||||
void MainWindow::setupStyle()
|
||||
{
|
||||
setStyleSheet("QWidget {"
|
||||
" background-color: #1e1e1e;"
|
||||
"}"
|
||||
"QListWidget {"
|
||||
" background-color: #1e1e1e;"
|
||||
" border: none;"
|
||||
" outline: none;"
|
||||
"}"
|
||||
"QListWidget::item {"
|
||||
" background-color: transparent;"
|
||||
" padding: 4px;"
|
||||
"}"
|
||||
"QListWidget::item:selected {"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
"QScrollBar:vertical {"
|
||||
" border: none;"
|
||||
" background: #1e1e1e;"
|
||||
" width: 8px;"
|
||||
" margin: 0px;"
|
||||
"}"
|
||||
"QScrollBar::handle:vertical {"
|
||||
" background: #404040;"
|
||||
" min-height: 20px;"
|
||||
" border-radius: 4px;"
|
||||
"}"
|
||||
"QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {"
|
||||
" height: 0px;"
|
||||
"}"
|
||||
"QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {"
|
||||
" background: none;"
|
||||
"}"
|
||||
"QMenu {"
|
||||
" background-color: #2d2d2d;"
|
||||
" border: 1px solid #404040;"
|
||||
" padding: 5px;"
|
||||
"}"
|
||||
"QMenu::item {"
|
||||
" background-color: transparent;"
|
||||
" padding: 6px 25px;"
|
||||
" border-radius: 4px;"
|
||||
" color: #ffffff;"
|
||||
"}"
|
||||
"QMenu::item:selected {"
|
||||
" background-color: #404040;"
|
||||
"}"
|
||||
"QMenu::separator {"
|
||||
" height: 1px;"
|
||||
" background: #404040;"
|
||||
" margin: 5px 0px;"
|
||||
"}"
|
||||
);
|
||||
}
|
||||
|
||||
void MainWindow::addCardItem(const CardData& data)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(listWidget);
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(data));
|
||||
item->setSizeHint(QSize(380, 120));
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||
}
|
||||
|
||||
void MainWindow::onItemDoubleClicked(QListWidgetItem* item)
|
||||
{
|
||||
// 先将所有项目设置为未激活状态
|
||||
for (int row = 0; row < listWidget->count(); ++row) {
|
||||
QListWidgetItem* currentItem = listWidget->item(row);
|
||||
CardData data = currentItem->data(Qt::UserRole).value<CardData>();
|
||||
data.activated = false;
|
||||
currentItem->setData(Qt::UserRole, QVariant::fromValue(data));
|
||||
}
|
||||
|
||||
// 设置当前点击项目为激活状态
|
||||
CardData data = item->data(Qt::UserRole).value<CardData>();
|
||||
data.activated = true;
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(data));
|
||||
|
||||
listWidget->viewport()->update();
|
||||
}
|
||||
|
||||
void MainWindow::showContextMenu(const QPoint& pos)
|
||||
{
|
||||
QListWidgetItem* item = listWidget->itemAt(pos);
|
||||
if (!item) return;
|
||||
|
||||
QMenu menu(this);
|
||||
|
||||
QAction* sendAction = menu.addAction(tr("发送到设备"));
|
||||
menu.addSeparator();
|
||||
QAction* editAction = menu.addAction(tr("修改"));
|
||||
QAction* deleteAction = menu.addAction(tr("删除"));
|
||||
menu.addSeparator();
|
||||
QAction* showInExplorerAction = menu.addAction(tr("在资源管理器中显示"));
|
||||
|
||||
// 设置图标
|
||||
sendAction->setIcon(QIcon::fromTheme("document-send"));
|
||||
editAction->setIcon(QIcon::fromTheme("document-edit"));
|
||||
deleteAction->setIcon(QIcon::fromTheme("document-delete"));
|
||||
showInExplorerAction->setIcon(QIcon::fromTheme("folder"));
|
||||
|
||||
QAction* action = menu.exec(listWidget->viewport()->mapToGlobal(pos));
|
||||
if (!action) return;
|
||||
|
||||
if (action == sendAction)
|
||||
sendToDevice(item);
|
||||
else if (action == editAction)
|
||||
editItem(item);
|
||||
else if (action == deleteAction)
|
||||
deleteItem(item);
|
||||
else if (action == showInExplorerAction)
|
||||
showInExplorer(item);
|
||||
}
|
||||
|
||||
void MainWindow::sendToDevice(QListWidgetItem* item)
|
||||
{
|
||||
CardData data = item->data(Qt::UserRole).value<CardData>();
|
||||
qDebug() << "发送到设备:" << data.name;
|
||||
}
|
||||
|
||||
void MainWindow::editItem(QListWidgetItem* item)
|
||||
{
|
||||
CardData data = item->data(Qt::UserRole).value<CardData>();
|
||||
qDebug() << "编辑项目:" << data.name;
|
||||
}
|
||||
|
||||
void MainWindow::deleteItem(QListWidgetItem* item)
|
||||
{
|
||||
int row = listWidget->row(item);
|
||||
delete listWidget->takeItem(row);
|
||||
}
|
||||
|
||||
void MainWindow::showInExplorer(QListWidgetItem* item)
|
||||
{
|
||||
QString path = QDir::currentPath();
|
||||
#ifdef Q_OS_WIN
|
||||
QProcess::startDetached("explorer.exe", { "/select,", QDir::toNativeSeparators(path) });
|
||||
#elif defined(Q_OS_MAC)
|
||||
QProcess::startDetached("open", { "-R", path });
|
||||
#else
|
||||
QProcess::startDetached("xdg-open", { QFileInfo(path).path() });
|
||||
#endif
|
||||
}
|
||||
|
||||
59
widget_file_list/QtWidgetsApplication4.h
Normal file
59
widget_file_list/QtWidgetsApplication4.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef CARD_LIST_WIDGET_H
|
||||
#define CARD_LIST_WIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QListWidget>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QPainterPath>
|
||||
|
||||
// 卡片数据结构
|
||||
class CardData {
|
||||
public:
|
||||
// 添加默认构造函数
|
||||
CardData() : activated(false) {}
|
||||
|
||||
// 保留原有构造函数
|
||||
CardData(const QString& name, const QString& date, const QString& description);
|
||||
|
||||
QString name;
|
||||
QString date;
|
||||
QString description;
|
||||
bool activated;
|
||||
};
|
||||
|
||||
// 自定义委托类来绘制卡片样式
|
||||
class CardItemDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CardItemDelegate(QObject* parent = nullptr);
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const override;
|
||||
};
|
||||
|
||||
// 主窗口类
|
||||
class MainWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void onItemDoubleClicked(QListWidgetItem* item);
|
||||
void showContextMenu(const QPoint& pos);
|
||||
void sendToDevice(QListWidgetItem* item);
|
||||
void editItem(QListWidgetItem* item);
|
||||
void deleteItem(QListWidgetItem* item);
|
||||
void showInExplorer(QListWidgetItem* item);
|
||||
|
||||
private:
|
||||
void addCardItem(const CardData& data);
|
||||
void setupUI();
|
||||
void setupStyle();
|
||||
|
||||
QListWidget* listWidget;
|
||||
};
|
||||
|
||||
|
||||
#endif // CARD_LIST_WIDGET_H
|
||||
30
widget_file_list/main.cpp
Normal file
30
widget_file_list/main.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "QtWidgetsApplication4.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMenu>
|
||||
#include <QDate>
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
//#include <QTextCodec>
|
||||
#include <QFileInfo>
|
||||
|
||||
// 注册自定义数据类型
|
||||
Q_DECLARE_METATYPE(CardData)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// 设置编码和字体
|
||||
//QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||
QFont font("Microsoft YaHei", 9);
|
||||
app.setFont(font);
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@ -1,8 +1,9 @@
|
||||
from PySide6.QtWidgets import QWidget, QDialog, QVBoxLayout, QComboBox, QPushButton, QLabel, QTableWidgetItem, QAbstractScrollArea
|
||||
from PySide6.QtWidgets import QWidget, QDialog, QVBoxLayout, QComboBox, QPushButton, QLabel, QTableWidgetItem, QAbstractScrollArea, QHBoxLayout
|
||||
from PySide6.QtCore import Qt
|
||||
from widgets.Ui_widget import Ui_Widget
|
||||
from database.db_manager import DatabaseManager
|
||||
from database.models import FilterData, ParamData
|
||||
from database.models import FilterData, ParamData, ConfigData
|
||||
from typing import List
|
||||
|
||||
class AudioFilterModel:
|
||||
def __init__(self, db_manager: DatabaseManager):
|
||||
@ -253,13 +254,14 @@ class AudioFilterWidget(QWidget):
|
||||
self.model = AudioFilterModel(self.db_manager)
|
||||
self.model.current_channel_id = channel_id # 设置当前通道ID
|
||||
|
||||
# 加载该通道的默认配置
|
||||
# 加载该通道的所有配置
|
||||
configs = self.db_manager.get_all_configs()
|
||||
if configs:
|
||||
# 查找当前通道的配置
|
||||
channel_config = next((config for config in configs if config.channel_id == channel_id), None)
|
||||
if channel_config:
|
||||
self.model.load_config(channel_config.id)
|
||||
# 获取当前通道的所有配置
|
||||
channel_configs = [config for config in configs if config.channel_id == channel_id]
|
||||
if channel_configs:
|
||||
# 可以让用户选择要加载哪个配置
|
||||
self.show_config_selection_dialog(channel_configs)
|
||||
|
||||
self.controller = AudioFilterController(self.model, self)
|
||||
self.update_view()
|
||||
@ -442,3 +444,32 @@ class AudioFilterWidget(QWidget):
|
||||
|
||||
except ValueError:
|
||||
print("输入的值无效,请输入数字")
|
||||
|
||||
def show_config_selection_dialog(self, configs: List[ConfigData]):
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("选择配置")
|
||||
layout = QVBoxLayout()
|
||||
|
||||
combo = QComboBox()
|
||||
for config in configs:
|
||||
combo.addItem(f"{config.name} (创建于: {config.created_at})", config.id)
|
||||
|
||||
layout.addWidget(QLabel("请选择要加载的配置:"))
|
||||
layout.addWidget(combo)
|
||||
|
||||
buttons = QHBoxLayout()
|
||||
ok_button = QPushButton("确定")
|
||||
cancel_button = QPushButton("取消")
|
||||
|
||||
ok_button.clicked.connect(dialog.accept)
|
||||
cancel_button.clicked.connect(dialog.reject)
|
||||
|
||||
buttons.addWidget(ok_button)
|
||||
buttons.addWidget(cancel_button)
|
||||
layout.addLayout(buttons)
|
||||
|
||||
dialog.setLayout(layout)
|
||||
|
||||
if dialog.exec() == QDialog.Accepted:
|
||||
selected_config_id = combo.currentData()
|
||||
self.model.load_config(selected_config_id)
|
||||
|
||||
@ -99,18 +99,22 @@ class ChannelButton(QWidget):
|
||||
self.channel_btn.clicked.connect(self.show_filter_window)
|
||||
|
||||
def show_filter_window(self):
|
||||
if not self.filter_window:
|
||||
# 创建滤波器窗口时传入对应的通道号
|
||||
# 如果窗口已存在且可见,则关闭它
|
||||
if self.filter_window and self.filter_window.isVisible():
|
||||
self.filter_window.raise_()
|
||||
self.filter_window.activateWindow()
|
||||
else:
|
||||
# 如果窗口不存在或已关闭,创建新窗口
|
||||
self.filter_window = AudioFilterWidget(channel_id=self.channel_num)
|
||||
self.filter_window.setWindowTitle(f"Channel {self.group.title()} Filter Settings")
|
||||
|
||||
# Show the window if it's not visible
|
||||
if not self.filter_window.isVisible():
|
||||
# 监听窗口关闭事件,在窗口关闭时重置 filter_window
|
||||
self.filter_window.destroyed.connect(self._on_filter_window_closed)
|
||||
self.filter_window.show()
|
||||
else:
|
||||
# If already visible, bring to front
|
||||
self.filter_window.raise_()
|
||||
self.filter_window.activateWindow()
|
||||
|
||||
def _on_filter_window_closed(self):
|
||||
"""当滤波器窗口关闭时调用"""
|
||||
self.filter_window = None
|
||||
|
||||
class AVAS_WIDGET(QWidget):
|
||||
def __init__(self):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user