3

Tengo el siguiente problema.

Tengo un archivo en el cual tengo una clase para poder abrir un QMainWindow, esta clase la quiero mandar a llamar desde un archivo diferente pero me sale un error:

FileNotFoundError: [Errno 2] No such file or directory: 'ui_files/FirstUser.ui'

Archivo que manda a llamar a la clase:

import sqlite3
from Source.FirstUse.User.FirstUseUser import FirstUserClass

fc = FirstUserClass()

conexion = sqlite3.connect("Source/General.db")
cursor = conexion.cursor()

cursor.execute("SELECT * FROM Acess")
for registro in cursor:
    if registro[0] == 0:
        fc.show()
    else:
        pass
conexion.close()

Archivo que contiene la clase.

from PyQt5.QtWidgets import QMainWindow,QApplication
from PyQt5 import QtCore
from PyQt5 import uic

class FirstUserClass(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        uic.loadUi("ui_files/FirstUser.ui",self)

        #Prpiedades de la Ventana
        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)




app = QApplication([])
fcu = FirstUserClass()
fcu.show()
app.exec_()

Ruta de los archivos:

Archivo que llama la clase:

C:\Users\Angel\Desktop\School Administration System v.2.0\User Version

Archivo que contiene la clase:

A este nivel esta el archivo.py y el archivo .ui

C:\Users\Angel\Desktop\School Administration System v.2.0\User Version\Source\FirstUse\User

FJSevilla
  • 55,603
  • 7
  • 35
  • 58
  • Una aclaración ¿tienes una carpeta llamada `ui_files` en `User Version\Source\FirstUse\User` o el archivo está al mismo nivel que `FirstUseUser.py`? Lo digo porque tienes `uic.loadUi("ui_files/FirstUser.ui",self)` – FJSevilla Aug 18 '19 at 16:30
  • @FJSevilla perdon me equivoque es una carpeta ui_files y dentro esta el .ui – Angel Judath Alvarez Aug 18 '19 at 16:36

1 Answers1

2

El problema lo tienes en:

uic.loadUi("ui_files/FirstUser.ui",self)

Dado que ui_files/FirstUser.ui es una ruta relativa, esta se resuelve dependiendo del directorio de trabajo actual. Por efecto, si ejecutas FirstUseUser.py como módulo principal, el directorio de trabajo es:

C:\Users\Angel\Desktop\School Administration System v.2.0\User Version\Source\FirstUse\User

quedando la ruta del archivo como:

C:\Users\Angel\Desktop\School Administration System v.2.0\User Version\Source\FirstUse\User\ui_files\FirstUser.ui

que es correcta y no tenemos problema alguno.

Por contra, si importas el archivo, la ruta de trabajo será por defecto la del módulo principal ejecutado, no la del módulo importado. En tu caso esta ruta sería:

C:\Users\Angel\Desktop\School Administration System v.2.0\User Version

por lo que la ruta del .ui al intentar resolver la ruta relativa quedaría como:

C:\Users\Angel\Desktop\School Administration System v.2.0\User Version\ui_files\FirstUser.ui

que es incorrecta. Para que funcionara la ruta relativa debería ser:

uic.loadUi("Source/FirstUse/User/ui_files/FirstUser.ui", self)

el problema es que esto no es nada práctico, en cuanto modifiquemos el directorio de trabajo o se importe desde otro sitio no funcionará. Tampoco podremos ejecutar FirstUser.ui como script principal.

Una solución general es obtener la ruta del módulo importado mediante el atributo __file__ y construir la ruta en base a ella:

# Python >= 3.4
import pathlib
from PyQt5.QtWidgets import QMainWindow,QApplication
from PyQt5 import QtCore
from PyQt5 import uic

class FirstUserClass(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        mod_path = pathlib.Path(__file__).parent
        uic.loadUi(mod_path / "ui_files/FirstUser.ui", self)

        #Prpiedades de la Ventana
        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)


if __name__ == "__main__":
    app = QApplication([])
    fcu = FirstUserClass()
    fcu.show()
    app.exec_()

Si por algo se quiere obtener la ruta absoluta podemos hacer uso del método resolve():

(mod_path / "ui_files/FirstUser.ui").resolve()

Si usas Python < 3.4 puedes usar os.path en vez de pathlib:

# Python < 3.4
import os
from PyQt5.QtWidgets import QMainWindow,QApplication
from PyQt5 import QtCore
from PyQt5 import uic

class FirstUserClass(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        mod_path = os.path.dirname(__file__)
        uic.loadUi(os.path.join(mod_path, "ui_files/FirstUser.ui"), self)

        #Prpiedades de la Ventana
        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)


if __name__ == "__main__":
    app = QApplication([])
    fcu = FirstUserClass()
    fcu.show()
    app.exec_()

Hay casos en los que __file__ no está definido o no puede ser usado como en módulos que dependen de librerías dinámicas en C, en intérpretes interactivos, etc. Otra posibilidad es usar el módulo inspect de la biblioteca estándar:

# Python >= 3.4
import inspect
import pathlib

filename = inspect.getframeinfo(inspect.currentframe()).filename
mod_path = pathlib.Path(filename).resolve().parent
uic.loadUi(mod_path / "ui_files/FirstUser.ui", self)

# Python < 3.4
import inspect
import os

filename = inspect.getframeinfo(inspect.currentframe()).filename
mod_path = os.path.dirname(os.path.abspath(filename))
uic.loadUi(os.path.join(mod_path, "ui_files/FirstUser.ui"), self)

Recuerda que al importar un módulo este se ejecuta (todo lo que hay a nivel global), si no metes las últimas líneas dentro del condicional if __name__ == "__main__", al importar el módulo la ventana se mostrará inmediatamente.

FJSevilla
  • 55,603
  • 7
  • 35
  • 58