Split code into main and ui files individually

33 views
Skip to first unread message

likage

unread,
Oct 15, 2016, 7:39:00 PM10/15/16
to Python Programming for Autodesk Maya
I have done all my codings, ui creation etc into a single file and I would like to separate between my main functions (manager_main.py) and the ui (manager_ui.py) into 2 files
Just so you know, I created my widgets 'manually' instead of using Qt designer..

class manager_ui(QtGui.QDialog):
   
def __init__(self, parent=None):
       
QtGui.QDialog.__init__(self, parent)
       
self.setWindowTitle('UI Manager')

       
# Build the GUI
       
self.init_ui()
       
self.populate_table_data()
       
self.connect_signals()
       
self.resize(QtCore.QSize(600, 350))


   
def init_ui(self):
       
self.color_table = QtGui.QTableWidget()
       
self.color_table.setRowCount(5)
       
self.color_table.setColumnCount(2)
       
self.color_table.setHorizontalHeaderLabels(['Geos in Scene',
                                                     
'Colors'])
       
self.set_color_btn = QPushButton()
        ...

   
def connect_signals(self):
       
self.reset_colors_btn.clicked.connect(self.reset_color)
       
   
def reset_color(self):
       
for row in xrange(self.variant_table.rowCount()):
           
self.color_table.cellWidget(row, 1).setCurrentIndex(0)

   
def populate_data(self):
       
...
       
self.color_combobox = QtGui.QComboBox()
       
self.color_combobox.addItems(list(sorted(new_itempath)))
       
self.color_table.setCellWidget(index, 1, self.color_combobox)

Suppose if I am going to shift the reset_color function into the main file, I do got errors stating that self.variant_table, where self is not defined etc. I also tried importing in the ui file into the main script and renamed it to something such as 'mangaer_ui.variant_table.cellWidget...' still I am getting errors.

And so my question would be, in the various functions I have wrote, and especially within the functions in which I have stated the widget creations variables I have defined (self.color_table, self.set_color_btn etc), I suppose I am not able to move it into the main file at all? If it is, what is the best way to approach it?

Additionally, was wondering if anyone could give me any insights on what to look out for when splitting the file into a main and a ui file?

Justin Israel

unread,
Oct 16, 2016, 1:05:49 AM10/16/16
to python_in...@googlegroups.com
Your reset_color() method has direct knowledge of the UI structure in your class, so it needs to know about a couple table widget members. There are a few ways you can restructure this to make it work. You can make reset_color() a function which takes the required table widgets as parameters, and then you would have to use functools.partial() to wrap it up in your signal/slot connection:   self.reset_colors_btn.clicked.connect(partial(other_module.reset_color, table1, table2))
This can work in a number of situations, but for times when you have widgets that you expect to delete, this can sometimes cause your objects to stay alive (because of the partial wrapper). 

Another way would be to do what is documented in Qt about the different approaches in using a UI file: http://pyqt.sourceforge.net/Docs/PyQt4/designer.html
What you see in those examples is a reference to the instance of the main class being passed to the UI setup class, so that it can initialize it. Maybe something like this:

class MainClass():
    def __init__(...):
        self._ui = UIClass()
        self._ui.my_button.clicked.connect(self.reset_colors)

    def reset_colors():
        self._ui.some_table.doSomething()

 

Additionally, was wondering if anyone could give me any insights on what to look out for when splitting the file into a main and a ui file?

There are a couple of ways to design these things. Your UI could be "dumb" like the way Qt Designer UI files look after you convert them. They just define the layout of widgets but have no logic. And then some other class initializes them and uses the widgets. Then you could go the route of having a smart UI, where it privately lays out its internal widgets, has a bunch of logic for doing what it is meant to do, and exposes only the desired public signals, slots, and methods that a user should access. This encapsulation makes your widgets more reusable, since the outside world won't have knowledge about the child widgets. This is also my preferred approach. 
 

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/fe696c48-6cc6-4a63-9fe9-acb3ae6056f3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

likage

unread,
Oct 17, 2016, 12:51:02 PM10/17/16
to Python Programming for Autodesk Maya
Hi Justin, thanks for the feedback.
So I tried doing the following..

### UI File, manager_ui.py ###

import functools
import manager_main

class manager_ui(QtGui.QDialog):
   
def __init__(self, parent=None):
       
QtGui.QDialog.__init__(self, parent)
       
self.setWindowTitle('UI Manager')


       
# Build the GUI
       
self.init_ui()
       
self.populate_table_data()
       
self.connect_signals()
       
self.resize(QtCore.QSize(600, 350))

   
def init_ui(self):
       
self.color_table = QtGui.QTableWidget()
       
self.color_table.setRowCount(5)
       
self.color_table.setColumnCount(2)
       
self.color_table.setHorizontalHeaderLabels(['Geos in Scene',
                                                     
'Colors'])
       
self.set_color_btn = QPushButton()
       
...

   
def connect_signals(self):

       
#self.reset_colors_btn.clicked.connect(self.reset_color)
       
self.reset_colors_btn.clicked.connect(functools.partial(manager_main.reset_color, self.color_table))
   
   
'''
    # Function is to be called in the main file

    def reset_color(self):
        for row in xrange(self.variant_table.rowCount()):
            self.color_table.cellWidget(row, 1).setCurrentIndex(0)
    '''


   
def populate_data(self):
       
...
       
self.color_combobox = QtGui.QComboBox()
       
self.color_combobox.addItems(list(sorted(new_itempath)))
       
self.color_table.setCellWidget(index, 1, self.color_combobox)

        
And this is my main file:
### Main File, manager_main.py ###

def reset_color(table):
   
for row in xrange(table.rowCount()):
        table
.cellWidget(row, 1).setCurrentIndex(0)


While it seems to work, can I check with you if this is the correct approach to go about?

Justin Israel

unread,
Oct 17, 2016, 2:52:01 PM10/17/16
to Python Programming for Autodesk Maya
Well it's actually backwards from what I was thinking. But that might just be the names of your modules throwing me off because I don't really know what the full contents of manager_main will be. If you expect manager_main to also import manager_ui then you have circular dependencies and that would be undesirable.

My thought was that your UI would not connect up the external signals, because it shouldn't know about the outside world that will consume it. It can wire up its own internal signals though, to its own slots. I was thinking manager_main would hook up the signals to its own slots when it creates an instance of the UI.

What you can do is hide the details of your UI class by not having outside users access the composed widgets, and just exposing signals and function that you want users to call. An example of forwarding a signal can be

class Ui(QDialog)

resetRequested = QtCore.Signal()

def __init__(...) :
self.reset_colors_btn.clicked.connect(self.resetRequested)

I know in this case your main will need to access the table widgets, and that is OK since you specifically wanted a small amount of coupling and just a separation of the UI and business logic.

Justin

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

likage

unread,
Oct 17, 2016, 6:41:05 PM10/17/16
to Python Programming for Autodesk Maya
Well actually it will be my UI accessing the functions of Main.. I should have mentioned thath

Justin Israel

unread,
Oct 17, 2016, 8:29:03 PM10/17/16
to python_in...@googlegroups.com
On Tue, Oct 18, 2016 at 11:41 AM likage <dissid...@gmail.com> wrote:
Well actually it will be my UI accessing the functions of Main.. I should have mentioned thath

Can you explain what kind of code you expect to have living in your main? It still sounds backwards to have your UI code import main. Would main never import from the ui module? 
 

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages