Почему PyInstaller не распознаёт файл .uic?

Как я могу конвертировать свое GUI приложение, написанное на PyQt6, в исполняемый файл (exe)? Дизайн я создавал в QTDesigner и сохранил в формате ui файла. Для конвертации использовал pyinstaller с запросом: `pyinstaller --onedir --noconsole --icon=app/ui/pic/favicon.ico main.py`. Однако после создания exe файла при его запуске возникает ошибка о том, что не удается найти ui файл в директории, хотя он там присутствует. Я уже добавил ui файл через параметр datas в main.spec, но это не дало результата. Также попробовал загрузить uic с помощью кода: 

```python
template = """содержимое uic"""
uic.LoadUi(io.StringIO(template))
```

При этом приложение запускается, но сложные элементы дизайна, такие как qpixmap, не загружаются. Можете подсказать, как решить эту проблему?
  • 1 февраля 2025 г. 20:54
Ответы на вопрос 2
Ваша проблема связана с тем, как PyInstaller обрабатывает ресурсы в проекте. Когда вы используете последний вызов PyInstaller, он не копирует файлы, к которым идет обращение в вашем коде (например, файлы .ui) в каталог для развернутого приложения. Вот несколько шагов, которые могут помочь вам правильно подготовить ваше PyQt6 приложение для создания исполняемого файла:

### 1. Конвертация .ui файлов в Python код
Один из стандартных способов работы с .ui файлами — преобразовать их в соответствующий Python код с помощью `pyuic` из PyQt. Это позволит избежать проблем с доступом к ui-файлам в скомпилированном приложении.

Команда для конвертации:
```bash
pyuic6 -x your_file.ui -o output_file.py
```
Затем, в вашем основном коде, вы будете использовать сгенерированный файл напрямую. Это избавит вас от необходимости загружать .ui файл во время выполнения.

### 2. Использование параметра `--add-data`
Если вы хотите оставить .ui файл и использовать его, вам нужно убедиться, что PyInstaller правильно включил этот файл в сборку. Вот как вы можете использовать параметр `--add-data` с PyInstaller:

```bash
pyinstaller --onedir --noconsole --icon=app/ui/pic/favicon.ico --add-data "path/to/your/ui_file.ui;." main.py
```

Обратите внимание, что разделитель для `--add-data` зависит от операционной системы:
- Для Windows: `;`
- Для Linux и MacOS: `:`

Если вы используете .spec файл, добавьте `datas` в `Analysis`:
```python
a = Analysis(['main.py'],
             pathex=['.'],
             binaries=[],
             datas=[('path/to/your/ui_file.ui', '.')],
             ...
```

### 3. Загрузка .ui файла правильно
Если вы оставляете использование .ui файлов, убедитесь, что в вашем коде вы загружаете их правильно. При использовании PyInstaller структура директорий может измениться. Вы должны использовать `os.path.join` с `sys._MEIPASS`, чтобы получить путь к загруженному исполняемому файлу:

```python
import os
import sys
from PyQt6 import uic

if getattr(sys, 'frozen', False):
    # Если приложение запущено как исполняемый файл
    base_path = sys._MEIPASS
else:
    # Если приложение запущено из исходников
    base_path = os.path.dirname(__file__)

ui_file_path = os.path.join(base_path, 'your_file.ui')
uic.loadUi(ui_file_path, self)
```

### 4. Проверка ошибок
Если вы все еще сталкиваетесь с ошибками при запуске .exe файла, убедитесь, что путь к вашим ресурсам правильный, и они действительно присутствуют в созданном дистрибутиве. Просмотрите сгенерированный `dist` каталог и убедитесь, что файлы .ui и любые другие зависимости были включены.

Следуя этим рекомендациям, вы сможете успешно создать ваше приложение в исполняемый файл без ошибок загрузки интерфейса.
Если правильно понял суть проблемы, то: 
Вам нужно изменить подход к использованию ui.
Все исходные файлы из qtdesigner нужно перевести в формат .py

Ресурсы
В папку со всеми окнами располагаем ресурсы
`.qrc -> .py`
pyrcc6 res/resources.qrc -o src/gui/windows/ui/resources_rc.py; \

Интерфейс
`.ui -> .py`
pyuic6  --from-imports res/ui/main.ui -o src/gui/windows/ui/main.py; \

--from-imports - в файле ресурсов .py сделает импорт from . import resources_rc , т.е. подхватит ранее созданные в этом каталоге файл ресурсов

Класс окна (на примере главного)
from PyQt6.QtWidgets import QMainWindow
from .ui.main import Ui_MainWindow

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

Пересобрать программу с помощью pyinstaller.

Таким образом мы перевели файлы ресурсов и шаблонов в .py формат, инициировали их в нашем классе (MainWindow).

Еще можете обратить внимание на библиотеку nuitka для создания exe файлов и не только.
Похожие вопросы