pyside6 自动加载ui文件

发布于 / 文章 / 0条评论 / Tags: python / 6 次浏览

创建自动加载ui的基类 autoload_ui.py

import os
import sys
from pathlib import Path
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QPushButton
from PySide6.QtCore import QFile, QIODevice, QDir, Qt
from PySide6.QtUiTools import QUiLoader
import inspect

class AutoLoadUI(QMainWindow):
    """自动加载UI文件并连接事件的基类 - 修正版"""

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("AutoLoadUI")
        self.setMinimumSize(600, 400)

        # 主容器 - 用于显示加载的UI
        self.container = QWidget()
        self.setCentralWidget(self.container)
        self.container_layout = QVBoxLayout(self.container)

        # 状态标签 - 仅在加载失败时显示
        self.status_label = QLabel("正在加载UI文件...")
        self.status_label.setAlignment(Qt.AlignCenter)
        self.container_layout.addWidget(self.status_label)

        # 加载UI
        self.load_ui()

    def load_ui(self):
        """加载UI文件并自动连接事件 - 修正版本"""
        try:
            # 确定UI文件名 - 使用类名作为文件名
            class_name = self.__class__.__name__
            ui_file_name = f"{class_name}.ui"

            # 查找UI文件
            ui_file_path = self.find_ui_file(ui_file_name)

            if not ui_file_path:
                self.status_label.setText(f"未找到UI文件: {ui_file_name}")
                return

            # 创建UI加载器
            loader = QUiLoader()
            loader.setWorkingDirectory(QDir(os.path.dirname(ui_file_path)))

            # 打开UI文件
            ui_file = QFile(ui_file_path)
            if not ui_file.open(QIODevice.ReadOnly):
                self.status_label.setText(f"无法打开UI文件: {ui_file.errorString()}")
                return

            # 关键修正:正确加载UI文件到容器
            # 1. 先创建一个父容器
            # ui_container = QWidget()

            # 2. 加载UI到该容器
            # ui = loader.load(ui_file, ui_container)
            ui = loader.load(ui_file)
            ui_file.close()

            if not ui:
                self.status_label.setText(f"UI加载失败: {loader.errorString()}")
                return

            # # 3. 将UI容器添加到主布局
            self.container_layout.removeWidget(self.status_label)
            self.status_label.deleteLater()

            # 4. 添加UI容器到主布局
            self.container_layout.addWidget(ui)

            # 5. 设置UI容器为窗口的中央部件
            self.setCentralWidget(ui)
            self.ui = ui

            # 6. 设置窗口标题
            if title := ui.windowTitle():
                self.setWindowTitle(title)

            # 自动连接事件
            self.auto_connect(ui)

        except Exception as e:
            self.status_label.setText(f"加载UI时出错: {str(e)}")
            import traceback
            print(traceback.format_exc())

    def find_ui_file(self, file_name):
        """在常见位置查找UI文件"""
        search_paths = [
            Path(__file__).parent,  # 当前脚本目录
            Path(__file__).parent / "ui",  # ui子目录
            Path.cwd(),  # 当前工作目录
            Path.cwd() / "ui",  # 当前工作目录下的ui子目录
            Path.home(),  # 用户主目录
        ]

        for path in search_paths:
            ui_path = path / file_name
            if ui_path.exists():
                return str(ui_path)
        return None

    def auto_connect(self, ui):
        """自动连接事件信号"""
        for method_name in dir(self):
            if not method_name.startswith('on_'):
                continue

            # 解析方法名格式: on_控件名_信号名
            parts = method_name.split('_')
            if len(parts) < 3:
                continue

            widget_name = '_'.join(parts[1:-1])
            signal_name = parts[-1]

            # 查找控件 - 使用递归查找确保找到嵌套控件
            widget = self.find_widget(ui, widget_name)
            if not widget:
                print(f"控件未找到: {widget_name} (方法: {method_name})")
                continue

            # 获取信号
            signal = getattr(widget, signal_name, None)
            if not signal:
                print(f"信号未找到: {widget_name}.{signal_name}")
                continue

            # 连接信号
            try:
                method = getattr(self, method_name)
                signal.connect(method)
                print(f"已连接: {widget_name}.{signal_name} -> {method_name}")
            except Exception as e:
                print(f"连接失败: {widget_name}.{signal_name} -> {method_name}: {str(e)}")

    def find_widget(self, parent, name):
        """递归查找控件"""
        # 检查当前控件是否匹配
        if parent.objectName() == name:
            return parent

        # 检查子控件
        for child in parent.children():
            if isinstance(child, QWidget):
                # 精确匹配
                if child.objectName() == name:
                    return child

                # 递归查找子控件的子控件
                found = self.find_widget(child, name)
                if found:
                    return found
        return None



创建主窗体main.py


import sys

from PySide6.QtWidgets import QApplication

from autoload_ui import  AutoLoadUI

class Main(AutoLoadUI):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("多标签窗口示例")
        self.setGeometry(300, 300, 800, 600)

    # 自动连接方法命名格式: on_<控件objectName>_<信号名>
    def on_btnSubmit_clicked(self):
        print(self.ui.txtName.text())
        print("提交按钮被点击!")

    def on_txtName_textChanged(self,new_text):

        print(f"文本改变: {new_text}")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Main()
    window.show()
    sys.exit(app.exec())

目录结构如下:

D:.
│  autoload_ui.py
│  main.py
│
└─ui
        main.ui

main.ui(designer 自动生成的,需要自取)

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>823</width>
    <height>617</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="autoFillBackground">
   <bool>false</bool>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="btnSubmit">
    <property name="geometry">
     <rect>
      <x>160</x>
      <y>130</y>
      <width>75</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton</string>
    </property>
   </widget>
   <widget class="QLineEdit" name="txtName">
    <property name="geometry">
     <rect>
      <x>370</x>
      <y>230</y>
      <width>113</width>
      <height>21</height>
     </rect>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>823</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu">
    <property name="title">
     <string>测试</string>
    </property>
   </widget>
   <addaction name="menu"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

    评论区(暂无评论)