# Proper way to activate new layer?

**URL:** <https://krita-artists.org/t/proper-way-to-activate-new-layer/29481>\
**Category:** Plugins Development\
**Created:** [September 23, 2021, 9:57am UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481 "2021-09-23T09:57:40Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![yetanotherpainter](https://krita-artists.org/user_avatar/krita-artists.org/yetanotherpainter/32/31561_2.png) [@yetanotherpainter](https://krita-artists.org/u/yetanotherpainter)\
**Post date:** [September 23, 2021, 9:57am UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/1 "2021-09-23T09:57:40Z")

</div>

I use this part of the code to fill the selection with particular color

```auto
    layer = doc.createNode("Paint", "paintlayer")
    root.addChildNode(layer, None)
    doc.setActiveNode(layer)

    for i in range(color_count):
        newSelection = Selection()
        newSelection.select(i * s, 0, s, s, 255)    
        doc.setSelection(newSelection)
        app.action('fill_selection_foreground_color').trigger()

```

However once the operation is finished currently selected layer is filled with colors and my “Paint” layer is empty.

Is there other way to make the layer active such that changes applied there?

> **Sys Info**
>
> Krita
> 
> Version: 4.4.8  
> Languages: en\_US, en  
> Hidpi: true
> 
> Qt
> 
> Version (compiled): 5.12.11  
> Version (loaded): 5.12.11

---

<div class="post-metadata">

**Author:** ![AkiR](https://krita-artists.org/user_avatar/krita-artists.org/akir/32/8557_2.png) [@AkiR](https://krita-artists.org/u/AkiR)\
**Post date:** [September 23, 2021, 11:09am UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/2 "2021-09-23T11:09:03Z")

</div>

This worked in Win10, Krita 4.4.8

Create empty document and run in scripter.

```python
from krita import (
        Krita,
        Selection,
        ManagedColor)

from PyQt5.QtGui import (
        QColor,)

app = Krita.instance()
doc = app.activeDocument()
root = doc.rootNode()
win = app.activeWindow()
view = win.activeView()
s = 32
colors = [
        QColor(255, 0, 0),
        QColor(0, 255, 0),
        QColor(0, 0, 255),
        QColor(255, 255, 0),
        QColor(0, 255, 255),
        QColor(255, 0, 255)]

layer = doc.createNode("My new layer", "paintlayer")
root.addChildNode(layer, None)
doc.setActiveNode(layer)

for i, color in enumerate(colors):
    newSelection = Selection()
    x, y = i * s, 0
    width, height = s, s
    opacity = 255
    newSelection.select(x, y, width, height, opacity)
    doc.setSelection(newSelection)
    mColor = ManagedColor.fromQColor(color)
    view.setForeGroundColor(mColor)
    app.action('fill_selection_foreground_color').trigger()

```

result:  
“My new layer” has 6 color boxes and last box has current selection.

maybe document also created in script, and view to new document is NOT active?

/AkiR

---

<div class="post-metadata">

**Author:** ![yetanotherpainter](https://krita-artists.org/user_avatar/krita-artists.org/yetanotherpainter/32/31561_2.png) [@yetanotherpainter](https://krita-artists.org/u/yetanotherpainter)\
**Post date:** [September 23, 2021, 11:23am UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/3 "2021-09-23T11:23:00Z")

</div>

That is strange  
Your code works fine.

And I experimented a bit.  
I use QInputDialog.getInt in the script.  
And I noticed that this behaviour is actually when I use it.

Any suggestions how to better deal with it?

---

<div class="post-metadata">

**Author:** ![AkiR](https://krita-artists.org/user_avatar/krita-artists.org/akir/32/8557_2.png) [@AkiR](https://krita-artists.org/u/AkiR)\
**Post date:** [September 23, 2021, 11:45am UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/4 "2021-09-23T11:45:54Z")

</div>

```python
from random import (
        randint,)

from krita import (
        Krita,
        Selection,
        ManagedColor)

from PyQt5.QtGui import (
        QColor,)

from PyQt5.QtWidgets import (
    QInputDialog,)

def make_blocks(blockCount):
    app = Krita.instance()
    doc = app.activeDocument()
    root = doc.rootNode()
    win = app.activeWindow()
    view = win.activeView()
    s = 32
    colors = [QColor(randint(0, 255), randint(0, 255), randint(0, 255)) for _ in range(blockCount)]

    layer = doc.createNode("My new layer", "paintlayer")
    root.addChildNode(layer, None)
    doc.setActiveNode(layer)

    for i, color in enumerate(colors):
        newSelection = Selection()
        x, y = i * s, 0
        width, height = s, s
        opacity = 255
        newSelection.select(x, y, width, height, opacity)
        doc.setSelection(newSelection)
        mColor = ManagedColor.fromQColor(color)
        view.setForeGroundColor(mColor)
        app.action('fill_selection_foreground_color').trigger()

blockCount, doIt = QInputDialog.getInt(
        None,
        "Make Blocks",
        "give block count",
        value=1,
        min=1,
        max=100)
if doIt:
    make_blocks(blockCount)

```

still works correctly. 🤔

/AkiR

---

<div class="post-metadata">

**Author:** ![yetanotherpainter](https://krita-artists.org/user_avatar/krita-artists.org/yetanotherpainter/32/31561_2.png) [@yetanotherpainter](https://krita-artists.org/u/yetanotherpainter)\
**Post date:** [September 23, 2021, 11:50am UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/5 "2021-09-23T11:50:48Z")

</div>

Yes. It works on my PC too.  
It seems to be the case on a slower PCs.

I tested my script on a Virtual Machine (that is significantly slower).  
I think that is the case. When PC is slow operations are finished in a bit different order. On a fast PC it just has enough time to finish it.

The only way to fix it (as an idea) is to crate custom QDialog and use exec\_() method (that should block computations enough).

Thanks for validating the code on your side 🙂  
I think I will move on by myself now.

---

<div class="post-metadata">

**Author:** ![yetanotherpainter](https://krita-artists.org/user_avatar/krita-artists.org/yetanotherpainter/32/31561_2.png) [@yetanotherpainter](https://krita-artists.org/u/yetanotherpainter)\
**Post date:** [September 23, 2021, 12:35pm UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/6 "2021-09-23T12:35:40Z")

</div>

Yes. Having custom dialog did fix the issue:

```auto
class CustomDialog(QDialog):
    def __init__ (self, parent=None):
        super(). __init__ (parent)

        self.setWindowTitle("HELLO!")

        QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel

        self.buttonBox = QDialogButtonBox(QBtn)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.lineedit = QLineEdit()
        self.lineedit.setText("10")
        self.onlyint = QIntValidator()
        self.lineedit.setValidator(self.onlyint)

        self.layout = QVBoxLayout()
        message = QLabel("Something happened, is that OK?")
        self.layout.addWidget(message)
        self.layout.addWidget(self.lineedit)
        self.layout.addWidget(self.buttonBox)
        self.setLayout(self.layout)

def dialogGetInt():
    dlg = CustomDialog()
    if dlg.exec():
        print("Success!")
        print(dlg.lineedit.text())
        return int(dlg.lineedit.text())
    else:
        print("Cancel!")
    return 3

```

P.S. Code is a bit messy, though you can get the idea )  
@AkiR maybe it will be helpful to you too 😉

---

<div class="post-metadata">

**Author:** ![KnowZero](https://krita-artists.org/letter_avatar_proxy/v4/letter/k/e8c25b/32.png) [@KnowZero](https://krita-artists.org/u/KnowZero)\
**Post date:** [September 23, 2021, 1:52pm UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/7 "2021-09-23T13:52:38Z")

</div>

Just want to say that there is no reason to use setActiveLayer when using addChildNode as the new layer will automatically become the active layer. If anything, it seems to sometimes get a bit buggy when you do that.

2nd, what you may want to run is doc.waitForDone() after creating a new layer.

---

<div class="post-metadata">

**Author:** ![yetanotherpainter](https://krita-artists.org/user_avatar/krita-artists.org/yetanotherpainter/32/31561_2.png) [@yetanotherpainter](https://krita-artists.org/u/yetanotherpainter)\
**Post date:** [September 23, 2021, 2:02pm UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/8 "2021-09-23T14:02:36Z")

</div>

Actually I played a bit longer. And it still acts kinda weirdly. First it applies changes then creates new layer.  
With or without doc.saitForDone. And even with custom Dialog window.

Seems like it is some kind of bug. Have no idea.

---

<div class="post-metadata">

**Author:** ![KnowZero](https://krita-artists.org/letter_avatar_proxy/v4/letter/k/e8c25b/32.png) [@KnowZero](https://krita-artists.org/u/KnowZero)\
**Post date:** [September 23, 2021, 2:11pm UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/9 "2021-09-23T14:11:38Z")

</div>

If you want the most reliable way to know if a layer has switched

```auto
layerBox = qwin.findChild(QtWidgets.QDockWidget, "KisLayerBox")
layerList = layerBox.findChild(QtWidgets.QTreeView,"listLayers")

layerList.model().sourceModel().dataChanged.connect(layerChanged)
layerList.model().sourceModel().modelReset.connect(layerChanged)
layerList.model().sourceModel().rowsRemoved.connect(layerChanged)
        

```

But if you want a more simpler way, you can also use a timer

```auto
QtCore.QTimer.singleShot(500, myCommandHere)

```

---

<div class="post-metadata">

**Author:** ![yetanotherpainter](https://krita-artists.org/user_avatar/krita-artists.org/yetanotherpainter/32/31561_2.png) [@yetanotherpainter](https://krita-artists.org/u/yetanotherpainter)\
**Post date:** [September 23, 2021, 2:18pm UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/10 "2021-09-23T14:18:15Z")

</div>

Interesting. I will try this one out.

Hm… I just checked. Theoretically… Could this one be an issue.  
The thing is that I always keep my PC hibernated. And it is indeed can make some application work strangely (I have seen it in other cases). Could be the case with Krita too.

I just checked with virtual machine that started fresh and the code works properly.

---

<div class="post-metadata">

**Author:** ![ruruarchy](https://krita-artists.org/user_avatar/krita-artists.org/ruruarchy/32/60667_2.png) [@ruruarchy](https://krita-artists.org/u/ruruarchy)\
**Post date:** [November 28, 2022, 9:46am UTC](https://krita-artists.org/t/proper-way-to-activate-new-layer/29481/11 "2022-11-28T09:46:41Z")

</div>

heyy 😃 @yetanotherpainter  
based upon @AkiR first codes

> doc.setSelection(newSelection)  
> and  
> view.setForeGroundColor(mColor)

works perfectly, it does make selection and change the foreground color,  
but on my potato laptop sometimes its end up with a blank paint layer like you

after some testing, i guess it was because of the child node didn’t get added first, addChildNode() is likely slower than app.action() and setSelection()

try add QTest.qWait() and setActiveNode() before painting  
it’ll be something lke this :

```
    from PyQt5 import QtTest
    
    app = Krita.instance()
    doc = app.activeDocument()
    root = doc.rootNode()
    view = app.activeWindow().activeView()
    
    layer = doc.createNode("Paint", "paintlayer")
    root.addChildNode(layer, None)
    QtTest.QTest.qWait(100) #___wait 100ms for the child node to be added first

    newSelection = Selection()
    newSelection.select(100, 100, 32, 32, 255)    
    doc.setSelection(newSelection)
    mColor = ManagedColor.fromQColor(QColor(255, 0, 0))
    view.setForeGroundColor(mColor)
    doc.setActiveNode(layer) #___prevent interruption from interrupted by clicking/selecting another layer
    app.action('fill_selection_foreground_color').trigger()

```

or using @ KnowZero suggestion  
it’ll be like this, using additional lambda :

> ```
> app = Krita.instance()
> doc = app.activeDocument()
> root = doc.rootNode()
> view = app.activeWindow().activeView()
>     
> layer = doc.createNode("Paint", "paintlayer")
> root.addChildNode(layer, None)
> QtCore.QTimer.singleShot(100, lambda:self.delayed(app,doc,view,layer)) #___wait 100ms and call func with arguments
> 
> def delayed(self,app,doc,view,layer):
> newSelection = Selection()
> newSelection.select(100, 100, 32, 32, 255)    
> doc.setSelection(newSelection)
> mColor = ManagedColor.fromQColor(QColor(255, 0, 0))
> view.setForeGroundColor(mColor)
> doc.setActiveNode(layer) #___prevent interruption from interrupted by clicking/selecting another layer
> app.action('fill_selection_foreground_color').trigger()
> 
> ```

for me it works, thank you guys for sharing this all 😃 !
