UI file loading

I followed this explanation by Nathan Horne and built an inheritable class for loading .ui files and compiling them at runtime quite a while ago.

Also I found this neat way of writing singletons.

So here’s a class that takes a UI file, compiles it and shows its contents.

'''
@Author: Trevor van Hoof

UIC compiler at runtime
Inherit uicWindow and give it a ui file to open
Reloading the import of uicr will also recompile
the UI file, showing new changes.
'''


import os.path
from PyQt4 import uic, QtGui


'''
Generic PyQt window class which can be inherited from for quick window creation
'''
class UicWindow(object):
    '''
    Uses the uic compiler at runtime, so any QtDesigner file gets updated immediately
    The created QtWindow object is named after the file given (without extension)
    When creating multiple instances of the same .ui file it may be wise to manually rename
    by using the .window.setWindowTitle() function 
        
    @param in_parent
    The window this widget is parented to
    -> widgets get embedded in main
    -> dockwidgets can dock to main
    -> mainWindows get closed when main gets closed
        
    @param in_uifile
    The QtDesigner ui file to load, best is to use an absolute path to avoid problems with import and inheritance
        
    @param in_customtitle
    QtDesigner permits windows and widgets to be named, but it is also possible to set or change
    the name using script, this is supported so multiple copies of the same input can be differently named
    '''
    def __init__(self,in_parent,in_uifile,in_customtitle=None):
        window_class = uic.loadUiType(in_uifile)
        '''
        The uic returns both a form class with other functionality
        and a QWidget with the designer file objects
            
        Both functionalities are required and are therefore packed together
        through inheritance in this embedded class which serves no other
        purpose than combining data
        '''
        class QtWindow(window_class[0],window_class[1]):
            def __init(self):
                pass

        self.window = QtWindow()
        super(QtWindow, self.window).__init__(in_parent)
        self.window.setupUi(self.window)
        self.window.setObjectName(os.path.splitext(os.path.basename(in_uifile))[0])
        if in_customtitle is not None:
            self.window.setWindowTitle(in_customtitle)
        self.window.show()

    def snapToCenter(self):
        if self.window.parent() != None:
            core = self.window.parent().geometry().center()
        else:
            core = QtGui.QDesktopWidget().screen().geometry().center()
        geo = self.window.geometry()
        self.window.setGeometry( core.x()-geo.width()*0.5,
                                 core.y()-geo.height()*0.5,
                                 geo.width(),
                                 geo.height() )
    
    def resizeAndCenter(self, in_size):
        self.window.resize(in_size)
        self.snapToCenter()
    
    def __del__(self):
        try: self.window.close()
        except: pass

And here’s a usage example; note that the ui file must exist.

import Qtutils.uicr
from Qtutils.LaunchAsStandalone import *
from PyQt4 import QtCore, QtGui

class MainWindow(Qtutils.uicr.UicWindow):
    def __init__(self):
        #act like a singleton, any future function call will return this instance
        globals()[self.__class__.__name__] = self
        
        #get a file next to this file
        self.filepath = __file__.replace('\\','/').rsplit('/',1)[0]
        filename = ('%s/main.ui'%self.filepath)
        
        #and load it as a UI file, parent defaults to None
        Qtutils.uicr.UicWindow.__init__(self, None, filename)

    '''
    Makes sure the singleton instance is callable
    '''    
    def __call__(self):
        return self


#main function to launch as standalone app for unit-tests
def main():
    w = MainWindow()
    w.resizeAndCenter( QtCore.QSize(180,220) )
    return w
    
QtStandalone(main)

By removing the first line in __init__:

globals()[self.__class__.__name__] = self

The class is no longer a singleton, this may be desirable while frequently updating the ui file as it won’t be reimported unless the class is reinitialized.

Leave a Reply

Your email address will not be published. Required fields are marked *