feat: 主题切换(light/dark QSS)、QSS资源编译修复、托盘图标主题色

- 新增 main_dark.qss 暗色主题样式表
- 使用 .qrc + add_executable 方式确保 QSS 资源正确编译
- Application::applyTheme 动态切换主题和样式表
- 托盘图标 light 主题黑色、dark 主题白色
- Settings 保存后实时应用主题/字体

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
impressionyang 2026-06-11 19:13:34 +08:00
parent f8173cd0c1
commit ae35404d26
8 changed files with 541 additions and 77 deletions

View File

@ -139,7 +139,9 @@ else()
list(APPEND HEADERS src/core/caps_lock_voice_hotkey.h src/core/wayland_text_injector.h) list(APPEND HEADERS src/core/caps_lock_voice_hotkey.h src/core/wayland_text_injector.h)
add_compile_definitions(PLATFORM_LINUX) add_compile_definitions(PLATFORM_LINUX)
endif() endif()
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}) add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}
src/ui/resources/styles/styles.qrc
)
target_include_directories(${PROJECT_NAME} PRIVATE target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src
@ -197,15 +199,6 @@ if(WIN32)
endif() endif()
endif() endif()
# ============================================================================
#
# ============================================================================
#
qt_add_resources(${PROJECT_NAME} "styles"
PREFIX "/"
FILES
src/ui/resources/styles/main.qss
)
# ============================================================================ # ============================================================================
# #

View File

@ -3,11 +3,21 @@
#include "core/sense_voice_engine.h" #include "core/sense_voice_engine.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <QFile> #include <QFile>
#include <QPalette>
static const char* const kTag = "Application"; #include <QColor>
#include <QStyleFactory>
#include <QStyle>
#include <QFont>
#include <QIcon>
#include <QPixmap>
#include <QPainter>
namespace impress { namespace impress {
static QString s_currentTheme; // 跟踪当前主题
static const char* const kTag = "Application";
Application::Application(int& argc, char** argv) Application::Application(int& argc, char** argv)
: QApplication(argc, argv) : QApplication(argc, argv)
{ {
@ -71,4 +81,88 @@ void Application::loadGlobalModel() {
sttEngine_->loadModelAsync(modelPath, tokensPath, device, numThreads); sttEngine_->loadModelAsync(modelPath, tokensPath, device, numThreads);
} }
void Application::applyTheme(const QString& theme) {
s_currentTheme = theme;
// 1. 先设置风格(必须在 palette 和 stylesheet 之前)
qApp->setStyle(QStyleFactory::create("Fusion"));
// 2. 设置调色板
QPalette palette;
if (theme == "dark") {
palette.setColor(QPalette::Window, QColor(53, 53, 53));
palette.setColor(QPalette::WindowText, Qt::white);
palette.setColor(QPalette::Base, QColor(25, 25, 25));
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
palette.setColor(QPalette::ToolTipBase, Qt::white);
palette.setColor(QPalette::ToolTipText, Qt::white);
palette.setColor(QPalette::Text, Qt::white);
palette.setColor(QPalette::Button, QColor(53, 53, 53));
palette.setColor(QPalette::ButtonText, Qt::white);
palette.setColor(QPalette::BrightText, Qt::cyan);
palette.setColor(QPalette::Link, QColor(42, 130, 218));
palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
palette.setColor(QPalette::HighlightedText, Qt::black);
palette.setColor(QPalette::Disabled, QPalette::Text, QColor(127, 127, 127));
palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127, 127, 127));
palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127));
palette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(80, 80, 80));
palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127, 127, 127));
} else {
palette = qApp->style()->standardPalette();
}
qApp->setPalette(palette);
// 3. 最后设置样式表(覆盖 palette
const QString qssPath = (theme == "dark") ? ":/styles/main_dark.qss" : ":/styles/main.qss";
QFile styleFile(qssPath);
if (styleFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qApp->setStyleSheet(styleFile.readAll());
styleFile.close();
} else {
LOG_ERROR("Theme", QString("无法加载样式表: %1").arg(qssPath));
}
LOG_INFO("Theme", QString("主题已切换: %1").arg(theme));
}
void Application::applyFontSize(int size) {
QFont font = qApp->font();
font.setPointSize(size);
qApp->setFont(font);
LOG_INFO("Theme", QString("字体大小已设置: %1").arg(size));
}
QIcon Application::createTrayIcon(bool active) {
const QColor color = (s_currentTheme == "dark") ? Qt::white : Qt::black;
const int size = 16;
QPixmap pixmap(size, size);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(color);
if (active) {
// 播放图标(三角形)
const int margin = 3;
QPolygon triangle;
triangle << QPoint(margin, margin)
<< QPoint(margin, size - margin)
<< QPoint(size - margin, size / 2);
painter.drawPolygon(triangle);
} else {
// 停止图标(正方形)
const int margin = 3;
painter.drawRect(margin, margin, size - 2 * margin, size - 2 * margin);
}
return QIcon(pixmap);
}
bool Application::isDarkTheme() {
return s_currentTheme == "dark";
}
} // namespace impress } // namespace impress

View File

@ -35,6 +35,18 @@ public:
/** @brief 加载全局模型(在配置加载后手动调用) */ /** @brief 加载全局模型(在配置加载后手动调用) */
void loadGlobalModel(); void loadGlobalModel();
/** @brief 应用主题light/dark可在运行时调用 */
static void applyTheme(const QString& theme);
/** @brief 应用全局字体大小 */
static void applyFontSize(int size);
/** @brief 生成托盘图标light=黑色dark=白色) */
static QIcon createTrayIcon(bool active);
/** @brief 当前主题是否为 dark */
static bool isDarkTheme();
signals: signals:
/** @brief 模型加载中(带路径) */ /** @brief 模型加载中(带路径) */
void modelLoading(const QString& modelPath); void modelLoading(const QString& modelPath);

View File

@ -7,6 +7,7 @@
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QApplication>
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -66,6 +67,13 @@ int main(int argc, char* argv[])
configManager->set("stt.model_path", modelPath); configManager->set("stt.model_path", modelPath);
} }
// 应用主题和字体
QString theme = configManager->get("ui.theme").toString();
int fontSize = configManager->get("ui.font_size").toInt();
impress::Application::applyTheme(theme);
if (fontSize > 0) impress::Application::applyFontSize(fontSize);
LOG_INFO("Main", QString("主题: %1, 字体: %2").arg(theme).arg(fontSize));
// 配置加载完成后,启动全局模型加载 // 配置加载完成后,启动全局模型加载
app.loadGlobalModel(); app.loadGlobalModel();

View File

@ -5,6 +5,7 @@
#include "core/voice_input_service.h" #include "core/voice_input_service.h"
#include "core/sense_voice_engine.h" #include "core/sense_voice_engine.h"
#include "app/config_manager.h" #include "app/config_manager.h"
#include "app/application.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <QMenuBar> #include <QMenuBar>
@ -37,7 +38,6 @@ MainWindow::MainWindow(ConfigManager* configManager,
setupMenuBar(); setupMenuBar();
setupStatusBar(sttEngine); setupStatusBar(sttEngine);
setupTrayIcon(); setupTrayIcon();
loadStyleSheet();
// 初始化语音输入服务(共享全局引擎) // 初始化语音输入服务(共享全局引擎)
voiceInputService_ = new VoiceInputService(configManager_, sttEngine, this); voiceInputService_ = new VoiceInputService(configManager_, sttEngine, this);
@ -126,9 +126,9 @@ void MainWindow::setupTrayIcon() {
trayIcon_ = new QSystemTrayIcon(this); trayIcon_ = new QSystemTrayIcon(this);
trayIcon_->setContextMenu(trayMenu_); trayIcon_->setContextMenu(trayMenu_);
// 默认状态:停止图标SP_MediaStop // 默认状态:根据主题颜色生成图标
idleIcon_ = style()->standardIcon(QStyle::SP_MediaStop); idleIcon_ = Application::createTrayIcon(false);
activeIcon_ = style()->standardIcon(QStyle::SP_MediaPlay); activeIcon_ = Application::createTrayIcon(true);
trayIcon_->setIcon(idleIcon_); trayIcon_->setIcon(idleIcon_);
trayIcon_->setToolTip("Impress Voice Input - 语音输入就绪"); trayIcon_->setToolTip("Impress Voice Input - 语音输入就绪");
@ -236,6 +236,17 @@ void MainWindow::updateModelStatus() {
void MainWindow::onVoiceInputConfigChanged() { void MainWindow::onVoiceInputConfigChanged() {
if (!voiceInputService_) return; if (!voiceInputService_) return;
// 动态应用主题和字体
QString theme = configManager_->get("ui.theme").toString();
int fontSize = configManager_->get("ui.font_size").toInt();
Application::applyTheme(theme);
if (fontSize > 0) Application::applyFontSize(fontSize);
// 刷新托盘图标颜色
idleIcon_ = Application::createTrayIcon(false);
activeIcon_ = Application::createTrayIcon(true);
updateTrayIcon("语音输入就绪");
// 更新模型状态显示 // 更新模型状态显示
updateModelStatus(); updateModelStatus();

View File

@ -1,143 +1,157 @@
/* Impress Voice Input - 全局样式表 */ /* Impress Voice Input - 亮色主题样式表 */
/* ========== 全局 ========== */ /* ========== 全局 ========== */
* { * {
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif; font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
} }
QMainWindow, QWidget { QWidget {
background-color: #ffffff;
color: #1a1a1a;
}
/* 容器控件必须显式设置背景 */
QFrame {
background-color: #ffffff;
}
QScrollArea, QScrollArea > QWidget {
background-color: #ffffff; background-color: #ffffff;
color: #2c3e50;
} }
/* ========== QTabWidget ========== */ /* ========== QTabWidget ========== */
QTabWidget::pane { QTabWidget::pane {
border: 1px solid #dcdfe6; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 6px;
background: #fafafa; background: #ffffff;
} }
QTabBar::tab { QTabBar::tab {
background: #f0f2f5; background: #f5f5f5;
border: 1px solid #dcdfe6; border: 1px solid #e0e0e0;
border-bottom: none; border-bottom: none;
border-top-left-radius: 4px; border-top-left-radius: 6px;
border-top-right-radius: 4px; border-top-right-radius: 6px;
padding: 10px 24px; padding: 10px 24px;
margin-right: 2px; margin-right: 2px;
font-size: 14px; font-size: 14px;
color: #606266; color: #666666;
} }
QTabBar::tab:selected { QTabBar::tab:selected {
background: #ffffff; background: #ffffff;
border-bottom: 2px solid #409eff; border-bottom: 2px solid #1976d2;
color: #409eff; color: #1976d2;
font-weight: bold; font-weight: bold;
} }
QTabBar::tab:hover { QTabBar::tab:hover {
color: #409eff; color: #1976d2;
background: #e8eaf6;
} }
/* ========== QPushButton ========== */ /* ========== QPushButton ========== */
QPushButton { QPushButton {
background-color: #ffffff; background-color: #ffffff;
border: 1px solid #dcdfe6; border: 1px solid #d0d0d0;
border-radius: 4px; border-radius: 4px;
padding: 6px 16px; padding: 6px 16px;
color: #606266; color: #333333;
font-size: 13px; font-size: 13px;
} }
QPushButton:hover { QPushButton:hover {
background-color: #ecf5ff; background-color: #e3f2fd;
border-color: #b3d8ff; border-color: #1976d2;
color: #409eff; color: #1976d2;
} }
QPushButton:pressed { QPushButton:pressed {
background-color: #e6f0ff; background-color: #bbdefb;
} }
/* 主要操作按钮 */ /* 主要操作按钮 */
QPushButton[objectName="saveBtn"], QPushButton[objectName="saveBtn"],
QPushButton[text="保存配置"] { QPushButton[text="保存配置"] {
background-color: #409eff; background-color: #1976d2;
color: #ffffff; color: #ffffff;
border: 1px solid #409eff; border: 1px solid #1976d2;
} }
QPushButton[objectName="saveBtn"]:hover, QPushButton[objectName="saveBtn"]:hover,
QPushButton[text="保存配置"]:hover { QPushButton[text="保存配置"]:hover {
background-color: #66b1ff; background-color: #1565c0;
} }
/* 危险操作按钮 */ /* 危险操作按钮 */
QPushButton[text="停止"], QPushButton[text="停止"],
QPushButton[text="停止录音"] { QPushButton[text="停止录音"] {
background-color: #f56c6c; background-color: #e53935;
color: #ffffff; color: #ffffff;
border: 1px solid #f56c6c; border: 1px solid #e53935;
} }
QPushButton[text="停止"]:hover, QPushButton[text="停止"]:hover,
QPushButton[text="停止录音"]:hover { QPushButton[text="停止录音"]:hover {
background-color: #f78989; background-color: #c62828;
} }
/* ========== QGroupBox ========== */ /* ========== QGroupBox ========== */
QGroupBox { QGroupBox {
font-weight: bold; font-weight: bold;
border: 1px solid #dcdfe6; border: 1px solid #e0e0e0;
border-radius: 6px; border-radius: 6px;
margin-top: 12px; margin-top: 12px;
padding-top: 16px; padding-top: 16px;
color: #1a1a1a;
} }
QGroupBox::title { QGroupBox::title {
subcontrol-origin: margin; subcontrol-origin: margin;
subcontrol-position: top left; subcontrol-position: top left;
padding: 0 8px; padding: 0 8px;
color: #303133; color: #1a1a1a;
} }
/* ========== QLabel ========== */ /* ========== QLabel ========== */
QLabel { QLabel {
color: #606266; color: #333333;
background: none;
} }
/* ========== QLineEdit ========== */ /* ========== QLineEdit ========== */
QLineEdit { QLineEdit {
border: 1px solid #dcdfe6; border: 1px solid #d0d0d0;
border-radius: 4px; border-radius: 4px;
padding: 5px 10px; padding: 5px 10px;
background: #ffffff; background: #ffffff;
color: #1a1a1a;
} }
QLineEdit:focus { QLineEdit:focus {
border-color: #409eff; border-color: #1976d2;
} }
QLineEdit[readOnly="true"] { QLineEdit[readOnly="true"] {
background-color: #f5f7fa; background-color: #f5f5f5;
} }
/* ========== QComboBox ========== */ /* ========== QComboBox ========== */
QComboBox { QComboBox {
border: 1px solid #dcdfe6; border: 1px solid #d0d0d0;
border-radius: 4px; border-radius: 4px;
padding: 5px 10px; padding: 5px 10px;
background: #ffffff; background: #ffffff;
color: #1a1a1a;
min-width: 120px; min-width: 120px;
} }
QComboBox:hover { QComboBox:hover {
border-color: #c0c4cc; border-color: #909090;
} }
QComboBox:focus { QComboBox:focus {
border-color: #409eff; border-color: #1976d2;
} }
QComboBox::drop-down { QComboBox::drop-down {
@ -145,52 +159,62 @@ QComboBox::drop-down {
width: 24px; width: 24px;
} }
QComboBox QAbstractItemView {
background-color: #ffffff;
color: #1a1a1a;
selection-background-color: #e3f2fd;
}
/* ========== QSpinBox / QDoubleSpinBox ========== */ /* ========== QSpinBox / QDoubleSpinBox ========== */
QSpinBox, QDoubleSpinBox { QSpinBox, QDoubleSpinBox {
border: 1px solid #dcdfe6; border: 1px solid #d0d0d0;
border-radius: 4px; border-radius: 4px;
padding: 4px 8px; padding: 4px 8px;
background: #ffffff; background: #ffffff;
color: #1a1a1a;
} }
QSpinBox:focus, QDoubleSpinBox:focus { QSpinBox:focus, QDoubleSpinBox:focus {
border-color: #409eff; border-color: #1976d2;
} }
/* ========== QProgressBar ========== */ /* ========== QProgressBar ========== */
QProgressBar { QProgressBar {
border: 1px solid #dcdfe6; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
text-align: center; text-align: center;
height: 20px; height: 20px;
background: #f5f7fa; background: #f5f5f5;
color: #333333;
} }
QProgressBar::chunk { QProgressBar::chunk {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0, background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop:0 #409eff, stop:1 #66b1ff); stop:0 #1976d2, stop:1 #42a5f5);
border-radius: 3px; border-radius: 3px;
} }
/* ========== QTextEdit ========== */ /* ========== QTextEdit ========== */
QTextEdit { QTextEdit {
border: 1px solid #dcdfe6; border: 1px solid #d0d0d0;
border-radius: 4px; border-radius: 4px;
padding: 8px; padding: 8px;
background: #ffffff; background: #ffffff;
selection-background-color: #ecf5ff; color: #1a1a1a;
selection-background-color: #e3f2fd;
} }
QTextEdit:focus { QTextEdit:focus {
border-color: #409eff; border-color: #1976d2;
} }
/* ========== QListWidget ========== */ /* ========== QListWidget ========== */
QListWidget { QListWidget {
border: 1px solid #dcdfe6; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
background: #ffffff; background: #ffffff;
padding: 4px; padding: 4px;
color: #1a1a1a;
} }
QListWidget::item { QListWidget::item {
@ -199,58 +223,62 @@ QListWidget::item {
} }
QListWidget::item:selected { QListWidget::item:selected {
background-color: #ecf5ff; background-color: #e3f2fd;
color: #409eff; color: #1976d2;
} }
QListWidget::item:hover { QListWidget::item:hover {
background-color: #f5f7fa; background-color: #f5f5f5;
} }
/* ========== QCheckBox ========== */ /* ========== QCheckBox ========== */
QCheckBox { QCheckBox {
spacing: 8px; spacing: 8px;
color: #333333;
} }
QCheckBox::indicator { QCheckBox::indicator {
width: 16px; width: 16px;
height: 16px; height: 16px;
border: 1px solid #dcdfe6; border: 1px solid #d0d0d0;
border-radius: 3px; border-radius: 3px;
background-color: #ffffff;
} }
QCheckBox::indicator:checked { QCheckBox::indicator:checked {
background-color: #409eff; background-color: #1976d2;
border-color: #409eff; border-color: #1976d2;
} }
/* ========== QMenu / QMenuBar ========== */ /* ========== QMenu / QMenuBar ========== */
QMenuBar { QMenuBar {
background-color: #ffffff; background-color: #ffffff;
border-bottom: 1px solid #dcdfe6; border-bottom: 1px solid #e0e0e0;
padding: 2px; padding: 2px;
color: #333333;
} }
QMenuBar::item:selected { QMenuBar::item:selected {
background-color: #ecf5ff; background-color: #e3f2fd;
color: #409eff; color: #1976d2;
} }
QMenu { QMenu {
background-color: #ffffff; background-color: #ffffff;
border: 1px solid #dcdfe6; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 4px; padding: 4px;
color: #333333;
} }
QMenu::item:selected { QMenu::item:selected {
background-color: #ecf5ff; background-color: #e3f2fd;
color: #409eff; color: #1976d2;
} }
QMenu::separator { QMenu::separator {
height: 1px; height: 1px;
background-color: #ebeef5; background-color: #e0e0e0;
margin: 4px 0; margin: 4px 0;
} }
@ -260,25 +288,25 @@ QMessageBox {
} }
QMessageBox QLabel { QMessageBox QLabel {
color: #303133; color: #1a1a1a;
} }
/* ========== 滚动条 ========== */ /* ========== 滚动条 ========== */
QScrollBar:vertical { QScrollBar:vertical {
border: none; border: none;
background: #f5f7fa; background: #f5f5f5;
width: 8px; width: 8px;
border-radius: 4px; border-radius: 4px;
} }
QScrollBar::handle:vertical { QScrollBar::handle:vertical {
background: #c0c4cc; background: #bdbdbd;
border-radius: 4px; border-radius: 4px;
min-height: 30px; min-height: 30px;
} }
QScrollBar::handle:vertical:hover { QScrollBar::handle:vertical:hover {
background: #909399; background: #9e9e9e;
} }
QScrollBar::add-line:vertical, QScrollBar::add-line:vertical,

View File

@ -0,0 +1,312 @@
/* Impress Voice Input - 暗色主题样式表 */
/* ========== 全局 ========== */
* {
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
}
QWidget {
background-color: #353535;
color: #ffffff;
}
QFrame {
background-color: #353535;
}
QScrollArea, QScrollArea > QWidget {
background-color: #2a2a2a;
}
/* ========== QTabWidget ========== */
QTabWidget::pane {
border: 1px solid #555555;
border-radius: 4px;
background: #2a2a2a;
}
QTabBar::tab {
background: #3a3a3a;
border: 1px solid #555555;
border-bottom: none;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
padding: 10px 24px;
margin-right: 2px;
font-size: 14px;
color: #cccccc;
}
QTabBar::tab:selected {
background: #2a2a2a;
border-bottom: 2px solid #4286f4;
color: #4286f4;
font-weight: bold;
}
QTabBar::tab:hover {
color: #4286f4;
}
/* ========== QPushButton ========== */
QPushButton {
background-color: #353535;
border: 1px solid #555555;
border-radius: 4px;
padding: 6px 16px;
color: #cccccc;
font-size: 13px;
}
QPushButton:hover {
background-color: #4286f4;
border-color: #4286f4;
color: #ffffff;
}
QPushButton:pressed {
background-color: #3a6fd8;
}
/* 主要操作按钮 */
QPushButton[objectName="saveBtn"],
QPushButton[text="保存配置"] {
background-color: #4286f4;
color: #ffffff;
border: 1px solid #4286f4;
}
QPushButton[objectName="saveBtn"]:hover,
QPushButton[text="保存配置"]:hover {
background-color: #5a9aff;
}
/* 危险操作按钮 */
QPushButton[text="停止"],
QPushButton[text="停止录音"] {
background-color: #e74c3c;
color: #ffffff;
border: 1px solid #e74c3c;
}
QPushButton[text="停止"]:hover,
QPushButton[text="停止录音"]:hover {
background-color: #f05e50;
}
/* ========== QGroupBox ========== */
QGroupBox {
font-weight: bold;
border: 1px solid #555555;
border-radius: 6px;
margin-top: 12px;
padding-top: 16px;
color: #ffffff;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top left;
padding: 0 8px;
color: #ffffff;
}
/* ========== QLabel ========== */
QLabel {
color: #cccccc;
}
/* ========== QLineEdit ========== */
QLineEdit {
border: 1px solid #555555;
border-radius: 4px;
padding: 5px 10px;
background: #1a1a1a;
color: #ffffff;
}
QLineEdit:focus {
border-color: #4286f4;
}
QLineEdit[readOnly="true"] {
background-color: #2a2a2a;
}
/* ========== QComboBox ========== */
QComboBox {
border: 1px solid #555555;
border-radius: 4px;
padding: 5px 10px;
background: #1a1a1a;
color: #ffffff;
min-width: 120px;
}
QComboBox:hover {
border-color: #888888;
}
QComboBox:focus {
border-color: #4286f4;
}
QComboBox::drop-down {
border: none;
width: 24px;
}
QComboBox QAbstractItemView {
background-color: #1a1a1a;
color: #ffffff;
selection-background-color: #4286f4;
}
/* ========== QSpinBox / QDoubleSpinBox ========== */
QSpinBox, QDoubleSpinBox {
border: 1px solid #555555;
border-radius: 4px;
padding: 4px 8px;
background: #1a1a1a;
color: #ffffff;
}
QSpinBox:focus, QDoubleSpinBox:focus {
border-color: #4286f4;
}
/* ========== QProgressBar ========== */
QProgressBar {
border: 1px solid #555555;
border-radius: 4px;
text-align: center;
height: 20px;
background: #2a2a2a;
color: #ffffff;
}
QProgressBar::chunk {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop:0 #4286f4, stop:1 #5a9aff);
border-radius: 3px;
}
/* ========== QTextEdit ========== */
QTextEdit {
border: 1px solid #555555;
border-radius: 4px;
padding: 8px;
background: #1a1a1a;
color: #ffffff;
selection-background-color: #4286f4;
}
QTextEdit:focus {
border-color: #4286f4;
}
/* ========== QListWidget ========== */
QListWidget {
border: 1px solid #555555;
border-radius: 4px;
background: #1a1a1a;
padding: 4px;
color: #ffffff;
}
QListWidget::item {
padding: 8px;
border-radius: 4px;
}
QListWidget::item:selected {
background-color: #4286f4;
color: #ffffff;
}
QListWidget::item:hover {
background-color: #3a3a3a;
}
/* ========== QCheckBox ========== */
QCheckBox {
spacing: 8px;
color: #cccccc;
}
QCheckBox::indicator {
width: 16px;
height: 16px;
border: 1px solid #555555;
border-radius: 3px;
background-color: #1a1a1a;
}
QCheckBox::indicator:checked {
background-color: #4286f4;
border-color: #4286f4;
}
/* ========== QMenu / QMenuBar ========== */
QMenuBar {
background-color: #353535;
border-bottom: 1px solid #555555;
padding: 2px;
color: #cccccc;
}
QMenuBar::item:selected {
background-color: #4286f4;
color: #ffffff;
}
QMenu {
background-color: #353535;
border: 1px solid #555555;
border-radius: 4px;
padding: 4px;
color: #cccccc;
}
QMenu::item:selected {
background-color: #4286f4;
color: #ffffff;
}
QMenu::separator {
height: 1px;
background-color: #555555;
margin: 4px 0;
}
/* ========== QMessageBox ========== */
QMessageBox {
background-color: #353535;
}
QMessageBox QLabel {
color: #ffffff;
}
/* ========== 滚动条 ========== */
QScrollBar:vertical {
border: none;
background: #2a2a2a;
width: 8px;
border-radius: 4px;
}
QScrollBar::handle:vertical {
background: #666666;
border-radius: 4px;
min-height: 30px;
}
QScrollBar::handle:vertical:hover {
background: #888888;
}
QScrollBar::add-line:vertical,
QScrollBar::sub-line:vertical {
height: 0;
}

View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/styles">
<file>main.qss</file>
<file>main_dark.qss</file>
</qresource>
</RCC>