0

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?

3
  • The answer from @RichardSmith looks fine if you're really determined to use a one-file bundled executable. I question the value of the one-file proposition because it is guaranteed to (1) be slower to run and (2) consume more disk space. Probably there is a good use case that I'm not aware of, but I usually just distribute my whole dist folder. Commented Mar 8, 2022 at 19:53
  • You are right at least at (1) as far as I can see. With the dist folder shall we load the .ui with a 'simple' loadUi('main.ui', self)? Commented Mar 8, 2022 at 20:23
  • 1
    Yes, loadUi should work fine in your EXE file. I use loadUiType in most of my apps. You just need to make sure that the .ui file is included in your dist folder by putting it in the added_files section of spec file. Commented Mar 8, 2022 at 23:07

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

It worked and I didn't now about the frozen attribute. It seems to be a pyinstaller thing. The answer also suggests to use directory ui_path as a subdirectory at the place where our .exe is, but one can easily configure this part.
1

I turn back from PyQt5 version 5.15.7 to version 5.15.1 by command "pip install PyQt5==5.15.1". My problem resolved.

My Code Goes like this

from PyQt5.QtWidgets import QApplication
from PyQt5 import uic


class UI(QWidget):
    def __init__(self):
        super(UI,self).__init__()

    # loading the ui file with uic module
        uic.loadUi("*xxxxxx*.ui", self)


app = QApplication([])
window = UI()
window.show()
app.exec()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.