Tk-multi-publish : access dialog ui widget from collector

I’ve added a widget to the publisher dialog that I want to query the state of prior to running the collector.
Is it possible to access the app ui widgets from the collector hook?
I imagine something like self.parent.ui.my_widget should work?

1 Like

The AppDialog and GUI by default is obscured from the collector and publish plugin hooks. Here are some quick and dirty approaches:

  1. You can hack it by creating your own pre_publish hook that overrides the default show_dialog behaviour and storing the created, non-model dialog as self.parent.ui i.e.
    class PrePublishHook(HookBaseClass):
        def validate(self):
            app = self.parent
            app.ui = None
            display_name = app.get_setting("display_name")
    
            if super(PrePublishHook, self).validate():
                # start ui
                if app.modal:
                    app.engine.show_modal(display_name, app, AppDialog)
                else:
                    app.ui = app.engine.show_dialog(display_name, app, AppDialog)
            else:
                app.logger.debug(
                    "%s validate returned False -- abort publish."
                    % app.pre_publish_hook.__class__.__name__
                )
            return False  # Used our own launch logic, so always return False to abort original logic
    
  2. Alternatively, you can try exploring the hook’s self.parent.engine.created_qt_dialogs to see if the Publish Dialog is in there somewhere

A more engineered suggestion will be to fork the tk-multi-publish2 app repository and setup a ui property (or dialogs if supporting multiple UIs) in app.py.

Hey. Number one method is not going to work as you don’t have “AppDialog” variable and in order to feed it to the prepublish hook you need to correct the code of the app and take it over anyway.
Number two can find the dialog, but not during the start because it is constructed only after all the collectors and plugins past through the accept phase. So there is no place to put in the code for getting the app dialog. That’s a pity because take over the whole app only because the dialog is so small and you want to change the initial size is a bummer.
I even tried to initiate an additional thread inside the collector, that would search for the newly opened dialog with the name “Publish” and resize it if found. And it works, but only once. The second time you open publisher, 3ds max just crashes… So I had to completely give up on that idea.

that’s the code for the collector

def process_current_session(self, settings, parent_item):

        """

        Analyzes the current session open in Max and parents a subtree of

        items under the parent_item passed in.

        :param parent_item: Root item instance

        """

        resize_dialog_thread = threading.Thread(target=_resize_dialog, args=(self,))

        resize_dialog_thread.setDaemon(True)

        resize_dialog_thread.start()

        blablabla

that’s the function for the thread

def _resize_dialog(the_hook):

    """

    A method to resize the dialog.

    :param the_hook: The base hook to get the engine and the dialog.

    """

    for _ in range(15):

        time.sleep(0.5)

        the_dialogs = the_hook.parent.engine.created_qt_dialogs

        for the_dialog in the_dialogs:

            if the_dialog.ui.app_name.text() == 'Publish':

                the_dialog.resize(1100, 900)

                return

Ah yes, my mistake for not explaining the AppDialog sub-class hack properly.

Here’s what a better pre_publish.py hook would look like

  1. At the top of the file, create a factory method that will construct a sub-class of AppDialog

    def subclassed_app_dialog(AppDialog):
        class MyAppDialog(AppDialog):
            """Custom code added in this scope."""
    
         return MyAppDialog
    
  2. Then later on in the hook, call the factory with the original AppDialog class imported from hook’s self.import_module("tk_multi_publish2.dialog")

    class PrePublishHook(HookBaseClass):
        def validate(self):
            app = self.parent
            app.ui = None
            display_name = app.get_setting("display_name")
            if super(PrePublishHook, self).validate():
    
                dialog = self.import_module("tk_multi_publish2.dialog")
                MyAppDialog = subclassed_app_dialog(dialog.AppDialog)
    
                # start ui
                if app.modal:
                    app.engine.show_modal(display_name, app, MyAppDialog)
                else:
                    app.ui = app.engine.show_dialog(display_name, app, MyAppDialog)
            else:
                app.logger.debug(
                    "%s validate returned False -- abort publish."
                    % app.pre_publish_hook.__class__.__name__
                )
            return False  # Used our own launch logic, so always return False to abort original logic
    
1 Like

hey, thank you so much for the tip!
I ended up with this code

class PrePublishHook (HookBaseClass):
    """
    This plugin is made to resize the main publish dialog as it is too small.
    """

    def validate(self):
        app = self.parent
        app.ui = None
        display_name = app.get_setting("display_name")
        dialog = app.import_module("tk_multi_publish2.dialog")

        # start ui

        if app.modal:
            app.engine.show_modal(display_name, app, dialog.AppDialog)
            return

        app.ui = app.engine.show_dialog(display_name, app, dialog.AppDialog)
        the_app_ui = app.ui.ui
        qdialog = app.ui.parent().parent().parent()

        qdialog.resize(1200,900)
        qdialog.move(350,50)
        the_app_ui.splitter.setSizes([600,600])

        return False  # Used our own launch logic, so always return False to abort original logic