This commit is contained in:
2025-05-08 00:39:41 +08:00
parent 1bc836fafa
commit 24acc2a6f1
17 changed files with 1464 additions and 1388 deletions

View File

@@ -79,15 +79,13 @@ class BaseUI(object):
def create_connections(self):
"""连接UI信号和槽"""
pass
def showEvent(self, event):
"""显示事件处理函数"""
# 调用父类的showEvent方法
super(BaseUI, self).showEvent(event)
# 强制设置分割器均等大小
if hasattr(self, 'splitters') and 'main_splitter' in self.splitters:
setup_splitter(self, 'main_splitter', equal_sizes=True)
def update_language(self):
"""
更新所有UI文本到当前语言
"""
if self.main_widget:
update_ui_texts(self.main_widget)
#============================================ UI HELPERS ==========================================
def connect_ui_signals(ui_instance, signal_mapping):
@@ -222,247 +220,78 @@ def load_icon(icon_name):
return QtGui.QIcon()
#============================================ SPLITTER ==========================================
def create_splitter(orientation=QtCore.Qt.Horizontal, parent=None):
def set_splitter_proportions(splitter, proportions):
"""
创建一个QSplitter对象并设置基本属性
设置分割器各部分的比例
Args:
orientation: 分割器方向,默认水平
parent: 父窗口对象
Returns:
QtWidgets.QSplitter: 创建的分割器对象
splitter: 要设置的分割器
proportions: 比例列表,如 [0.3, 0.7] 表示左侧占30%右侧占70%
"""
splitter = QtWidgets.QSplitter(orientation, parent)
splitter.setOpaqueResize(True) # 拖动时实时显示
splitter.setChildrenCollapsible(False) # 防止子部件被完全折叠
splitter.setHandleWidth(2) # 设置分割条宽度
return splitter
def setup_splitter(ui_instance, splitter_name="main_splitter", equal_sizes=True):
"""
设置分割器的属性和大小,确保完全自由调整
Args:
ui_instance: UI实例对象
splitter_name (str): 分割器名称
equal_sizes (bool): 是否设置均等大小
Returns:
bool: 是否成功设置
"""
# 检查分割器是否存在
if not hasattr(ui_instance, 'splitters') or splitter_name not in ui_instance.splitters:
print(f"分割器 '{splitter_name}' 不存在")
return False
# 获取分割器
splitter = ui_instance.splitters[splitter_name]
if not isinstance(splitter, QtWidgets.QSplitter):
print(f"对象 '{splitter_name}' 不是QSplitter类型")
return False
# 设置分割器属性
splitter.setOpaqueResize(True) # 拖动时实时显示
splitter.setChildrenCollapsible(False) # 防止子部件被完全折叠
splitter.setHandleWidth(2) # 设置分割条宽度
# 设置子部件属性
for i in range(splitter.count()):
# 设置伸缩因子 - 所有子部件使用相同的伸缩因子
splitter.setStretchFactor(i, 1)
# 设置子部件属性
widget = splitter.widget(i)
if widget:
# 确保子部件可以自由调整大小
widget.setMinimumWidth(10) # 设置最小宽度而不是0防止完全消失
widget.setMinimumHeight(10) # 设置最小高度而不是0防止完全消失
widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 设置均等大小
if equal_sizes and splitter.count() > 0:
# 计算每个部件应该的大小
total_size = splitter.width() if splitter.orientation() == QtCore.Qt.Horizontal else splitter.height()
size_per_widget = max(1, total_size // splitter.count())
sizes = [size_per_widget] * splitter.count()
# 立即设置大小
splitter.setSizes(sizes)
splitter.update()
# 延迟设置确保生效 - 使用两次定时器调用确保在UI完全加载后生效
QtCore.QTimer.singleShot(50, lambda: splitter.setSizes(sizes))
QtCore.QTimer.singleShot(200, lambda: splitter.setSizes(sizes))
# 连接分割器移动信号
splitter.splitterMoved.connect(lambda: on_splitter_moved(splitter))
return True
def on_splitter_moved(splitter):
"""
处理分割器移动事件
Args:
splitter: 被移动的分割器对象
"""
# 这里可以添加分割器移动后的处理逻辑
# 例如记录分割器位置或者调整其他UI元素
pass
def reset_splitter_sizes(splitter, equal_sizes=True):
"""
重置分割器大小,可选择设置均等大小
Args:
splitter: 分割器对象
equal_sizes: 是否设置均等大小
"""
if not isinstance(splitter, QtWidgets.QSplitter):
return
if equal_sizes and splitter.count() > 0:
# 计算每个部件应该的大小
total_size = splitter.width() if splitter.orientation() == QtCore.Qt.Horizontal else splitter.height()
size_per_widget = max(1, total_size // splitter.count())
sizes = [size_per_widget] * splitter.count()
# 设置大小
splitter.setSizes(sizes)
splitter.update()
# 延迟设置确保生效
QtCore.QTimer.singleShot(50, lambda: splitter.setSizes(sizes))
QtCore.QTimer.singleShot(200, lambda: splitter.setSizes(sizes))
def force_equal_splitter_sizes(ui_instance, splitter_name="main_splitter"):
"""
强制设置分割器大小为均等,并确保完全自由调整
Args:
ui_instance: UI实例对象
splitter_name (str): 分割器名称
"""
# 调用通用的分割器设置函数,设置均等大小
return setup_splitter(ui_instance, splitter_name, equal_sizes=True)
def set_splitter_children_minimum_size(ui_instance, splitter_name="main_splitter", recursive=True):
"""
设置分割器所有子元素的最小宽度和高度为0允许完全自由调整
Args:
ui_instance: UI实例对象
splitter_name (str): 分割器名称
recursive (bool): 是否递归设置所有子元素
"""
# 检查分割器是否存在
if not hasattr(ui_instance, 'splitters') or splitter_name not in ui_instance.splitters:
if not isinstance(splitter, QtWidgets.QSplitter) or not proportions:
return
# 获取分割器
splitter = ui_instance.splitters[splitter_name]
# 设置分割器属性
splitter.setOpaqueResize(True)
splitter.setChildrenCollapsible(False)
# 设置所有子部件的最小尺寸为0
for i in range(splitter.count()):
widget = splitter.widget(i)
if widget and recursive:
# 设置最小尺寸为0
widget.setMinimumWidth(0)
widget.setMinimumHeight(0)
widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 递归设置子控件
_set_widget_children_minimum_size(widget)
def _set_widget_children_minimum_size(widget):
"""
递归设置控件及其所有子控件的最小尺寸为0
Args:
widget: 要设置的控件
"""
# 递归设置所有子部件
for child in widget.findChildren(QtWidgets.QWidget):
# 设置每个子控件的最小宽度为0
child.setMinimumWidth(0)
# 确保比例数量与分割器子部件数量一致
if len(proportions) != splitter.count():
return
# 对于按钮、标签等控件不应该设置最小高度为0否则会导致界面异常
if isinstance(child, (QtWidgets.QPushButton, QtWidgets.QToolButton,
QtWidgets.QLabel, QtWidgets.QLineEdit,
QtWidgets.QComboBox, QtWidgets.QCheckBox,
QtWidgets.QRadioButton)):
# 这些控件应该保持其默认高度只设置水平方向的策略为Expanding
policy = child.sizePolicy()
policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Expanding)
child.setSizePolicy(policy)
else:
# 其他控件可以设置最小高度为0
child.setMinimumHeight(0)
child.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 确保比例总和为1
total = sum(proportions)
if total <= 0:
return
# 特别处理容器控件
if isinstance(child, (QtWidgets.QSplitter, QtWidgets.QScrollArea,
QtWidgets.QGroupBox, QtWidgets.QFrame,
QtWidgets.QTabWidget, QtWidgets.QStackedWidget)) and hasattr(child, 'layout') and child.layout():
child.layout().setContentsMargins(0, 0, 0, 0)
child.layout().setSpacing(0)
# 特别处理列表、树和表格控件
elif isinstance(child, (QtWidgets.QListWidget, QtWidgets.QTreeWidget,
QtWidgets.QTableWidget, QtWidgets.QListView,
QtWidgets.QTreeView, QtWidgets.QTableView)):
child.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
child.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
def set_all_controls_minimum_size(ui_instance):
"""
设置UI实例中所有控件的最小尺寸为0确保分割器可以自由移动
Args:
ui_instance: UI实例对象必须包含controls和buttons字典
"""
# 设置所有按钮的最小尺寸
if hasattr(ui_instance, 'buttons'):
for button in ui_instance.buttons.values():
_set_control_minimum_size(button)
# 设置所有控件的最小尺寸
if hasattr(ui_instance, 'controls'):
for control in ui_instance.controls.values():
_set_control_minimum_size(control)
def _set_control_minimum_size(control):
"""
设置单个控件的最小尺寸为0
Args:
control: 要设置的控件
"""
control.setMinimumWidth(0)
# 对于按钮、标签等控件不应该设置最小高度为0否则会导致界面异常
if isinstance(control, (QtWidgets.QPushButton, QtWidgets.QToolButton,
QtWidgets.QLabel, QtWidgets.QLineEdit,
QtWidgets.QComboBox, QtWidgets.QCheckBox,
QtWidgets.QRadioButton)):
# 这些控件应该保持其默认高度只设置水平方向的策略为Expanding
policy = control.sizePolicy()
policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Expanding)
control.setSizePolicy(policy)
# 计算每个部件应该的大小
if splitter.orientation() == QtCore.Qt.Horizontal:
total_size = splitter.width()
else:
# 其他控件可以设置最小高度为0
control.setMinimumHeight(0)
control.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
total_size = splitter.height()
# 计算实际大小
sizes = [int(total_size * (p / total)) for p in proportions]
# 特别处理列表、树和表格控件
if isinstance(control, (QtWidgets.QListWidget, QtWidgets.QTreeWidget,
QtWidgets.QTableWidget, QtWidgets.QListView,
QtWidgets.QTreeView, QtWidgets.QTableView)):
# 确保这些控件可以自由调整大小
control.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
control.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
# 设置大小
splitter.setSizes(sizes)
def update_ui_texts(widget):
"""
递归更新控件文本以应用当前语言
Args:
widget: 要更新的控件或控件容器
"""
from scripts.ui import localization
# 更新标签文本
if isinstance(widget, QtWidgets.QLabel):
# 尝试查找与当前文本匹配的键
current_text = widget.text()
for lang in ["zh_CN", "en_US"]:
for key, text in localization.LANG.get(lang, {}).items():
if text == current_text:
widget.setText(localization.get_text(key, current_text))
break
# 更新按钮文本和工具提示
elif isinstance(widget, QtWidgets.QPushButton) or isinstance(widget, QtWidgets.QToolButton):
# 更新按钮文本
if widget.text():
current_text = widget.text()
for lang in ["zh_CN", "en_US"]:
for key, text in localization.LANG.get(lang, {}).items():
if text == current_text:
widget.setText(localization.get_text(key, current_text))
break
# 更新工具提示
if widget.toolTip():
current_tip = widget.toolTip()
for lang in ["zh_CN", "en_US"]:
for key, text in localization.LANG.get(lang, {}).items():
if text == current_tip:
widget.setToolTip(localization.get_text(key, current_tip))
break
# 递归处理所有子控件
for child in widget.findChildren(QtWidgets.QWidget):
update_ui_texts(child)