MJ_McLaren | 2020-05-07 16:49:19 UTC | #1
https://www.pythonguis.com/courses/qt-creator/embed-pyqtgraph-custom-widgets-qt-app/
I'm trying to integrate this technique with fbs but can't seem to make it work. It doesn't see my .ui file. Can you please explain how to set this up in fbs?
mike2750 | 2020-07-23 13:47:22 UTC | #2
@MJ_McLaren Its probably due to the way the file is being called i learned the below techniques from trial and error and loading it this way loads it from a relative path which works in fbs when run from source in pycharm and fbs and when frozen
This would be the fbs way to do that tutorial with fbs in mind and if the mainwindow.ui file is in same path as main.py and also in "src/main/resources/base/mainwindow.ui"
# from fbs_runtime.application_context import is_frozen
# from fbs_runtime.excepthook.sentry import SentryExceptionHandler
import os
import sys
import requests
from PyQt5 import uic, QtWidgets
from pyqtgraph import PlotWidget
import pyqtgraph as pg
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QApplication
from fbs_runtime.application_context.PyQt5 import ApplicationContext, \
cached_property
class AppContext(ApplicationContext):
def run(self):
version = self.build_settings['version']
QApplication.setApplicationName("App Name")
QApplication.setOrganizationName("Some Corp")
QApplication.setOrganizationDomain("example.com")
current_version = version
self.main_window.setWindowTitle("App Name v" + version)
self.main_window.show()
return self.app.exec_()
@cached_property
def main_window(self):
return MainWindow(self)
qtCreatorFile = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), "mainwindow.ui") # Type your file path
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, ctx):
super().__init__()
self.ctx = ctx
self.setupUi(self)
#Put all your custom signals slots and other code here.
import sys
if __name__ == '__main__':
appctxt = AppContext()
exit_code = appctxt.run()
sys.exit(exit_code)
I use this same approach in my fbs app with lots of UI files.
Create GUI Applications with Python & Qt5 by Martin Fitzpatrick — (PyQt5 Edition) The hands-on guide to making apps with Python — Over 10,000 copies sold!
Setting up Application context with fbs and UI was a royal pita to learn but once you have a nice skeleton def save a copy somewhere cause it comes in handy. You will want to then define as much as possible in the UI file vs the python main so its cleaner and just have the logic in the python.
For reference of my setup
Main root is
src/main/python
Ui files
src/main/python/ui
For FBS stuff i also copy same files into this path so bundled properly when compiled
src/main/resources/base/ui
To load say the about.ui file from "src/main/resources/base/ui/about.ui" via relative path "ui/about.ui" with FBS even when frozen
about_ui = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'ui', "about.ui")
uic.loadUi(about_ui, self)
This handy trick also works for images too :slightly_smiling_face:
loads my app logo in about dialog from relative 'images/chevron_logo.png'
self.about_app_logo.setPixmap(
QPixmap(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'images', 'chevron_logo.png')))
====================================================
The best part of joining paths and that code is always works from where code is executed even when frozen and its OS agnostic so works for joining same path on Windows with path separators \ like it does with / on linux and Mac. One of the things i wish i had learned at beginning of my python adventures.
this equals path of current running script
os.path.abspath(os.path.dirname(sys.argv[0]))
This is joining current path + 'ui' folder + 'about.ui' filename
os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'ui', "about.ui")
To experiment can use the below snippet and adjust
import os
import sys
print(os.path.abspath(os.path.dirname(sys.argv[0])))
print(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'ui'))
print(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'ui', "about.ui"))
Output
/home/username/.config/JetBrains/PyCharm2020.1/scratches
/home/username/.config/JetBrains/PyCharm2020.1/scratches/ui
/home/username/.config/JetBrains/PyCharm2020.1/scratches/ui/about.ui
====================================================
To understand the resource files and structure for when its frozen also see. https://build-system.fman.io/manual/#resource-files
Hopefully that helps some and provides some context.
Screenshots for visualization.