修复问题
This commit is contained in:
parent
17655f2dba
commit
104dfe9693
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# Python 编译文件
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.so
|
||||
ui/__pycache__/
|
||||
|
||||
# 打包exe相关
|
||||
dist/
|
||||
build/
|
||||
*.spec
|
||||
|
||||
# 编辑器
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
Binary file not shown.
Binary file not shown.
@ -1,12 +1,16 @@
|
||||
"""标准对话框(QMessageBox / QInputDialog / QFileDialog)与当前主题一致。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QTextOption
|
||||
from PyQt6.QtWidgets import (
|
||||
QFileDialog,
|
||||
QInputDialog,
|
||||
QMessageBox,
|
||||
QWidget,
|
||||
QDialog,
|
||||
QLabel,
|
||||
QSizePolicy,
|
||||
)
|
||||
|
||||
import ui.theme as theme
|
||||
@ -29,7 +33,15 @@ def stylesheet() -> str:
|
||||
QMessageBox QLabel {{
|
||||
color: {fg};
|
||||
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 {{
|
||||
min-width: 64px;
|
||||
@ -127,6 +139,34 @@ def _apply(w: QWidget | None) -> None:
|
||||
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(
|
||||
parent: QWidget | None,
|
||||
title: str,
|
||||
@ -146,8 +186,7 @@ def question(
|
||||
if default_button is not None:
|
||||
msg.setDefaultButton(default_button)
|
||||
_apply(msg)
|
||||
# 防止对话框因为文本长度/默认最小宽度变得过宽
|
||||
msg.setFixedWidth(320)
|
||||
_prepare_qmessagebox(msg)
|
||||
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.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||
_apply(msg)
|
||||
msg.setFixedWidth(320)
|
||||
_prepare_qmessagebox(msg)
|
||||
msg.exec()
|
||||
|
||||
|
||||
@ -169,7 +208,7 @@ def information(parent: QWidget | None, title: str, text: str) -> None:
|
||||
msg.setIcon(QMessageBox.Icon.Information)
|
||||
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||
_apply(msg)
|
||||
msg.setFixedWidth(320)
|
||||
_prepare_qmessagebox(msg)
|
||||
msg.exec()
|
||||
|
||||
|
||||
|
||||
102
ui/dock.py
102
ui/dock.py
@ -7,6 +7,7 @@ import struct
|
||||
import time as _time
|
||||
import datetime
|
||||
import urllib.request
|
||||
import webbrowser
|
||||
import qtawesome as qta
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget,
|
||||
@ -647,6 +648,14 @@ class PanelWindow(QWidget):
|
||||
bottom_layout.setContentsMargins(6, 0, 6, 0)
|
||||
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.setFixedSize(28, 28)
|
||||
self.theme_btn.setToolTip("切换亮/暗主题")
|
||||
@ -671,6 +680,7 @@ class PanelWindow(QWidget):
|
||||
)
|
||||
self.quit_btn.clicked.connect(self._quit_application)
|
||||
|
||||
bottom_layout.addWidget(self.menu_btn)
|
||||
bottom_layout.addStretch()
|
||||
bottom_layout.addWidget(self.theme_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)
|
||||
)
|
||||
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.setIconSize(QSize(14, 14))
|
||||
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.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):
|
||||
# 记录当前折叠状态
|
||||
collapsed_ids = set()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user