Run script without window popup or After popup

I want to be able to either: have my script run after the window is done. Or just directly do what I want it to do without the window popup in the first place.

I can’t find information on how to call the ‘Seperate Image…’ without a popup. When I call the function with batchmode enabled it pops up anyway

My only other idea was to get keypresses somehow but I don’t think that is supported?

Following auto accepts separate dialog. (You might want to find dialogs radio/check buttons, and change values before accepting…)

from krita import Krita
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication


def do_separation():
    def _do_after():
        separate_dialog = QApplication.activeModalWidget()
        # ToDo: find QCheckBox & QRadioButton widgets and set values...
        separate_dialog.accept()

    app = Krita.instance()
    separate_action = app.action('separate')
    QTimer.singleShot(0, _do_after)  # call _do_after, separate dialog is active
    separate_action.trigger()
    
            
do_separation()

/AkiR

1 Like

@AkiR Thank you for your answer, it was very helpful!

For the ToDo part of your comment, is it something along these lines? Or - ignoring the fact that it iterates the widget tree every time to check a box - is there a more elegant/correct way I should be doing it?


from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QCheckBox
from PyQt5.QtCore import QObject
from typing import cast


def find_widget(inParentWidget, inName):
    if inParentWidget.objectName() == inName:
        return inParentWidget
    for widget in inParentWidget.children():
        widget = find_widget(widget, inName)
        if widget:
            return widget
    return None


def set_checked(inDialog, inName, inChecked):
    widget = find_widget(inDialog, inName)
    if not widget:
        raise Exception(f"{inDialog} has no widget named {inName}")

    if isinstance(widget, QCheckBox):
        checkbox = cast(QCheckBox, widget)
        checkbox.setChecked(inChecked)
    else:
        raise Exception(f"{widget} is not a QCheckBox")


def split_layer(inDoc):

    def _do_after():
        dialog = QApplication.activeModalWidget()
        set_checked(dialog, "chkCreateGroupLayer", True)
        set_checked(dialog, "chkSeparateGroupLayers", False)
        set_checked(dialog, "chkAlphaLock", False)
        dialog.accept()

    splitAction = Krita.instance().action("layersplit")
    QTimer.singleShot(0, _do_after)
    splitAction.trigger()

Yes, you got the correct idea, walk the object tree and find correct widgets to manipulate.

For walking down the object tree there are some methods build in Qt
QObject.findChild(object_type, [object_name])->QObject
QObject.findChildren(object_type, [object_name])->iterator
note: both methods have option to disable recursion to child objects.
Also sometimes you can use QObject.metaObject().className() to filter out correct widget.

Example on using commands to find dialog’s widgets, bonus small tool for examining object tree.

from PyQt5.QtCore import QObject, QTimer
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QCheckBox, QSpinBox, QComboBox, QTreeView


_tree_view = QTreeView()


def show_object_tree(q_object):
    global _tree_view
    model = QStandardItemModel(parent=_tree_view)
    model.setHorizontalHeaderLabels(['type', 'name', 'meta cls name'])
    _tree_view.setModel(model)
    populate_tree(model.invisibleRootItem(), q_object)
    _tree_view.show()


def populate_tree(parent_item, parent_obj):
    for child_obj in parent_obj.children():
        type_item = QStandardItem(type(child_obj).__name__)
        name_item = QStandardItem(child_obj.objectName())
        meta_cls_item = QStandardItem(child_obj.metaObject().className())
        parent_item.appendRow([type_item, name_item, meta_cls_item])
        populate_tree(type_item, child_obj)


def split_layer(inDoc):

    def _do_after():
        dialog = QApplication.activeModalWidget()
        show_object_tree(dialog)
        dialog.findChild(QComboBox, "cmbMode").setCurrentIndex(0)
        dialog.findChild(QCheckBox, "chkCreateGroupLayer").setChecked(True)
        dialog.findChild(QCheckBox, "chkSeparateGroupLayers").setChecked(False)
        dialog.findChild(QCheckBox, "chkAlphaLock").setChecked(False)
        dialog.findChild(QCheckBox, "chkHideOriginal").setChecked(True)
        dialog.findChild(QCheckBox, "chkSortLayers").setChecked(False)
        dialog.findChild(QCheckBox, "chkDisregardOpacity").setChecked(False)
        dialog.findChild(QSpinBox, "intFuzziness").setValue(25)
        dialog.accept()

    splitAction = Krita.instance().action("layersplit")
    QTimer.singleShot(0, _do_after)
    splitAction.trigger()


doc = Krita.instance().activeDocument()
split_layer(doc)

/AkiR

1 Like

@AkiR Thank you! It’s indeed a lot more elegant. (And the tree view is easier than tracking it down in the .ui files.)