修复问题

This commit is contained in:
扫地僧 2026-04-03 23:56:36 +08:00
parent 17655f2dba
commit 104dfe9693
6 changed files with 161 additions and 5 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Python 编译文件
__pycache__/
*.py[cod]
*.so
ui/__pycache__/
# 打包exe相关
dist/
build/
*.spec
# 编辑器
.idea/
.vscode/
*.swp

BIN
logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

View File

@ -1,12 +1,16 @@
"""标准对话框QMessageBox / QInputDialog / QFileDialog与当前主题一致。""" """标准对话框QMessageBox / QInputDialog / QFileDialog与当前主题一致。"""
from __future__ import annotations from __future__ import annotations
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QTextOption
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QFileDialog, QFileDialog,
QInputDialog, QInputDialog,
QMessageBox, QMessageBox,
QWidget, QWidget,
QDialog, QDialog,
QLabel,
QSizePolicy,
) )
import ui.theme as theme import ui.theme as theme
@ -29,7 +33,15 @@ def stylesheet() -> str:
QMessageBox QLabel {{ QMessageBox QLabel {{
color: {fg}; color: {fg};
background: transparent; background: transparent;
min-width: 160px; min-width: 0px;
}}
QMessageBox QLabel#qt_msgbox_label {{
min-width: 200px;
max-width: 560px;
}}
QMessageBox QLabel#qt_msgboxex_icon_label {{
min-width: 28px;
max-width: 28px;
}} }}
QMessageBox QPushButton {{ QMessageBox QPushButton {{
min-width: 64px; min-width: 64px;
@ -127,6 +139,34 @@ def _apply(w: QWidget | None) -> None:
w.setStyleSheet(stylesheet()) w.setStyleSheet(stylesheet())
def _prepare_qmessagebox(msg: QMessageBox) -> None:
"""让提示框按内容换行并自适应宽高(避免固定宽度截断文字)。"""
lbl = msg.findChild(QLabel, "qt_msgbox_label")
if lbl is not None:
lbl.setWordWrap(True)
lbl.setTextFormat(Qt.TextFormat.PlainText)
# 无空格长中文也能在边界处断行,而不是整段挤在一行被裁切
try:
lbl.setWordWrapMode(QTextOption.WrapMode.WrapAnywhere)
except AttributeError:
pass
lbl.setMinimumWidth(200)
lbl.setMaximumWidth(560)
lbl.setSizePolicy(
QSizePolicy.Policy.Preferred,
QSizePolicy.Policy.MinimumExpanding,
)
lay = msg.layout()
if lay is not None:
lay.activate()
msg.setSizePolicy(
QSizePolicy.Policy.Preferred,
QSizePolicy.Policy.Preferred,
)
msg.setMinimumSize(0, 0)
msg.adjustSize()
def question( def question(
parent: QWidget | None, parent: QWidget | None,
title: str, title: str,
@ -146,8 +186,7 @@ def question(
if default_button is not None: if default_button is not None:
msg.setDefaultButton(default_button) msg.setDefaultButton(default_button)
_apply(msg) _apply(msg)
# 防止对话框因为文本长度/默认最小宽度变得过宽 _prepare_qmessagebox(msg)
msg.setFixedWidth(320)
return QMessageBox.StandardButton(msg.exec()) return QMessageBox.StandardButton(msg.exec())
@ -158,7 +197,7 @@ def warning(parent: QWidget | None, title: str, text: str) -> None:
msg.setIcon(QMessageBox.Icon.Warning) msg.setIcon(QMessageBox.Icon.Warning)
msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.setStandardButtons(QMessageBox.StandardButton.Ok)
_apply(msg) _apply(msg)
msg.setFixedWidth(320) _prepare_qmessagebox(msg)
msg.exec() msg.exec()
@ -169,7 +208,7 @@ def information(parent: QWidget | None, title: str, text: str) -> None:
msg.setIcon(QMessageBox.Icon.Information) msg.setIcon(QMessageBox.Icon.Information)
msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.setStandardButtons(QMessageBox.StandardButton.Ok)
_apply(msg) _apply(msg)
msg.setFixedWidth(320) _prepare_qmessagebox(msg)
msg.exec() msg.exec()

View File

@ -7,6 +7,7 @@ import struct
import time as _time import time as _time
import datetime import datetime
import urllib.request import urllib.request
import webbrowser
import qtawesome as qta import qtawesome as qta
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QWidget, QWidget,
@ -647,6 +648,14 @@ class PanelWindow(QWidget):
bottom_layout.setContentsMargins(6, 0, 6, 0) bottom_layout.setContentsMargins(6, 0, 6, 0)
bottom_layout.setSpacing(4) bottom_layout.setSpacing(4)
self.menu_btn = QPushButton()
self.menu_btn.setFixedSize(28, 28)
self.menu_btn.setToolTip("菜单")
self.menu_btn.setStyleSheet(
"border:none; background:transparent; border-radius:4px;"
)
self.menu_btn.clicked.connect(self._show_bottom_menu)
self.theme_btn = QPushButton() self.theme_btn = QPushButton()
self.theme_btn.setFixedSize(28, 28) self.theme_btn.setFixedSize(28, 28)
self.theme_btn.setToolTip("切换亮/暗主题") self.theme_btn.setToolTip("切换亮/暗主题")
@ -671,6 +680,7 @@ class PanelWindow(QWidget):
) )
self.quit_btn.clicked.connect(self._quit_application) self.quit_btn.clicked.connect(self._quit_application)
bottom_layout.addWidget(self.menu_btn)
bottom_layout.addStretch() bottom_layout.addStretch()
bottom_layout.addWidget(self.theme_btn) bottom_layout.addWidget(self.theme_btn)
bottom_layout.addWidget(self.settings_btn) bottom_layout.addWidget(self.settings_btn)
@ -787,6 +797,8 @@ class PanelWindow(QWidget):
qta.icon("fa5s.sun" if is_dark else "fa5s.moon", color=ic) qta.icon("fa5s.sun" if is_dark else "fa5s.moon", color=ic)
) )
self.theme_btn.setIconSize(QSize(14, 14)) self.theme_btn.setIconSize(QSize(14, 14))
self.menu_btn.setIcon(qta.icon("fa5s.bars", color=ic))
self.menu_btn.setIconSize(QSize(14, 14))
self.settings_btn.setIcon(qta.icon("fa5s.cog", color=ic)) self.settings_btn.setIcon(qta.icon("fa5s.cog", color=ic))
self.settings_btn.setIconSize(QSize(14, 14)) self.settings_btn.setIconSize(QSize(14, 14))
self.quit_btn.setIcon(qta.icon("fa5s.sign-out-alt", color=ic)) self.quit_btn.setIcon(qta.icon("fa5s.sign-out-alt", color=ic))
@ -827,6 +839,96 @@ class PanelWindow(QWidget):
self._settings_win = SettingsWindow(self) self._settings_win = SettingsWindow(self)
self._settings_win.show() self._settings_win.show()
def _show_bottom_menu(self):
menu = QMenu(self)
menu.setStyleSheet(self._bottom_menu_stylesheet())
menu.addAction(self._make_doubao_icon(), "豆包会话").triggered.connect(
self._open_doubao_session
)
menu.addAction(
self._make_round_menu_icon("D", "#4d6bfe"), "DeepSeek"
).triggered.connect(
lambda: self._open_url_in_browser(
"https://chat.deepseek.com/", "DeepSeek"
)
)
menu.addAction(
self._make_round_menu_icon("G", "#4285f4"), "Gemini"
).triggered.connect(
lambda: self._open_url_in_browser(
"https://gemini.google.com/", "Gemini"
)
)
# 菜单贴近按钮下方显示,避免漂移到不自然位置
pos = self.menu_btn.mapToGlobal(self.menu_btn.rect().bottomLeft())
menu.exec(pos)
def _bottom_menu_stylesheet(self) -> str:
t = theme.current()
return f"""
QMenu {{
background: {t['menu_bg']};
color: {t['menu_color']};
border: 1px solid {t['menu_border']};
border-radius: 8px;
padding: 4px;
}}
QMenu::item {{
padding: 6px 14px;
border-radius: 5px;
background: transparent;
}}
QMenu::item:selected {{
background: {t['menu_selected']};
}}
QMenu::separator {{
height: 1px;
background: {t['menu_border']};
margin: 4px 8px;
}}
"""
def _make_doubao_icon(self) -> QIcon:
return self._make_round_menu_icon("", "#3b82f6", font_pt=9)
def _make_round_menu_icon(
self, letter: str, bg_hex: str, *, font_pt: int = 9
) -> QIcon:
pm = QPixmap(18, 18)
pm.fill(Qt.GlobalColor.transparent)
p = QPainter(pm)
p.setRenderHint(QPainter.RenderHint.Antialiasing)
p.setBrush(QBrush(QColor(bg_hex)))
p.setPen(Qt.PenStyle.NoPen)
p.drawEllipse(1, 1, 16, 16)
p.setPen(QPen(QColor("white")))
f = p.font()
f.setPointSize(font_pt)
f.setBold(True)
p.setFont(f)
p.drawText(pm.rect(), int(Qt.AlignmentFlag.AlignCenter), letter)
p.end()
return QIcon(pm)
def _open_url_in_browser(self, url: str, title: str) -> None:
try:
ok = webbrowser.open(url)
except Exception as e:
dialog_style.warning(
self, "打开失败", f"无法在默认浏览器中打开{title}{e}"
)
return
if not ok:
dialog_style.warning(
self,
"打开失败",
f"系统未注册可用的默认浏览器,请手动在浏览器中打开{title}\n{url}",
)
def _open_doubao_session(self):
"""用系统默认浏览器打开豆包会话页。"""
self._open_url_in_browser("https://www.doubao.com/chat/", "豆包")
def refresh_groups(self): def refresh_groups(self):
# 记录当前折叠状态 # 记录当前折叠状态
collapsed_ids = set() collapsed_ids = set()