如何实现一个.ui文件来用fbs封装PyQt5应用程序



编辑:我的问题可能与以下问题重复:链接。我习惯了在谷歌上搜索,还没有意识到我应该在Stack搜索栏上搜索。

我一直在尝试用Pyinstaller打包PyQt5应用程序(但没有成功(,并决定尝试使用fbs。但我正在努力重写我的主python文件,使其与编译器一起工作。经过两周的努力,我想知道如何最终解决这些问题,我想向更高级的开发人员寻求帮助。

我的项目是一个具有可拖动元素的虚拟板,其组织方式如下:

  • a";main.py";文件
  • a";board.ui";文件
  • 包含图像的文件夹(使用Qt Designer创建UI时使用(

代码的第一个版本(在尝试将其转换为fbs之前(:

# Main Window
class App(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
# ... Several other functions called for initialization 
# (changing language, e.g.)...
def initUI(self):
uic.loadUi("board.ui", self)
self.setWindowIcon(QtGui.QIcon('images/logo.png'))
self.setWindowTitle("My Board")
self.show()
# ... rest of the code ...
# (includes functions for initialization and interaction with UI elements
# (changing their text content, position, e.g.)
# and a subclass of QLabel for Drag and Drop interaction)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())

这段代码在编译时会很好地工作,但无论我尝试什么,我都无法将其打包以供分发——控制台会打开,但UI永远不会出现。因此,我决定尝试fbs(作为奖励,这将迫使我下次开始更多地考虑项目组织(:

新版本的代码(试图根据fbs指南组织项目(:

class AppContext(ApplicationContext):
def run(self):
window = QMainWindow()
version = self.build_settings['version']
window.setWindowTitle("My Board v" + version)
self.initUI()
# ... other functions for initialization...
window.show()
return self.app.exec_()
@cached_property
def initUI(self):
uic.loadUi("board.ui", self)
# I know the next line has to be rewritten, I have tried to comment it out 
# as it is another question - one step at the time
self.setWindowIcon(QtGui.QIcon('images/logo.png')) 
self.setWindowTitle("My Board")
self.show()
# ...other cached properties linked to the previous initialization functions...
# ...rest of the code (same than in the first version)
if __name__ == '__main__':
appctxt = AppContext()
exit_code = appctxt.run()
sys.exit(exit_code)

这段代码甚至不会编译,我收到了这个回溯:

Traceback (most recent call last):
File "C:/Users/...Board/main.py", line 529, in <module>
exit_code = appctxt.run()
File "C:/Users/...Board/main.py", line 25, in run
self.initUI()
File "C:/Users/...Board/main.py", line 45, in initUI
uic.loadUi("board.ui", self)
File "C:Users...Boardmain.pyvenvlibsite-packagesPyQt5uic__init__.py", line 238, in 
loadUi
return DynamicUILoader(package).loadUi(uifile, baseinstance, resource_suffix)
File "C:Users...Boardvenvlibsite-packagesPyQt5uicLoaderloader.py", line 66, in 
loadUi
return self.parse(filename, resource_suffix)
File "C:Users...Boardvenvlibsite-packagesPyQt5uicuiparser.py", line 1037, in parse
actor(elem)
File "C:Users...Boardvenvlibsite-packagesPyQt5uicuiparser.py", line 822, in 
createUserInterface
self.toplevelWidget = self.createToplevelWidget(cname, wname)
File "C:Users...Boardvenvlibsite-packagesPyQt5uicLoaderloader.py", line 59, in 
createToplevelWidget
(type(self.toplevelInst), classname)))
TypeError: ('Wrong base class of toplevel widget', (<class '__main__.AppContext'>, 
'QMainWindow'))

我已经尝试使用那里提出的解决方案(用于UI实现(:https://forum.learnpyqt.com/t/ui-files-with-fbs/61/2

qtCreatorFile = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), "board.ui")  
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)

但我想我不知道如何正确地实施它。关于";顶层小部件的错误基类";我不知道该怎么办。我真的很想知道我接下来的步骤是什么,并了解它。

确切地说,我正在使用Python3.6,并在PyCharm上工作。

我对编程还很陌生,这是我关于堆栈溢出的第一个问题(在过去的几个月里,堆栈溢出非常有用(,所以如果有什么不清楚的地方,请告诉我,我会尽我所能更正确地解释它。

感谢您的真知灼见!

编辑:

所选答案有帮助。由于其他原因,我不得不稍微改变一下结构,不过,这是当前的代码:

class AppContext(ApplicationContext):
def run(self):
self.window()
return self.app.exec_()
@cached_property
def window(self):
return App
class App(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()

# ...Other functions called to initialize
# ...
def initUI(self):
uic.loadUi("src/main/resources/base/ui/board.ui", self)
self.setWindowTitle("Board Routine")
self.show()

我遵循eyllanesc所示的结构,并在UI文件夹中包含了Qt Designer中使用的图片,以直接构建UI。现在,该项目使用fbsrun命令运行良好。冻结后获得的可执行文件返回一个";没有名为main的模块;错误,但这似乎与其他原因有关。

ApplicationContext不是一个小部件,因此loadUi是不合逻辑的,您应该使用窗口。此外,由于您没有指示.ui在哪里,因此您必须使用以下结构:
└── src
├── build
│   └── settings
│       ├── base.json
│       ├── linux.json
│       └── mac.json
└── main
├── icons
│   ├── base
│   │   ├── 16.png
│   │   ├── 24.png
│   │   ├── 32.png
│   │   ├── 48.png
│   │   └── 64.png
│   ├── Icon.ico
│   ├── linux
│   │   ├── 1024.png
│   │   ├── 128.png
│   │   ├── 256.png
│   │   └── 512.png
│   ├── mac
│   │   ├── 1024.png
│   │   ├── 128.png
│   │   ├── 256.png
│   │   └── 512.png
│   └── README.md
├── python
│   └── main.py
└── resources
└── base
└── ui
└── board.ui

main.py

from fbs_runtime.application_context.PyQt5 import ApplicationContext, cached_property
from PyQt5 import QtGui, QtWidgets, uic
import sys

class AppContext(ApplicationContext):
def run(self):
self.initUI()
return self.app.exec_()
def initUI(self):
uic.loadUi(self.get_resource("ui/board.ui"), self.window)
version = self.build_settings['version']
self.window.setWindowTitle("My Board v" + version)
self.window.show()
@cached_property
def window(self):
return QtWidgets.QMainWindow()

if __name__ == '__main__':
appctxt = AppContext()
exit_code = appctxt.run()
sys.exit(exit_code)

最新更新