I have been trying to make custom shortcut to set visibility to given layer. For example, I have two layers I work on LAYER_1 however I use LAYER_2 as reference, but sometimes I need to hide LAYER_2 and I want to achieve it by using Keyboard Key rather than clicking. By the help of forum I have made some code, but it does not work. I guess it's something with my toggleLayer
function. It's my first time using PyQt. What I am doing wrong?
from PyQt5.QtWidgets import QWidget, QShortcut, QApplication, QMessageBox
from PyQt5.QtGui import QKeySequence
root = QgsProject.instance().layerTreeRoot()
current = root.findLayer(iface.activeLayer().id())
def setToggleLayer():
current = root.findLayer(iface.activeLayer().id())
def toggleLayer():
new_state = Qt.Checked if current.isVisible() == Qt.Unchecked else Qt.Unchecked
current.setItemVisibilityChecked(new_state)
shortcutSetToggleLayer = QShortcut(QKeySequence(Qt.AltModifier + Qt.Key_K), iface.mainWindow())
shortcutSetToggleLayer.setContext(Qt.ApplicationShortcut)
shortcutSetToggleLayer.activated.connect(setToggleLayer)
shortcutToggleLayer = QShortcut(QKeySequence(Qt.Key_K), iface.mainWindow())
shortcutToggleLayer.setContext(Qt.ApplicationShortcut)
shortcutToggleLayer.activated.connect(toggleLayer)
I've also tried something more brutal to use toggleLayer
:
def toggleLayer():
if root.findLayer(layer.id()).isVisible() == True:
QgsProject.instance().layerTreeRoot().findLayer(currentToggleNode.id()).setItemVisibilityChecked(False)
elif root.findLayer(layer.id()).isVisible() == False:
QgsProject.instance().layerTreeRoot().findLayer(currentToggleNode.id()).setItemVisibilityChecked(True)
But it returns
```
AttributeError: 'QgsLayerTreeLayer' object has no attribute 'id
```
It seems that my programmer skill are too low right now and i am having a lot of problems. I would like to have this plugin to be loaded once and not having to load it by console every now and then. So i decided to load script by plugins panel(ZIP install) and be able to trigger code by using icon to on toolbar. I have managed to do something like this:
from PyQt5.QtWidgets import QAction, QMessageBox
from PyQt5.QtCore import QObject, Qt
from qgis.utils import iface
from qgis.core import QgsProject
def classFactory(iface):
return Hotkeys(iface)
class Hotkeys:
def __init__(self, iface):
self.iface = iface
self.root = QgsProject.instance().layerTreeRoot()
self.current = self.root.findLayer(iface.activeLayer().id())
self.shortcut_choose = "Alt+X"
self.shortcut_toggle = "X"
def initGui(self):
self.action = QAction('HOTKEY', self.iface.mainWindow())
self.action.triggered.connect(self.run)
self.iface.addToolBarIcon(self.action)
def run(self):
self.choose_action = QAction("Choose layer to toggling", iface.mainWindow())
iface.registerMainWindowAction(self.choose_action, self.shortcut_choose)
self.toggle_action = QAction("Toggle layer", iface.mainWindow())
iface.registerMainWindowAction(self.toggle_action, self.shortcut_toggle)
iface.addPluginToMenu("&Additional Hotkeys", self.choose_action)
self.choose_action.triggered.connect(self.choose)
iface.addPluginToMenu("&Additional Hotkeys", self.toggle_action)
self.toggle_action.triggered.connect(self.toggle)
def choose(self):
self.current = self.root.findLayer(iface.activeLayer().id())
def toggle(self):
boolean = Qt.Checked if self.current.isVisible() == Qt.Unchecked else Qt.Unchecked
self.current.setItemVisibilityChecked(boolean)
def unload(self):
self.iface.removeToolBarIcon(self.action)
del self.action
However it loads only when there are load layers in project unless it returns that error:
error:
AttributeError: 'NoneType' object has no attribute 'id'
Traceback (most recent call last):
File "C:/PROGRA~1/QGIS3~1.12/apps/qgis/./python\qgis\utils.py", line 334, in _startPlugin
plugins[packageName] = package.classFactory(iface)
File "C:/Users/Piotr/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\minmal\__init__.py", line 9, in classFactory
return Hotkeys(iface)
File "C:/Users/Piotr/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\minmal\__init__.py", line 17, in __init__
self.current = self.root.findLayer(iface.activeLayer().id())
AttributeError: 'NoneType' object has no attribute 'id'
How to get workaround and make this script loadable even on empty project. I mean right now it's useless because you have load this script every single time on opening project. Plus when you load it once and close qgis, on the next qgis start it will turn off plugin cause it's starting on empty. I guess it's something with active layer selection or getting data from layer root but i am not sure - i am newbie in python qgis.
I just moved root
and current
variables to run method and it works like a charm!