AWS Thinkbox Discussion Forums

QT custom UI's within Deadline

Hi,
Thought it would be nice now we have QT UI for studio’s to build their own UI’s as both standalone and with a minimum amount of change, allow them to be ‘hosted’ / tied into the Deadline environment when required by a studio.

So, I’m trying to tie a basic pyQT UI script into Deadline’s QApplication as it’s parent but not having much luck. What if Deadline in it’s own shipping version of Python also included pyQT and PySide site-packages in the future?

Untitled.png

[code]import os, sys

from PyQt4 import QtCore, QtGui

from Deadline.Scripting import *

class SampleDialog(QtGui.QDialog):
def init(self, parent):
super(SampleDialog, self).init(parent)
self.setWindowTitle(‘Test QT QDialog in Deadline’)
self.resize(400, 200)

class MainWindow(QtGui.QMainWindow):
def init(self, parent = None):
super(MainWindow, self).init(parent)
self.setWindowTitle(‘Test QT QWindow inside of Deadline’)
self.resize(600, 400)

    # create the menu
    file_menu = self.menuBar().addMenu('File')
    edit_menu = self.menuBar().addMenu('Edit')
    debug_menu = self.menuBar().addMenu('Debug')
    
    # create the menu actions
    exec_act  = debug_menu.addAction('Exec Dialog')
    show_act  = debug_menu.addAction('Show Dialog')
    count_act = debug_menu.addAction('Show Count')
    
    # create the connections
    exec_act.triggered.connect( self.execDialog )
    show_act.triggered.connect( self.showDialog )
    count_act.triggered.connect( self.showCount )

def execDialog(self):
    dlg = SampleDialog(self)
    dlg.exec_()
    
def showDialog(self):
    dlg = SampleDialog(self)
    dlg.show()

def showCount(self):
    count = len(self.findChildren(QtGui.QDialog))
    QtGui.QMessageBox.information(self, 'Dialog Count', str(count))

def main( *args ):

window = MainWindow()
window.show()

QApplication.exec_()[/code]

I get this error:

2013-09-17 10:49:02: Traceback (most recent call last): 2013-09-17 10:49:02: File "DeadlineUI\UI\Commands\ScriptCommands.py", line 87, in InnerExecute 2013-09-17 10:49:02: Exception: Python Error: NameError : global name 'QApplication' is not defined (Python.Runtime.PythonException) 2013-09-17 10:49:02: Stack Trace: 2013-09-17 10:49:02: [' File "none", line 52, in __main__\n'] 2013-09-17 10:49:02: 2013-09-17 10:49:02: at FranticX.Scripting.PythonNetScriptEngine.a (System.Exception A_0) [0x00000] in <filename unknown>:0 2013-09-17 10:49:02: at FranticX.Scripting.PythonNetScriptEngine.CallFunction (System.String functionName, Python.Runtime.PyObject[] args) [0x00000] in <filename unknown>:0 2013-09-17 10:49:02: at Deadline.Scripting.DeadlineScriptEngine.CallFunction (System.String functionName, Python.Runtime.PyObject[] args) [0x00000] in <filename unknown>:0 2013-09-17 10:49:02: at Deadline.Scripting.DeadlineScriptManager.CallFunction (System.String scopeName, System.String functionName) [0x00000] in <filename unknown>:0 2013-09-17 10:49:02: at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) 2013-09-17 10:49:02: at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0

Hey Mike,

You need to add this import statement to get rid of that QApplication error:

from PyQt4.QtGui import *

However, your script still won’t work. The main window will show briefly and then close. I’m not sure why this is the case, but if you were to use a QDialog instead, you could use the exec_() function which will block and keep the window open. You should be able to add a menu bar to a QDialog.

We do ship with the pyQT site-package already.

Cheers,

  • Ryan

Menu bar isn’t supported in a QDialog. Only a QMainWindow it would seem…
I’ll have a look into why the MainWindow flashes. I reckon it’s a parenting issue to the main Deadline QApplication…fix that and should work…

Apologies, of course you do!

You aren’t parenting your UI to anything, and you aren’t calling any blocking methods on it, so it’s almost certainly getting GC’ed right away. Rule #1* of Qt GUI programming: Make sure your widget hierarchy is in order.

-Nathan

  • Not actually Rule #1, but it’s up there.

An example would be useful :slight_smile:

Well, one simple thing to do is just have your UI automatically parent itself to the QApplication’s active window if no other parent is passed. However, if this is a single-purpose GUI, you may not even want to keep the ‘parent’ argument around.

class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): if parent is None: parent = QtGui.qApp.activeWindow() super(MainWindow, self).__init__(parent) # Do other __init__ stuff

Thanks Nathan! That’s the parenting all sorted when it’s executed within the Deadline monitor environment. I haven’t been able to figure out a way to call the QMainWindow via a blocking method within the Deadline QApplication? I can get it working for any child widgets such as a QDialog, but not for my MainWindow. ie: when my MainWindow is visible, I am unable to block the Deadline monitor UI from being interactive to the user. Any ideas?
Thanks,
Mike

[code]from PyQt4 import QtCore, QtGui

from Deadline.Scripting import *

class SampleDialog(QtGui.QDialog):
def init(self, parent):
super(SampleDialog, self).init(parent)
self.setWindowTitle(‘Test QT QDialog in Deadline’)
self.resize(400, 200)

class MainWindow(QtGui.QMainWindow):
def init(self, parent = None):
if parent is None:
parent = QtGui.qApp.activeWindow()
super(MainWindow, self).init(parent)

    self.setWindowTitle('Test QT QWindow inside of Deadline')
    self.resize(600, 400)
    
    # create the menu
    file_menu = self.menuBar().addMenu('File')
    edit_menu = self.menuBar().addMenu('Edit')
    debug_menu = self.menuBar().addMenu('Debug')
    
    # create the menu actions
    exec_act  = debug_menu.addAction('Exec Dialog')
    show_act  = debug_menu.addAction('Show Dialog')
    count_act = debug_menu.addAction('Show Count')
    
    # create the connections
    exec_act.triggered.connect( self.execDialog )
    show_act.triggered.connect( self.showDialog )
    count_act.triggered.connect( self.showCount )

def execDialog(self):
    dlg = SampleDialog(self)
    dlg.exec_()
    
def showDialog(self):
    dlg = SampleDialog(self)
    dlg.show()

def showCount(self):
    count = len(self.findChildren(QtGui.QDialog))
    QtGui.QMessageBox.information(self, 'Dialog Count', str(count))

def main( *args ):
window = MainWindow()
window.show()[/code]

If you want your window to prevent users from interacting with other windows in the application until it is closed, you need to set its modality appropriately (in this case, you want application-modal). In your init, simply call:

self.setWindowModality(QtCore.Qt.ApplicationModal)

Then just call .show() and .raise_() as usual.

What I meant by a “blocking method” is blocking in the programming sense. For instance, QDialog.exec_() is a blocking method; once called, it will not return control to its calling code until the dialog is closed. Compare this to QWidget.show(), which simply shows the widget (and its children) and returns immediately.

I hear you fella :slight_smile:
That snippet is exactly what I was after.
Thanks!

Privacy | Site terms | Cookie preferences