I am building a PyQt5 application by constructing the interfaces with the designer and the exporting to .ui
files. The latter are then loaded by my main class. Here is an example of my source code under the name main.py
:
main.py
import os.path
import PyQt5.QtWidgets as qtw
from PyQt5.uic import loadUi
import sys
class MainUI(qtw.QMainWindow):
def __init__(self, parent=None):
super(MainUI, self).__init__()
self._ui_path = os.path.dirname(os.path.abspath(__file__))
loadUi(os.path.join(self._ui_path, 'main.ui'), self)
if __name__ == "__main__":
# Create the application
app = qtw.QApplication(sys.argv)
# Create and show the application's main window
win = MainUI()
win.show()
sys.exit(app.exec())
main.ui
<?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>320</width>
<height>240</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>110</x>
<y>100</y>
<width>88</width>
<height>27</height>
</rect>
</property>
<property name="text">
<string>ok</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
I generate an executable with pyinstaller
by giving pyinstaller -F -w main.py
.
In the beginning the executable should be in the same folder with the ui. I have changed loadUI
following the answer here.
When I run the executable now it gives me an error message with the following traceback:
Traceback (most recent call last):
File "main.py", line 17, in <module>
win = MainUI()
File "main.py", line 11, in __init__
loadUi(os.path.join(self._ui_path, 'main.ui'), self)
File "PyQt5\uic\__init__.py", line 238, in loadUi
File "PyQt5\uic\Loader\loader.py", line 66, in loadUi
File "PyQt5\uic\uiparser.py", line 1020, in parse
File "xml\etree\ElementTree.py", line 1202, in parse
File "xml\etree\ElementTree.py", line 584, in parse
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\username\\AppData\\Local\\Temp\\_MEI187162\\main.ui'
What has happened is that after running the .exe file, a temporary directory is created having some dll files, and the program tries to locate the .ui file there, without success. What can be done to direct the executable to the place where the .ui file is?
Add this somewhere at the top of your program:
import sys
import os
if getattr(sys, 'frozen', False):
RELATIVE_PATH = os.path.dirname(sys.executable)
else:
RELATIVE_PATH = os.path.dirname(__file__)
Then when you go to call loadUi()
:
self._ui_path = RELATIVE_PATH + "/ui_path" # Update this as needed
loadUi(os.path.join(self._ui_path, 'main.ui'), self)
When programs are compiled and ran elsewhere the directories can get a little weird. See if this works for you, if not, let me know and I can help out further.