当前位置:   article > 正文

PyQt6 uic 修改ui编译器代码生成 方便实现ui和逻辑代码分离提高效率_pyqt6 pyuic

pyqt6 pyuic

使用PyQt6 uic 在终端生成py代码命令如下:

python -m PyQt6.uic.pyuic uifile.ui -o uifile.py

pycharm的设置如下:

通过PyQt附带的designer设计好UI后,通过uic可以将ui文件转换为py文件, 生成py文件后类似下面的代码:

  1. class Ui_Frame(object):
  2. def setupUi(self, Frame):
  3. # ...

ui类默认从object派生,如果直接使用该文件进行后续开发,需要将object替换为QWidget才能将界面显示出来,类似下面的代码

  1. from PyQt6 import QtCore, QtGui, QtWidgets
  2. from PyQt6.QtWidgets import QWidget
  3. class Ui_Frame(QWidget):
  4. def __init__(self):
  5. super(Ui_Frame, self).__init__()
  6. self.setupUi(self)
  7. def setupUi(self, Frame):
  8. pass
  9. # ...

而且如果后期一旦界面更新,需要重新生成文件的时候内容会被覆盖,不利于界面和代码的分离,每次手动修改也麻烦,于是想到能不能修改编译器代码生成把ui代码类(Ui_Frame)的生成修改一下,改成上图所示的那样,业务逻辑在Ui_Frame的派生类进行处理,这样每次变更ui重新生成代码,对于业务逻辑处理的影响降到最小

通过翻看uic的源码 (site-packages\PyQt6\uic 路径下),可以实现上面的修改

我这边的实现修改了三个文件:

site-packages\PyQt6\uic\pyuic.py

site-packages\PyQt6\uic\compile_ui.py

site-packages\PyQt6\uic\Compiler\compiler.py

修改步骤如下:

1.pyuic.py文件的修改,修改 generate 函数,新增函数 generate_extend,使得可以生成派生类文件

  1. def generate(ui_file, output, indent, execute):
  2. """ Generate the Python code. """
  3. from .compile_ui import compileUi
  4. if output == '-':
  5. import io
  6. pyfile = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8')
  7. needs_close = False
  8. else:
  9. pyfile = open(output, 'wt', encoding='utf8')
  10. needs_close = True
  11. winfo = compileUi(ui_file, pyfile, execute, indent) # 修改1
  12. if needs_close:
  13. pyfile.close()
  14. # 生成派生类
  15. generate_extend(output, winfo) # 新增 2
  16. # by qifa(新增函数)
  17. def generate_extend(output: str, winfo: dict) -> None:
  18. import os
  19. filename = output[:output.rfind('.')]
  20. class_name = 'Ui_' + filename + 'extend'
  21. output_file = filename + 'extend.py'
  22. if os.path.exists(output_file):
  23. return # 如果文件已经存在,不再生成
  24. from PyQt6.uic.Compiler.indenter import createCodeIndenter, getIndenter
  25. output_stream = open(output_file, 'wt', encoding='utf8')
  26. createCodeIndenter(output_stream)
  27. indenter = getIndenter()
  28. indenter.level = 0
  29. # 生成代码
  30. indenter.write("from %s import %s" % (filename, winfo['uiclass']))
  31. indenter.write("")
  32. indenter.write("")
  33. indenter.write("class %s(%s):" %(class_name, winfo['uiclass']))
  34. indenter.indent()
  35. indenter.write("def __init__(self):")
  36. indenter.indent()
  37. indenter.write("super().__init__()")
  38. indenter.write("pass")
  39. output_stream.close()

派生类最终生成的示例代码如下:

  1. from ebookdownloadmain import Ui_Frame
  2. class Ui_ebookdownloadmainextend(Ui_Frame):
  3. def __init__(self):
  4. super().__init__()
  5. pass

2. 修改 compile_ui.py 文件,修改compileUi函数,返回一个字典信息

  1. def compileUi(uifile, pyfile, execute=False, indent=4):
  2. """compileUi(uifile, pyfile, execute=False, indent=4)
  3. Creates a Python module from a Qt Designer .ui file.
  4. uifile is a file name or file-like object containing the .ui file.
  5. pyfile is the file-like object to which the Python code will be written to.
  6. execute is optionally set to generate extra Python code that allows the
  7. code to be run as a standalone application. The default is False.
  8. indent is the optional indentation width using spaces. If it is 0 then a
  9. tab is used. The default is 4.
  10. """
  11. from PyQt6.QtCore import PYQT_VERSION_STR
  12. try:
  13. uifname = uifile.name
  14. except AttributeError:
  15. uifname = uifile
  16. indenter.indentwidth = indent
  17. pyfile.write(_header.format(uifname, PYQT_VERSION_STR))
  18. winfo = compiler.UICompiler().compileUi(uifile, pyfile)
  19. if execute:
  20. indenter.write_code(_display_code % winfo)
  21. return winfo # 修改 返回字典信息

3. 修改Compiler\compiler.py文件,这里才是修改ui文件生成py文件的地方,修改UICompiler类的createToplevelWidget成员函数,代码如下:

  1. class UICompiler(UIParser):
  2. def __init__(self):
  3. UIParser.__init__(self, qtproxies.QtCore, qtproxies.QtGui,
  4. qtproxies.QtWidgets, CompilerCreatorPolicy())
  5. def reset(self):
  6. qtproxies.i18n_strings = []
  7. UIParser.reset(self)
  8. def setContext(self, context):
  9. qtproxies.i18n_context = context
  10. # 修改
  11. def createToplevelWidget(self, classname, widgetname):
  12. indenter = getIndenter()
  13. indenter.level = 0
  14. indenter.write("from PyQt6 import QtCore, QtGui, QtWidgets")
  15. indenter.write("from PyQt6.QtWidgets import QWidget")
  16. indenter.write("")
  17. indenter.write("")
  18. indenter.write("class Ui_%s(QWidget):" % self.uiname)
  19. indenter.indent()
  20. indenter.write("def __init__(self):")
  21. indenter.indent()
  22. indenter.write("super(Ui_%s, self).__init__()" % self.uiname)
  23. indenter.write("self.setupUi(self)")
  24. indenter.dedent()
  25. indenter.write("")
  26. indenter.write("def setupUi(self, %s):" % widgetname)
  27. indenter.indent()
  28. w = self.factory.createQtObject(classname, widgetname,
  29. is_attribute=False, no_instantiation=True)
  30. w.baseclass = classname
  31. w.uiclass = "Ui_%s" % self.uiname
  32. return w
  33. # ...

最终效果示例效果:

  1. from PyQt6 import QtCore, QtGui, QtWidgets
  2. from PyQt6.QtWidgets import QWidget
  3. class Ui_Frame(QWidget):
  4. def __init__(self):
  5. super(Ui_Frame, self).__init__()
  6. self.setupUi(self)
  7. def setupUi(self, Frame):
  8. pass
  9. # ...
  10. from ebookdownloadmain import Ui_Frame
  11. class Ui_ebookdownloadmainextend(Ui_Frame):
  12. def __init__(self):
  13. super().__init__()
  14. pass
  15. if __name__ == '__main__':
  16. app = QApplication(sys.argv)
  17. ui = Ui_ebookdownloadmainextend()
  18. ui.show()
  19. sys.exit(app.exec())

后续只需要在 Ui_ebookdownloadmainextend 类写业务逻辑即可,代码的智能提示也方便,原ui生成的py文件不用管它,界面更新了重新生成即可

修改的几个文件已经打包好了,点这里下载

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/830744
推荐阅读
相关标签
  

闽ICP备14008679号