[{"data":1,"prerenderedAt":2079},["ShallowReactive",2],{"doc:\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fadd-custom-dock-widget-pyqgis":3},{"id":4,"title":5,"body":6,"description":2072,"extension":2073,"meta":2074,"navigation":211,"path":2075,"seo":2076,"stem":2077,"__hash__":2078},"docs\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fadd-custom-dock-widget-pyqgis\u002Findex.md","Add a Custom Dock Widget in PyQGIS",{"type":7,"value":8,"toc":2060},"minimark",[9,13,41,57,62,105,109,127,752,785,789,810,1047,1091,1095,1108,1495,1523,1527,1544,1721,1747,1751,1754,1844,1854,1858,1880,1892,1911,1926,1939,1943,1975,1979,1988,2002,2022,2038,2042,2056],[10,11,5],"h1",{"id":12},"add-a-custom-dock-widget-in-pyqgis",[14,15,16,17,21,22,24,25,28,29,32,33,36,37,40],"p",{},"A dock widget is the right container for any plugin tool that should stay visible while the user works — a layer inspector, a live query panel, a styling controller. Unlike a modal dialog that interrupts the workflow, a ",[18,19,20],"code",{},"QDockWidget"," snaps into the QGIS window alongside the Layers and Browser panels, can be moved, floated, or hidden, and persists across the session. This page builds one two ways — by subclassing ",[18,23,20],{}," directly and by loading a Qt Designer ",[18,26,27],{},".ui"," with ",[18,30,31],{},"uic.loadUiType"," — embeds GIS-aware widgets inside it, docks it with ",[18,34,35],{},"addDockWidget",", remembers its visibility between sessions, and removes it cleanly in ",[18,38,39],{},"unload()",".",[14,42,43,44,49,50,52,53,40],{},"This task belongs to ",[45,46,48],"a",{"href":47},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002F","Qt Designer for GIS Interfaces",", which covers the broader ",[18,51,27],{}," workflow. A dock widget is typically opened by a toolbar control, so it pairs naturally with ",[45,54,56],{"href":55},"\u002Fqgis-plugin-development\u002Fplugin-boilerplate-structure\u002Fadd-toolbar-button-to-qgis-plugin\u002F","Add a Toolbar Button to a QGIS Plugin",[58,59,61],"h2",{"id":60},"prerequisites","Prerequisites",[63,64,65,73,92,99],"ul",{},[66,67,68,72],"li",{},[69,70,71],"strong",{},"QGIS 3.34 LTR"," (Python 3.12) with the Python console available",[66,74,75,76,79,80,83,84,86,87,91],{},"A plugin skeleton with a main class that receives ",[18,77,78],{},"iface"," and implements ",[18,81,82],{},"initGui()"," \u002F ",[18,85,39],{}," — generate one with ",[45,88,90],{"href":89},"\u002Fqgis-plugin-development\u002Fplugin-boilerplate-structure\u002Fcreate-qgis-plugin-with-plugin-builder\u002F","Create a QGIS Plugin with Plugin Builder 3"," if needed",[66,93,94,95,98],{},"Basic Qt layout knowledge (",[18,96,97],{},"QVBoxLayout",", signal\u002Fslot connections)",[66,100,101,102,104],{},"For the ",[18,103,27],{}," approach, Qt Designer installed and widget promotion understood",[58,106,108],{"id":107},"approach-a-subclass-qdockwidget-directly","Approach A: Subclass QDockWidget Directly",[14,110,111,112,114,115,118,119,122,123,126],{},"For a panel with a handful of controls, writing the widget in Python avoids a ",[18,113,27],{}," round-trip. Build a ",[18,116,117],{},"QWidget"," content area, lay it out, and set it as the dock's content. Embedding ",[18,120,121],{},"QgsMapLayerComboBox"," and ",[18,124,125],{},"QgsFieldComboBox"," gives users the same layer and field pickers QGIS uses natively.",[128,129,134],"pre",{"className":130,"code":131,"language":132,"meta":133,"style":133},"language-python shiki shiki-themes github-dark","from qgis.PyQt.QtCore import Qt, pyqtSignal\nfrom qgis.PyQt.QtWidgets import (\n    QDockWidget, QWidget, QVBoxLayout, QLabel, QPushButton,\n)\nfrom qgis.gui import QgsMapLayerComboBox, QgsFieldComboBox\nfrom qgis.core import QgsMapLayerProxyModel\n\n\nclass LayerInspectorDock(QDockWidget):\n    \"\"\"A dockable panel that reports feature counts for a chosen field.\"\"\"\n\n    closingPlugin = pyqtSignal()\n\n    def __init__(self, iface, parent=None):\n        super().__init__(\"Layer Inspector\", parent)\n        self.iface = iface\n        self.setObjectName(\"LayerInspectorDock\")  # needed to persist state\n\n        content = QWidget(self)\n        layout = QVBoxLayout(content)\n\n        layout.addWidget(QLabel(\"Layer\"))\n        self.layer_combo = QgsMapLayerComboBox()\n        self.layer_combo.setFilters(QgsMapLayerProxyModel.VectorLayer)\n        layout.addWidget(self.layer_combo)\n\n        layout.addWidget(QLabel(\"Field\"))\n        self.field_combo = QgsFieldComboBox()\n        layout.addWidget(self.field_combo)\n\n        self.count_button = QPushButton(\"Count distinct values\")\n        layout.addWidget(self.count_button)\n        self.result = QLabel(\"--\")\n        layout.addWidget(self.result)\n        layout.addStretch()\n\n        self.setWidget(content)\n\n        # Keep the field combo in sync with the selected layer\n        self.layer_combo.layerChanged.connect(self.field_combo.setLayer)\n        self.field_combo.setLayer(self.layer_combo.currentLayer())\n        self.count_button.clicked.connect(self._count)\n\n    def _count(self):\n        layer = self.layer_combo.currentLayer()\n        field = self.field_combo.currentField()\n        if layer is None or not field:\n            self.result.setText(\"Pick a layer and field\")\n            return\n        idx = layer.fields().indexOf(field)\n        distinct = layer.uniqueValues(idx)\n        self.result.setText(f\"{len(distinct)} distinct values\")\n\n    def closeEvent(self, event):\n        self.closingPlugin.emit()\n        event.accept()\n","python","",[18,135,136,155,168,174,180,193,206,213,218,236,243,248,260,265,285,305,319,337,342,358,369,374,386,399,407,418,423,433,446,456,461,479,489,507,517,523,528,536,541,547,560,573,586,591,602,616,629,653,667,673,684,695,722,727,738,746],{"__ignoreMap":133},[137,138,141,145,149,152],"span",{"class":139,"line":140},"line",1,[137,142,144],{"class":143},"snl16","from",[137,146,148],{"class":147},"s95oV"," qgis.PyQt.QtCore ",[137,150,151],{"class":143},"import",[137,153,154],{"class":147}," Qt, pyqtSignal\n",[137,156,158,160,163,165],{"class":139,"line":157},2,[137,159,144],{"class":143},[137,161,162],{"class":147}," qgis.PyQt.QtWidgets ",[137,164,151],{"class":143},[137,166,167],{"class":147}," (\n",[137,169,171],{"class":139,"line":170},3,[137,172,173],{"class":147},"    QDockWidget, QWidget, QVBoxLayout, QLabel, QPushButton,\n",[137,175,177],{"class":139,"line":176},4,[137,178,179],{"class":147},")\n",[137,181,183,185,188,190],{"class":139,"line":182},5,[137,184,144],{"class":143},[137,186,187],{"class":147}," qgis.gui ",[137,189,151],{"class":143},[137,191,192],{"class":147}," QgsMapLayerComboBox, QgsFieldComboBox\n",[137,194,196,198,201,203],{"class":139,"line":195},6,[137,197,144],{"class":143},[137,199,200],{"class":147}," qgis.core ",[137,202,151],{"class":143},[137,204,205],{"class":147}," QgsMapLayerProxyModel\n",[137,207,209],{"class":139,"line":208},7,[137,210,212],{"emptyLinePlaceholder":211},true,"\n",[137,214,216],{"class":139,"line":215},8,[137,217,212],{"emptyLinePlaceholder":211},[137,219,221,224,228,231,233],{"class":139,"line":220},9,[137,222,223],{"class":143},"class",[137,225,227],{"class":226},"svObZ"," LayerInspectorDock",[137,229,230],{"class":147},"(",[137,232,20],{"class":226},[137,234,235],{"class":147},"):\n",[137,237,239],{"class":139,"line":238},10,[137,240,242],{"class":241},"sU2Wk","    \"\"\"A dockable panel that reports feature counts for a chosen field.\"\"\"\n",[137,244,246],{"class":139,"line":245},11,[137,247,212],{"emptyLinePlaceholder":211},[137,249,251,254,257],{"class":139,"line":250},12,[137,252,253],{"class":147},"    closingPlugin ",[137,255,256],{"class":143},"=",[137,258,259],{"class":147}," pyqtSignal()\n",[137,261,263],{"class":139,"line":262},13,[137,264,212],{"emptyLinePlaceholder":211},[137,266,268,271,275,278,280,283],{"class":139,"line":267},14,[137,269,270],{"class":143},"    def",[137,272,274],{"class":273},"sDLfK"," __init__",[137,276,277],{"class":147},"(self, iface, parent",[137,279,256],{"class":143},[137,281,282],{"class":273},"None",[137,284,235],{"class":147},[137,286,288,291,294,297,299,302],{"class":139,"line":287},15,[137,289,290],{"class":273},"        super",[137,292,293],{"class":147},"().",[137,295,296],{"class":273},"__init__",[137,298,230],{"class":147},[137,300,301],{"class":241},"\"Layer Inspector\"",[137,303,304],{"class":147},", parent)\n",[137,306,308,311,314,316],{"class":139,"line":307},16,[137,309,310],{"class":273},"        self",[137,312,313],{"class":147},".iface ",[137,315,256],{"class":143},[137,317,318],{"class":147}," iface\n",[137,320,322,324,327,330,333],{"class":139,"line":321},17,[137,323,310],{"class":273},[137,325,326],{"class":147},".setObjectName(",[137,328,329],{"class":241},"\"LayerInspectorDock\"",[137,331,332],{"class":147},")  ",[137,334,336],{"class":335},"sAwPA","# needed to persist state\n",[137,338,340],{"class":139,"line":339},18,[137,341,212],{"emptyLinePlaceholder":211},[137,343,345,348,350,353,356],{"class":139,"line":344},19,[137,346,347],{"class":147},"        content ",[137,349,256],{"class":143},[137,351,352],{"class":147}," QWidget(",[137,354,355],{"class":273},"self",[137,357,179],{"class":147},[137,359,361,364,366],{"class":139,"line":360},20,[137,362,363],{"class":147},"        layout ",[137,365,256],{"class":143},[137,367,368],{"class":147}," QVBoxLayout(content)\n",[137,370,372],{"class":139,"line":371},21,[137,373,212],{"emptyLinePlaceholder":211},[137,375,377,380,383],{"class":139,"line":376},22,[137,378,379],{"class":147},"        layout.addWidget(QLabel(",[137,381,382],{"class":241},"\"Layer\"",[137,384,385],{"class":147},"))\n",[137,387,389,391,394,396],{"class":139,"line":388},23,[137,390,310],{"class":273},[137,392,393],{"class":147},".layer_combo ",[137,395,256],{"class":143},[137,397,398],{"class":147}," QgsMapLayerComboBox()\n",[137,400,402,404],{"class":139,"line":401},24,[137,403,310],{"class":273},[137,405,406],{"class":147},".layer_combo.setFilters(QgsMapLayerProxyModel.VectorLayer)\n",[137,408,410,413,415],{"class":139,"line":409},25,[137,411,412],{"class":147},"        layout.addWidget(",[137,414,355],{"class":273},[137,416,417],{"class":147},".layer_combo)\n",[137,419,421],{"class":139,"line":420},26,[137,422,212],{"emptyLinePlaceholder":211},[137,424,426,428,431],{"class":139,"line":425},27,[137,427,379],{"class":147},[137,429,430],{"class":241},"\"Field\"",[137,432,385],{"class":147},[137,434,436,438,441,443],{"class":139,"line":435},28,[137,437,310],{"class":273},[137,439,440],{"class":147},".field_combo ",[137,442,256],{"class":143},[137,444,445],{"class":147}," QgsFieldComboBox()\n",[137,447,449,451,453],{"class":139,"line":448},29,[137,450,412],{"class":147},[137,452,355],{"class":273},[137,454,455],{"class":147},".field_combo)\n",[137,457,459],{"class":139,"line":458},30,[137,460,212],{"emptyLinePlaceholder":211},[137,462,464,466,469,471,474,477],{"class":139,"line":463},31,[137,465,310],{"class":273},[137,467,468],{"class":147},".count_button ",[137,470,256],{"class":143},[137,472,473],{"class":147}," QPushButton(",[137,475,476],{"class":241},"\"Count distinct values\"",[137,478,179],{"class":147},[137,480,482,484,486],{"class":139,"line":481},32,[137,483,412],{"class":147},[137,485,355],{"class":273},[137,487,488],{"class":147},".count_button)\n",[137,490,492,494,497,499,502,505],{"class":139,"line":491},33,[137,493,310],{"class":273},[137,495,496],{"class":147},".result ",[137,498,256],{"class":143},[137,500,501],{"class":147}," QLabel(",[137,503,504],{"class":241},"\"--\"",[137,506,179],{"class":147},[137,508,510,512,514],{"class":139,"line":509},34,[137,511,412],{"class":147},[137,513,355],{"class":273},[137,515,516],{"class":147},".result)\n",[137,518,520],{"class":139,"line":519},35,[137,521,522],{"class":147},"        layout.addStretch()\n",[137,524,526],{"class":139,"line":525},36,[137,527,212],{"emptyLinePlaceholder":211},[137,529,531,533],{"class":139,"line":530},37,[137,532,310],{"class":273},[137,534,535],{"class":147},".setWidget(content)\n",[137,537,539],{"class":139,"line":538},38,[137,540,212],{"emptyLinePlaceholder":211},[137,542,544],{"class":139,"line":543},39,[137,545,546],{"class":335},"        # Keep the field combo in sync with the selected layer\n",[137,548,550,552,555,557],{"class":139,"line":549},40,[137,551,310],{"class":273},[137,553,554],{"class":147},".layer_combo.layerChanged.connect(",[137,556,355],{"class":273},[137,558,559],{"class":147},".field_combo.setLayer)\n",[137,561,563,565,568,570],{"class":139,"line":562},41,[137,564,310],{"class":273},[137,566,567],{"class":147},".field_combo.setLayer(",[137,569,355],{"class":273},[137,571,572],{"class":147},".layer_combo.currentLayer())\n",[137,574,576,578,581,583],{"class":139,"line":575},42,[137,577,310],{"class":273},[137,579,580],{"class":147},".count_button.clicked.connect(",[137,582,355],{"class":273},[137,584,585],{"class":147},"._count)\n",[137,587,589],{"class":139,"line":588},43,[137,590,212],{"emptyLinePlaceholder":211},[137,592,594,596,599],{"class":139,"line":593},44,[137,595,270],{"class":143},[137,597,598],{"class":226}," _count",[137,600,601],{"class":147},"(self):\n",[137,603,605,608,610,613],{"class":139,"line":604},45,[137,606,607],{"class":147},"        layer ",[137,609,256],{"class":143},[137,611,612],{"class":273}," self",[137,614,615],{"class":147},".layer_combo.currentLayer()\n",[137,617,619,622,624,626],{"class":139,"line":618},46,[137,620,621],{"class":147},"        field ",[137,623,256],{"class":143},[137,625,612],{"class":273},[137,627,628],{"class":147},".field_combo.currentField()\n",[137,630,632,635,638,641,644,647,650],{"class":139,"line":631},47,[137,633,634],{"class":143},"        if",[137,636,637],{"class":147}," layer ",[137,639,640],{"class":143},"is",[137,642,643],{"class":273}," None",[137,645,646],{"class":143}," or",[137,648,649],{"class":143}," not",[137,651,652],{"class":147}," field:\n",[137,654,656,659,662,665],{"class":139,"line":655},48,[137,657,658],{"class":273},"            self",[137,660,661],{"class":147},".result.setText(",[137,663,664],{"class":241},"\"Pick a layer and field\"",[137,666,179],{"class":147},[137,668,670],{"class":139,"line":669},49,[137,671,672],{"class":143},"            return\n",[137,674,676,679,681],{"class":139,"line":675},50,[137,677,678],{"class":147},"        idx ",[137,680,256],{"class":143},[137,682,683],{"class":147}," layer.fields().indexOf(field)\n",[137,685,687,690,692],{"class":139,"line":686},51,[137,688,689],{"class":147},"        distinct ",[137,691,256],{"class":143},[137,693,694],{"class":147}," layer.uniqueValues(idx)\n",[137,696,698,700,702,705,708,711,714,717,720],{"class":139,"line":697},52,[137,699,310],{"class":273},[137,701,661],{"class":147},[137,703,704],{"class":143},"f",[137,706,707],{"class":241},"\"",[137,709,710],{"class":273},"{len",[137,712,713],{"class":147},"(distinct)",[137,715,716],{"class":273},"}",[137,718,719],{"class":241}," distinct values\"",[137,721,179],{"class":147},[137,723,725],{"class":139,"line":724},53,[137,726,212],{"emptyLinePlaceholder":211},[137,728,730,732,735],{"class":139,"line":729},54,[137,731,270],{"class":143},[137,733,734],{"class":226}," closeEvent",[137,736,737],{"class":147},"(self, event):\n",[137,739,741,743],{"class":139,"line":740},55,[137,742,310],{"class":273},[137,744,745],{"class":147},".closingPlugin.emit()\n",[137,747,749],{"class":139,"line":748},56,[137,750,751],{"class":147},"        event.accept()\n",[14,753,754,757,758,760,761,764,765,768,769,772,773,776,777,780,781,784],{},[69,755,756],{},"Breakdown:"," The dock title (",[18,759,301],{},") appears on the panel's title bar. ",[18,762,763],{},"setObjectName"," is mandatory for QGIS to save and restore the dock's position. ",[18,766,767],{},"QgsMapLayerComboBox.setFilters(QgsMapLayerProxyModel.VectorLayer)"," limits the picker to vector layers; its ",[18,770,771],{},"layerChanged"," signal feeds ",[18,774,775],{},"QgsFieldComboBox.setLayer",", so the field list always reflects the chosen layer's schema. ",[18,778,779],{},"layer.uniqueValues(index)"," returns the set of distinct values for the field. The custom ",[18,782,783],{},"closingPlugin"," signal lets the host plugin react when the user clicks the dock's close button, which is how we keep the toolbar toggle in sync below.",[58,786,788],{"id":787},"approach-b-load-a-ui-file-with-uicloaduitype","Approach B: Load a .ui File with uic.loadUiType",[14,790,791,792,795,796,798,799,802,803,805,806,809],{},"When the panel grows or a designer maintains the layout, build it in Qt Designer from the ",[69,793,794],{},"Dock Widget"," template and load it at runtime. Promote the layer and field pickers in Designer (",[18,797,121],{}," → header ",[18,800,801],{},"qgsmaplayercombobox.h","; ",[18,804,125],{}," → ",[18,807,808],{},"qgsfieldcombobox.h",") so the same widgets appear without manual instantiation.",[128,811,813],{"className":130,"code":812,"language":132,"meta":133,"style":133},"import os\nfrom qgis.PyQt import uic\nfrom qgis.PyQt.QtCore import pyqtSignal\nfrom qgis.core import QgsMapLayerProxyModel\n\nFORM_CLASS, _ = uic.loadUiType(\n    os.path.join(os.path.dirname(__file__), \"ui\", \"inspector_dock_base.ui\")\n)\n\n\nclass LayerInspectorDock(FORM_CLASS):\n    \"\"\"Dock widget whose layout comes from a Qt Designer .ui file.\"\"\"\n\n    closingPlugin = pyqtSignal()\n\n    def __init__(self, iface, parent=None):\n        super().__init__(parent)\n        self.setupUi(self)\n        self.iface = iface\n\n        # Widgets below are defined and promoted in the .ui file\n        self.mLayerCombo.setFilters(QgsMapLayerProxyModel.VectorLayer)\n        self.mLayerCombo.layerChanged.connect(self.mFieldCombo.setLayer)\n        self.mFieldCombo.setLayer(self.mLayerCombo.currentLayer())\n\n    def closeEvent(self, event):\n        self.closingPlugin.emit()\n        event.accept()\n",[18,814,815,822,834,845,855,859,872,894,898,902,906,918,923,927,935,939,953,964,975,985,989,994,1001,1013,1025,1029,1037,1043],{"__ignoreMap":133},[137,816,817,819],{"class":139,"line":140},[137,818,151],{"class":143},[137,820,821],{"class":147}," os\n",[137,823,824,826,829,831],{"class":139,"line":157},[137,825,144],{"class":143},[137,827,828],{"class":147}," qgis.PyQt ",[137,830,151],{"class":143},[137,832,833],{"class":147}," uic\n",[137,835,836,838,840,842],{"class":139,"line":170},[137,837,144],{"class":143},[137,839,148],{"class":147},[137,841,151],{"class":143},[137,843,844],{"class":147}," pyqtSignal\n",[137,846,847,849,851,853],{"class":139,"line":176},[137,848,144],{"class":143},[137,850,200],{"class":147},[137,852,151],{"class":143},[137,854,205],{"class":147},[137,856,857],{"class":139,"line":182},[137,858,212],{"emptyLinePlaceholder":211},[137,860,861,864,867,869],{"class":139,"line":195},[137,862,863],{"class":273},"FORM_CLASS",[137,865,866],{"class":147},", _ ",[137,868,256],{"class":143},[137,870,871],{"class":147}," uic.loadUiType(\n",[137,873,874,877,880,883,886,889,892],{"class":139,"line":208},[137,875,876],{"class":147},"    os.path.join(os.path.dirname(",[137,878,879],{"class":273},"__file__",[137,881,882],{"class":147},"), ",[137,884,885],{"class":241},"\"ui\"",[137,887,888],{"class":147},", ",[137,890,891],{"class":241},"\"inspector_dock_base.ui\"",[137,893,179],{"class":147},[137,895,896],{"class":139,"line":215},[137,897,179],{"class":147},[137,899,900],{"class":139,"line":220},[137,901,212],{"emptyLinePlaceholder":211},[137,903,904],{"class":139,"line":238},[137,905,212],{"emptyLinePlaceholder":211},[137,907,908,910,912,914,916],{"class":139,"line":245},[137,909,223],{"class":143},[137,911,227],{"class":226},[137,913,230],{"class":147},[137,915,863],{"class":273},[137,917,235],{"class":147},[137,919,920],{"class":139,"line":250},[137,921,922],{"class":241},"    \"\"\"Dock widget whose layout comes from a Qt Designer .ui file.\"\"\"\n",[137,924,925],{"class":139,"line":262},[137,926,212],{"emptyLinePlaceholder":211},[137,928,929,931,933],{"class":139,"line":267},[137,930,253],{"class":147},[137,932,256],{"class":143},[137,934,259],{"class":147},[137,936,937],{"class":139,"line":287},[137,938,212],{"emptyLinePlaceholder":211},[137,940,941,943,945,947,949,951],{"class":139,"line":307},[137,942,270],{"class":143},[137,944,274],{"class":273},[137,946,277],{"class":147},[137,948,256],{"class":143},[137,950,282],{"class":273},[137,952,235],{"class":147},[137,954,955,957,959,961],{"class":139,"line":321},[137,956,290],{"class":273},[137,958,293],{"class":147},[137,960,296],{"class":273},[137,962,963],{"class":147},"(parent)\n",[137,965,966,968,971,973],{"class":139,"line":339},[137,967,310],{"class":273},[137,969,970],{"class":147},".setupUi(",[137,972,355],{"class":273},[137,974,179],{"class":147},[137,976,977,979,981,983],{"class":139,"line":344},[137,978,310],{"class":273},[137,980,313],{"class":147},[137,982,256],{"class":143},[137,984,318],{"class":147},[137,986,987],{"class":139,"line":360},[137,988,212],{"emptyLinePlaceholder":211},[137,990,991],{"class":139,"line":371},[137,992,993],{"class":335},"        # Widgets below are defined and promoted in the .ui file\n",[137,995,996,998],{"class":139,"line":376},[137,997,310],{"class":273},[137,999,1000],{"class":147},".mLayerCombo.setFilters(QgsMapLayerProxyModel.VectorLayer)\n",[137,1002,1003,1005,1008,1010],{"class":139,"line":388},[137,1004,310],{"class":273},[137,1006,1007],{"class":147},".mLayerCombo.layerChanged.connect(",[137,1009,355],{"class":273},[137,1011,1012],{"class":147},".mFieldCombo.setLayer)\n",[137,1014,1015,1017,1020,1022],{"class":139,"line":401},[137,1016,310],{"class":273},[137,1018,1019],{"class":147},".mFieldCombo.setLayer(",[137,1021,355],{"class":273},[137,1023,1024],{"class":147},".mLayerCombo.currentLayer())\n",[137,1026,1027],{"class":139,"line":409},[137,1028,212],{"emptyLinePlaceholder":211},[137,1030,1031,1033,1035],{"class":139,"line":420},[137,1032,270],{"class":143},[137,1034,734],{"class":226},[137,1036,737],{"class":147},[137,1038,1039,1041],{"class":139,"line":425},[137,1040,310],{"class":273},[137,1042,745],{"class":147},[137,1044,1045],{"class":139,"line":435},[137,1046,751],{"class":147},[14,1048,1049,1051,1052,1055,1056,1058,1059,1061,1062,1065,1066,1069,1070,1073,1074,888,1077,1080,1081,1084,1085,1087,1088,1090],{},[69,1050,756],{}," ",[18,1053,1054],{},"uic.loadUiType()"," parses the ",[18,1057,27],{}," XML once at import time and returns a base class — for a Dock Widget template that base is already a ",[18,1060,20],{},", so the subclass ",[1063,1064,640],"em",{}," a dock. ",[18,1067,1068],{},"setupUi(self)"," instantiates every widget defined in Designer and attaches it as an attribute named after its ",[18,1071,1072],{},"objectName"," (",[18,1075,1076],{},"mLayerCombo",[18,1078,1079],{},"mFieldCombo","). Runtime loading sidesteps ",[18,1082,1083],{},"pyuic5"," version mismatches, which is why it is preferred over static compilation; the trade-off is that the ",[18,1086,27],{}," file must ship inside the plugin. Notice there is no ",[18,1089,763],{}," call here — set it on the dock in Designer's property editor instead.",[58,1092,1094],{"id":1093},"docking-toggling-and-removing-on-unload","Docking, Toggling, and Removing on Unload",[14,1096,1097,1098,1100,1101,1103,1104,1107],{},"The main plugin class owns the dock's lifecycle. Add it with ",[18,1099,35],{},", expose a checkable toolbar action to show or hide it, and remove it in ",[18,1102,39],{},". The dock's ",[18,1105,1106],{},"visibilityChanged"," signal keeps the toolbar toggle accurate when the user closes the panel manually.",[128,1109,1111],{"className":130,"code":1110,"language":132,"meta":133,"style":133},"from qgis.PyQt.QtCore import Qt\nfrom qgis.PyQt.QtGui import QIcon\nfrom qgis.PyQt.QtWidgets import QAction\n\n\nclass InspectorPlugin:\n    def __init__(self, iface):\n        self.iface = iface\n        self.dock = None\n        self.action = None\n\n    def initGui(self):\n        self.action = QAction(QIcon(), \"Layer Inspector\", self.iface.mainWindow())\n        self.action.setCheckable(True)\n        self.action.toggled.connect(self.toggle_dock)\n        self.iface.addToolBarIcon(self.action)\n\n    def toggle_dock(self, checked):\n        if checked and self.dock is None:\n            self.dock = LayerInspectorDock(self.iface, self.iface.mainWindow())\n            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock)\n            self.dock.closingPlugin.connect(lambda: self.action.setChecked(False))\n            self.dock.visibilityChanged.connect(self.action.setChecked)\n        elif self.dock is not None:\n            self.dock.setVisible(checked)\n\n    def unload(self):\n        if self.dock is not None:\n            self.iface.removeDockWidget(self.dock)\n            self.dock.deleteLater()\n            self.dock = None\n        if self.action is not None:\n            self.iface.removeToolBarIcon(self.action)\n            self.action = None\n",[18,1112,1113,1124,1136,1147,1151,1155,1165,1174,1184,1196,1207,1211,1220,1240,1252,1264,1276,1280,1290,1310,1330,1342,1365,1377,1394,1401,1405,1414,1430,1441,1448,1458,1474,1485],{"__ignoreMap":133},[137,1114,1115,1117,1119,1121],{"class":139,"line":140},[137,1116,144],{"class":143},[137,1118,148],{"class":147},[137,1120,151],{"class":143},[137,1122,1123],{"class":147}," Qt\n",[137,1125,1126,1128,1131,1133],{"class":139,"line":157},[137,1127,144],{"class":143},[137,1129,1130],{"class":147}," qgis.PyQt.QtGui ",[137,1132,151],{"class":143},[137,1134,1135],{"class":147}," QIcon\n",[137,1137,1138,1140,1142,1144],{"class":139,"line":170},[137,1139,144],{"class":143},[137,1141,162],{"class":147},[137,1143,151],{"class":143},[137,1145,1146],{"class":147}," QAction\n",[137,1148,1149],{"class":139,"line":176},[137,1150,212],{"emptyLinePlaceholder":211},[137,1152,1153],{"class":139,"line":182},[137,1154,212],{"emptyLinePlaceholder":211},[137,1156,1157,1159,1162],{"class":139,"line":195},[137,1158,223],{"class":143},[137,1160,1161],{"class":226}," InspectorPlugin",[137,1163,1164],{"class":147},":\n",[137,1166,1167,1169,1171],{"class":139,"line":208},[137,1168,270],{"class":143},[137,1170,274],{"class":273},[137,1172,1173],{"class":147},"(self, iface):\n",[137,1175,1176,1178,1180,1182],{"class":139,"line":215},[137,1177,310],{"class":273},[137,1179,313],{"class":147},[137,1181,256],{"class":143},[137,1183,318],{"class":147},[137,1185,1186,1188,1191,1193],{"class":139,"line":220},[137,1187,310],{"class":273},[137,1189,1190],{"class":147},".dock ",[137,1192,256],{"class":143},[137,1194,1195],{"class":273}," None\n",[137,1197,1198,1200,1203,1205],{"class":139,"line":238},[137,1199,310],{"class":273},[137,1201,1202],{"class":147},".action ",[137,1204,256],{"class":143},[137,1206,1195],{"class":273},[137,1208,1209],{"class":139,"line":245},[137,1210,212],{"emptyLinePlaceholder":211},[137,1212,1213,1215,1218],{"class":139,"line":250},[137,1214,270],{"class":143},[137,1216,1217],{"class":226}," initGui",[137,1219,601],{"class":147},[137,1221,1222,1224,1226,1228,1231,1233,1235,1237],{"class":139,"line":262},[137,1223,310],{"class":273},[137,1225,1202],{"class":147},[137,1227,256],{"class":143},[137,1229,1230],{"class":147}," QAction(QIcon(), ",[137,1232,301],{"class":241},[137,1234,888],{"class":147},[137,1236,355],{"class":273},[137,1238,1239],{"class":147},".iface.mainWindow())\n",[137,1241,1242,1244,1247,1250],{"class":139,"line":267},[137,1243,310],{"class":273},[137,1245,1246],{"class":147},".action.setCheckable(",[137,1248,1249],{"class":273},"True",[137,1251,179],{"class":147},[137,1253,1254,1256,1259,1261],{"class":139,"line":287},[137,1255,310],{"class":273},[137,1257,1258],{"class":147},".action.toggled.connect(",[137,1260,355],{"class":273},[137,1262,1263],{"class":147},".toggle_dock)\n",[137,1265,1266,1268,1271,1273],{"class":139,"line":307},[137,1267,310],{"class":273},[137,1269,1270],{"class":147},".iface.addToolBarIcon(",[137,1272,355],{"class":273},[137,1274,1275],{"class":147},".action)\n",[137,1277,1278],{"class":139,"line":321},[137,1279,212],{"emptyLinePlaceholder":211},[137,1281,1282,1284,1287],{"class":139,"line":339},[137,1283,270],{"class":143},[137,1285,1286],{"class":226}," toggle_dock",[137,1288,1289],{"class":147},"(self, checked):\n",[137,1291,1292,1294,1297,1300,1302,1304,1306,1308],{"class":139,"line":344},[137,1293,634],{"class":143},[137,1295,1296],{"class":147}," checked ",[137,1298,1299],{"class":143},"and",[137,1301,612],{"class":273},[137,1303,1190],{"class":147},[137,1305,640],{"class":143},[137,1307,643],{"class":273},[137,1309,1164],{"class":147},[137,1311,1312,1314,1316,1318,1321,1323,1326,1328],{"class":139,"line":360},[137,1313,658],{"class":273},[137,1315,1190],{"class":147},[137,1317,256],{"class":143},[137,1319,1320],{"class":147}," LayerInspectorDock(",[137,1322,355],{"class":273},[137,1324,1325],{"class":147},".iface, ",[137,1327,355],{"class":273},[137,1329,1239],{"class":147},[137,1331,1332,1334,1337,1339],{"class":139,"line":371},[137,1333,658],{"class":273},[137,1335,1336],{"class":147},".iface.addDockWidget(Qt.RightDockWidgetArea, ",[137,1338,355],{"class":273},[137,1340,1341],{"class":147},".dock)\n",[137,1343,1344,1346,1349,1352,1355,1357,1360,1363],{"class":139,"line":376},[137,1345,658],{"class":273},[137,1347,1348],{"class":147},".dock.closingPlugin.connect(",[137,1350,1351],{"class":143},"lambda",[137,1353,1354],{"class":147},": ",[137,1356,355],{"class":273},[137,1358,1359],{"class":147},".action.setChecked(",[137,1361,1362],{"class":273},"False",[137,1364,385],{"class":147},[137,1366,1367,1369,1372,1374],{"class":139,"line":388},[137,1368,658],{"class":273},[137,1370,1371],{"class":147},".dock.visibilityChanged.connect(",[137,1373,355],{"class":273},[137,1375,1376],{"class":147},".action.setChecked)\n",[137,1378,1379,1382,1384,1386,1388,1390,1392],{"class":139,"line":401},[137,1380,1381],{"class":143},"        elif",[137,1383,612],{"class":273},[137,1385,1190],{"class":147},[137,1387,640],{"class":143},[137,1389,649],{"class":143},[137,1391,643],{"class":273},[137,1393,1164],{"class":147},[137,1395,1396,1398],{"class":139,"line":409},[137,1397,658],{"class":273},[137,1399,1400],{"class":147},".dock.setVisible(checked)\n",[137,1402,1403],{"class":139,"line":420},[137,1404,212],{"emptyLinePlaceholder":211},[137,1406,1407,1409,1412],{"class":139,"line":425},[137,1408,270],{"class":143},[137,1410,1411],{"class":226}," unload",[137,1413,601],{"class":147},[137,1415,1416,1418,1420,1422,1424,1426,1428],{"class":139,"line":435},[137,1417,634],{"class":143},[137,1419,612],{"class":273},[137,1421,1190],{"class":147},[137,1423,640],{"class":143},[137,1425,649],{"class":143},[137,1427,643],{"class":273},[137,1429,1164],{"class":147},[137,1431,1432,1434,1437,1439],{"class":139,"line":448},[137,1433,658],{"class":273},[137,1435,1436],{"class":147},".iface.removeDockWidget(",[137,1438,355],{"class":273},[137,1440,1341],{"class":147},[137,1442,1443,1445],{"class":139,"line":458},[137,1444,658],{"class":273},[137,1446,1447],{"class":147},".dock.deleteLater()\n",[137,1449,1450,1452,1454,1456],{"class":139,"line":463},[137,1451,658],{"class":273},[137,1453,1190],{"class":147},[137,1455,256],{"class":143},[137,1457,1195],{"class":273},[137,1459,1460,1462,1464,1466,1468,1470,1472],{"class":139,"line":481},[137,1461,634],{"class":143},[137,1463,612],{"class":273},[137,1465,1202],{"class":147},[137,1467,640],{"class":143},[137,1469,649],{"class":143},[137,1471,643],{"class":273},[137,1473,1164],{"class":147},[137,1475,1476,1478,1481,1483],{"class":139,"line":491},[137,1477,658],{"class":273},[137,1479,1480],{"class":147},".iface.removeToolBarIcon(",[137,1482,355],{"class":273},[137,1484,1275],{"class":147},[137,1486,1487,1489,1491,1493],{"class":139,"line":509},[137,1488,658],{"class":273},[137,1490,1202],{"class":147},[137,1492,256],{"class":143},[137,1494,1195],{"class":273},[14,1496,1497,1051,1499,1502,1503,1505,1506,1509,1510,1512,1513,888,1515,1518,1519,1522],{},[69,1498,756],{},[18,1500,1501],{},"addDockWidget(Qt.RightDockWidgetArea, dock)"," snaps the panel into the right-hand dock area, beside Layers and Browser; users can drag it anywhere afterward. The dock is created lazily on first activation so a disabled feature costs nothing. Connecting ",[18,1504,1106],{}," to ",[18,1507,1508],{},"action.setChecked"," keeps the toolbar button's pressed state in lockstep with the panel — including when the user clicks the panel's close X, which also fires our ",[18,1511,783],{}," signal. In ",[18,1514,39],{},[18,1516,1517],{},"removeDockWidget"," detaches the panel from the main window and ",[18,1520,1521],{},"deleteLater()"," schedules its Qt-side destruction; skipping either leaves a stranded panel after the plugin is disabled.",[58,1524,1526],{"id":1525},"persisting-visibility-across-sessions","Persisting Visibility Across Sessions",[14,1528,1529,1530,1533,1534,1536,1537,1540,1541,1543],{},"QGIS restores a dock's ",[1063,1531,1532],{},"position"," automatically once ",[18,1535,763],{}," is set, but not whether your plugin should recreate it on the next launch. Use ",[18,1538,1539],{},"QSettings"," to remember the user's preference and reopen the dock during ",[18,1542,82],{}," if it was open last time.",[128,1545,1547],{"className":130,"code":1546,"language":132,"meta":133,"style":133},"from qgis.PyQt.QtCore import QSettings\n\nSETTINGS_KEY = \"InspectorPlugin\u002FdockVisible\"\n\n\ndef initGui(self):\n    self.action = QAction(QIcon(), \"Layer Inspector\", self.iface.mainWindow())\n    self.action.setCheckable(True)\n    self.action.toggled.connect(self.toggle_dock)\n    self.iface.addToolBarIcon(self.action)\n\n    # Restore last session's choice\n    if QSettings().value(SETTINGS_KEY, False, type=bool):\n        self.action.setChecked(True)  # triggers toggle_dock -> creates the dock\n\n\ndef toggle_dock(self, checked):\n    QSettings().setValue(SETTINGS_KEY, checked)\n    # ... creation \u002F visibility logic from the previous section ...\n",[18,1548,1549,1560,1564,1575,1579,1583,1592,1611,1621,1631,1641,1645,1650,1677,1690,1694,1698,1706,1716],{"__ignoreMap":133},[137,1550,1551,1553,1555,1557],{"class":139,"line":140},[137,1552,144],{"class":143},[137,1554,148],{"class":147},[137,1556,151],{"class":143},[137,1558,1559],{"class":147}," QSettings\n",[137,1561,1562],{"class":139,"line":157},[137,1563,212],{"emptyLinePlaceholder":211},[137,1565,1566,1569,1572],{"class":139,"line":170},[137,1567,1568],{"class":273},"SETTINGS_KEY",[137,1570,1571],{"class":143}," =",[137,1573,1574],{"class":241}," \"InspectorPlugin\u002FdockVisible\"\n",[137,1576,1577],{"class":139,"line":176},[137,1578,212],{"emptyLinePlaceholder":211},[137,1580,1581],{"class":139,"line":182},[137,1582,212],{"emptyLinePlaceholder":211},[137,1584,1585,1588,1590],{"class":139,"line":195},[137,1586,1587],{"class":143},"def",[137,1589,1217],{"class":226},[137,1591,601],{"class":147},[137,1593,1594,1597,1599,1601,1603,1605,1607,1609],{"class":139,"line":208},[137,1595,1596],{"class":273},"    self",[137,1598,1202],{"class":147},[137,1600,256],{"class":143},[137,1602,1230],{"class":147},[137,1604,301],{"class":241},[137,1606,888],{"class":147},[137,1608,355],{"class":273},[137,1610,1239],{"class":147},[137,1612,1613,1615,1617,1619],{"class":139,"line":215},[137,1614,1596],{"class":273},[137,1616,1246],{"class":147},[137,1618,1249],{"class":273},[137,1620,179],{"class":147},[137,1622,1623,1625,1627,1629],{"class":139,"line":220},[137,1624,1596],{"class":273},[137,1626,1258],{"class":147},[137,1628,355],{"class":273},[137,1630,1263],{"class":147},[137,1632,1633,1635,1637,1639],{"class":139,"line":238},[137,1634,1596],{"class":273},[137,1636,1270],{"class":147},[137,1638,355],{"class":273},[137,1640,1275],{"class":147},[137,1642,1643],{"class":139,"line":245},[137,1644,212],{"emptyLinePlaceholder":211},[137,1646,1647],{"class":139,"line":250},[137,1648,1649],{"class":335},"    # Restore last session's choice\n",[137,1651,1652,1655,1658,1660,1662,1664,1666,1670,1672,1675],{"class":139,"line":262},[137,1653,1654],{"class":143},"    if",[137,1656,1657],{"class":147}," QSettings().value(",[137,1659,1568],{"class":273},[137,1661,888],{"class":147},[137,1663,1362],{"class":273},[137,1665,888],{"class":147},[137,1667,1669],{"class":1668},"s9osk","type",[137,1671,256],{"class":143},[137,1673,1674],{"class":273},"bool",[137,1676,235],{"class":147},[137,1678,1679,1681,1683,1685,1687],{"class":139,"line":267},[137,1680,310],{"class":273},[137,1682,1359],{"class":147},[137,1684,1249],{"class":273},[137,1686,332],{"class":147},[137,1688,1689],{"class":335},"# triggers toggle_dock -> creates the dock\n",[137,1691,1692],{"class":139,"line":287},[137,1693,212],{"emptyLinePlaceholder":211},[137,1695,1696],{"class":139,"line":307},[137,1697,212],{"emptyLinePlaceholder":211},[137,1699,1700,1702,1704],{"class":139,"line":321},[137,1701,1587],{"class":143},[137,1703,1286],{"class":226},[137,1705,1289],{"class":147},[137,1707,1708,1711,1713],{"class":139,"line":339},[137,1709,1710],{"class":147},"    QSettings().setValue(",[137,1712,1568],{"class":273},[137,1714,1715],{"class":147},", checked)\n",[137,1717,1718],{"class":139,"line":344},[137,1719,1720],{"class":335},"    # ... creation \u002F visibility logic from the previous section ...\n",[14,1722,1723,1051,1725,1727,1728,1731,1732,1735,1736,1739,1740,1742,1743,1746],{},[69,1724,756],{},[18,1726,1539],{}," writes to the platform-native store (registry on Windows, plist on macOS, ",[18,1729,1730],{},".conf"," on Linux) under the QGIS organization, so the value survives restarts. Reading it with ",[18,1733,1734],{},"type=bool"," guarantees a real boolean rather than the string ",[18,1737,1738],{},"\"false\"",", which is truthy and a common bug. Setting the checkable action to checked during ",[18,1741,82],{}," re-runs ",[18,1744,1745],{},"toggle_dock",", recreating the panel exactly as the user left it.",[58,1748,1750],{"id":1749},"qgis-version-compatibility","QGIS Version Compatibility",[14,1752,1753],{},"The dock widget APIs are stable across the 3.x line; the only moving parts are enum spellings, which affect both approaches identically.",[1755,1756,1757,1776],"table",{},[1758,1759,1760],"thead",{},[1761,1762,1763,1767,1770,1773],"tr",{},[1764,1765,1766],"th",{},"API",[1764,1768,1769],{},"QGIS 3.28 LTR (Py 3.9)",[1764,1771,1772],{},"QGIS 3.34 LTR (Py 3.12)",[1764,1774,1775],{},"QGIS 3.40 \u002F 3.44 (Py 3.12)",[1777,1778,1779,1796,1811,1830],"tbody",{},[1761,1780,1781,1789,1792,1794],{},[1782,1783,1784,83,1787],"td",{},[18,1785,1786],{},"iface.addDockWidget",[18,1788,1517],{},[1782,1790,1791],{},"stable",[1782,1793,1791],{},[1782,1795,1791],{},[1761,1797,1798,1804,1807,1809],{},[1782,1799,1800,83,1802],{},[18,1801,121],{},[18,1803,125],{},[1782,1805,1806],{},"available",[1782,1808,1806],{},[1782,1810,1806],{},[1761,1812,1813,1816,1821,1824],{},[1782,1814,1815],{},"Filter enum",[1782,1817,1818],{},[18,1819,1820],{},"QgsMapLayerProxyModel.VectorLayer",[1782,1822,1823],{},"same",[1782,1825,1826,1829],{},[18,1827,1828],{},"Qgis.LayerFilter.VectorLayer"," also available",[1761,1831,1832,1835,1840,1842],{},[1782,1833,1834],{},"Dock area enum",[1782,1836,1837],{},[18,1838,1839],{},"Qt.RightDockWidgetArea",[1782,1841,1823],{},[1782,1843,1823],{},[14,1845,1846,1847,1849,1850,1853],{},"On QGIS 3.34 the classic ",[18,1848,1820],{}," filter remains the documented form. Newer releases add ",[18,1851,1852],{},"Qgis.LayerFilter"," aliases, but the old enum still works, so the code above is portable.",[58,1855,1857],{"id":1856},"troubleshooting","Troubleshooting",[14,1859,1860,1865,1866,1868,1869,1871,1872,1874,1875,83,1877,1879],{},[69,1861,1862,40],{},[18,1863,1864],{},"AttributeError: 'NoneType' object has no attribute 'setLayer'"," The promoted widget name in your code does not match the ",[18,1867,1072],{}," in the ",[18,1870,27],{}," file. Open the ",[18,1873,27],{}," in Qt Designer and confirm ",[18,1876,1076],{},[18,1878,1079],{}," exactly match your attribute names.",[14,1881,1882,1885,1886,1888,1889,1891],{},[69,1883,1884],{},"Dock position is not remembered between sessions."," You did not set an object name. Call ",[18,1887,763],{}," (subclass approach) or set it in Designer (",[18,1890,27],{}," approach) — QGIS keys saved layout state on it.",[14,1893,1894,1897,1898,1900,1901,1903,1904,1906,1907,1910],{},[69,1895,1896],{},"The toolbar toggle and the panel get out of sync."," Connect the dock's ",[18,1899,1106],{}," signal to ",[18,1902,1508],{},", and emit a ",[18,1905,783],{}," signal from ",[18,1908,1909],{},"closeEvent"," so the close button also updates the toggle.",[14,1912,1913,1051,1916,1918,1919,1922,1923,1925],{},[69,1914,1915],{},"Field combo is empty.",[18,1917,125],{}," needs a layer. Call ",[18,1920,1921],{},"setLayer"," once after creation and connect it to the layer combo's ",[18,1924,771],{}," signal so it updates on every change.",[14,1927,1928,1051,1931,1933,1934,122,1936,1938],{},[69,1929,1930],{},"Panel remains after disabling the plugin.",[18,1932,39],{}," must call ",[18,1935,1517],{},[18,1937,1521],{}," on the dock; removing only the toolbar icon leaves the panel behind.",[58,1940,1942],{"id":1941},"conclusion","Conclusion",[14,1944,1945,1946,1948,1949,28,1951,1953,1954,122,1956,1958,1959,1961,1962,1964,1965,1967,1968,28,1970,122,1972,1974],{},"A custom dock widget turns a one-shot dialog into a persistent, native-feeling part of the QGIS workspace. Whether you subclass ",[18,1947,20],{}," in Python or load a Qt Designer ",[18,1950,27],{},[18,1952,31],{},", the essentials are the same: embed GIS-aware widgets like ",[18,1955,121],{},[18,1957,125],{},", dock it with ",[18,1960,35],{},", keep a checkable toolbar action in sync via ",[18,1963,1106],{},", persist the user's choice with ",[18,1966,1539],{},", and tear it all down in ",[18,1969,39],{},[18,1971,1517],{},[18,1973,1521],{},". Get that lifecycle right and the panel behaves exactly like a built-in QGIS dock.",[58,1976,1978],{"id":1977},"frequently-asked-questions","Frequently Asked Questions",[14,1980,1981,1984,1985,1987],{},[69,1982,1983],{},"Should I subclass QDockWidget or load a .ui file?"," Subclass for small, code-driven panels; use a ",[18,1986,27],{}," when the layout is complex or maintained by a designer. Both dock identically — the choice is about how you author the layout.",[14,1989,1990,1993,1994,1996,1997,1999,2000,40],{},[69,1991,1992],{},"Why does the panel not reappear after a QGIS restart?"," QGIS restores dock ",[1063,1995,1532],{}," once you set an object name, but your plugin must decide whether to recreate the widget. Persist that intent with ",[18,1998,1539],{}," and recreate the dock in ",[18,2001,82],{},[14,2003,2004,2007,2008,2010,2011,888,2014,2017,2018,2021],{},[69,2005,2006],{},"Can I dock the panel on the left or bottom?"," Yes. Pass a different area to ",[18,2009,35],{}," — ",[18,2012,2013],{},"Qt.LeftDockWidgetArea",[18,2015,2016],{},"Qt.BottomDockWidgetArea",", or ",[18,2019,2020],{},"Qt.TopDockWidgetArea",". The user can still move it afterward.",[14,2023,2024,2027,2028,2031,2032,2035,2036,40],{},[69,2025,2026],{},"How do I open the dock from a toolbar button?"," Use a checkable ",[18,2029,2030],{},"QAction"," whose ",[18,2033,2034],{},"toggled"," signal shows or hides the dock, as shown above. The toolbar mechanics are covered in ",[45,2037,56],{"href":55},[58,2039,2041],{"id":2040},"related","Related",[63,2043,2044,2048,2052],{},[66,2045,2046],{},[45,2047,48],{"href":47},[66,2049,2050],{},[45,2051,56],{"href":55},[66,2053,2054],{},[45,2055,90],{"href":89},[2057,2058,2059],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":133,"searchDepth":157,"depth":157,"links":2061},[2062,2063,2064,2065,2066,2067,2068,2069,2070,2071],{"id":60,"depth":157,"text":61},{"id":107,"depth":157,"text":108},{"id":787,"depth":157,"text":788},{"id":1093,"depth":157,"text":1094},{"id":1525,"depth":157,"text":1526},{"id":1749,"depth":157,"text":1750},{"id":1856,"depth":157,"text":1857},{"id":1941,"depth":157,"text":1942},{"id":1977,"depth":157,"text":1978},{"id":2040,"depth":157,"text":2041},"Build a custom QDockWidget in a QGIS plugin with PyQGIS. Embed QgsMapLayerComboBox and QgsFieldComboBox, dock it, persist visibility, and remove it on unload.","md",{},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fadd-custom-dock-widget-pyqgis",{"title":5,"description":2072},"qgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fadd-custom-dock-widget-pyqgis\u002Findex","QLdKUvMDCfGvTKuJjrAZtLhNnkxUBTAakNFJ-c48W-A",1781792483475]