[{"data":1,"prerenderedAt":1851},["ShallowReactive",2],{"doc:\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fuse-file-and-crs-selection-widgets-pyqgis":3},{"id":4,"title":5,"body":6,"description":1840,"extension":1841,"meta":1842,"navigation":226,"path":1847,"seo":1848,"stem":1849,"__hash__":1850},"docs\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fuse-file-and-crs-selection-widgets-pyqgis\u002Findex.md","Use File and CRS Selection Widgets in PyQGIS",{"type":7,"value":8,"toc":1826},"minimark",[9,13,22,31,151,156,171,175,180,436,474,478,481,554,661,681,685,688,778,791,795,798,896,1122,1136,1140,1143,1360,1380,1384,1391,1608,1630,1634,1667,1671,1700,1704,1719,1723,1735,1745,1759,1765,1775,1781,1791,1795,1822],[10,11,5],"h1",{"id":12},"use-file-and-crs-selection-widgets-in-pyqgis",[14,15,16,17,21],"p",{},"Almost every plugin dialog asks for the same few things: an input file, an output folder, a coordinate reference system, an extent, a field. Plain Qt widgets can do each — a line edit plus a browse button plus a ",[18,19,20],"code",{},"QFileDialog"," — but QGIS ships specialised widgets that already behave the way QGIS users expect: CRS selection with search and recently used systems, file pickers that remember folders and filter by GIS formats, extent boxes that take the canvas or a layer's extent. Using them makes dialogs smaller, more consistent and less buggy.",[14,23,24,25,30],{},"This recipe belongs to ",[26,27,29],"a",{"href":28},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002F","Qt Designer for GIS Interfaces",". It sets up file and folder pickers, CRS selection, extent input and field selection, wires them together, uses them in Qt Designer, and reads their values safely.",[14,32,33],{},[34,35,40,44,48,55,64,74,80,86,90,95,100,104,107,110,113,118,122,125,128,131,137,142,145,148],"svg",{"viewBox":36,"role":37,"ariaLabel":38,"xmlns":39},"0 0 760 280","img","Four QGIS widgets for plugin dialogs: file picker, CRS selector, extent box and field combo box","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[41,42,43],"title",{},"QGIS input widgets for common questions",[45,46,47],"desc",{},"Four widgets answer the usual dialog questions. QgsFileWidget picks a file or folder with filters and a remembered last location. QgsProjectionSelectionWidget picks a CRS with search, project CRS, layer CRS and recent choices. QgsExtentGroupBox sets an extent from the canvas, a layer or by drawing. QgsFieldComboBox picks a field from a layer, optionally filtered by type.",[49,50],"rect",{"x":51,"y":51,"width":52,"height":53,"fill":54},"0","760","280","#f6f3ea",[56,57,63],"text",{"x":58,"y":59,"style":60,"fill":61,"textAnchor":62},"380","28","text-anchor:middle;font-size:14px;font-family:sans-serif;font-weight:bold","#17211d","middle","Which file, which CRS, where, which field",[49,65],{"x":66,"y":67,"width":68,"height":69,"rx":70,"fill":71,"stroke":72,"style":73},"24","56","168","196","8","#eef7f4","#0f766e","stroke-width:2",[56,75,79],{"x":76,"y":77,"style":78,"fill":72,"textAnchor":62},"108","112.6","text-anchor:middle;font-size:11.0px;font-family:sans-serif;font-weight:bold","QgsFileWidget",[56,81,85],{"x":76,"y":82,"style":83,"fill":84,"textAnchor":62},"142.6","text-anchor:middle;font-size:10.0px;font-family:sans-serif","#2f3b35","file or folder",[56,87,89],{"x":76,"y":88,"style":83,"fill":84,"textAnchor":62},"172.6","filters",[56,91,94],{"x":76,"y":92,"style":83,"fill":93,"textAnchor":62},"202.6","#59645f","remembers folder",[49,96],{"x":97,"y":67,"width":68,"height":69,"rx":70,"fill":98,"stroke":99,"style":73},"206","#eff3ff","#2563eb",[56,101,103],{"x":102,"y":77,"style":78,"fill":99,"textAnchor":62},"290","QgsProjection-",[56,105,106],{"x":102,"y":82,"style":83,"fill":84,"textAnchor":62},"SelectionWidget",[56,108,109],{"x":102,"y":88,"style":83,"fill":84,"textAnchor":62},"search, recents",[56,111,112],{"x":102,"y":92,"style":83,"fill":93,"textAnchor":62},"project\u002Flayer CRS",[49,114],{"x":115,"y":67,"width":68,"height":69,"rx":70,"fill":116,"stroke":117,"style":73},"388","#fdf2e2","#b45309",[56,119,121],{"x":120,"y":77,"style":78,"fill":117,"textAnchor":62},"472","QgsExtentGroupBox",[56,123,124],{"x":120,"y":82,"style":83,"fill":84,"textAnchor":62},"canvas, layer,",[56,126,127],{"x":120,"y":88,"style":83,"fill":84,"textAnchor":62},"draw on map",[56,129,130],{"x":120,"y":92,"style":83,"fill":93,"textAnchor":62},"with CRS",[49,132],{"x":133,"y":67,"width":134,"height":69,"rx":70,"fill":135,"stroke":136,"style":73},"570","166","#e8efe6","#15803d",[56,138,141],{"x":139,"y":77,"style":78,"fill":140,"textAnchor":62},"653","#166534","QgsFieldComboBox",[56,143,144],{"x":139,"y":82,"style":83,"fill":84,"textAnchor":62},"fields of a layer",[56,146,147],{"x":139,"y":88,"style":83,"fill":84,"textAnchor":62},"type filter",[56,149,150],{"x":139,"y":92,"style":83,"fill":93,"textAnchor":62},"linked to layer",[152,153,155],"h2",{"id":154},"prerequisites","Prerequisites",[157,158,159,163],"ul",{},[160,161,162],"li",{},"QGIS 3.34 LTR or newer, or the QGIS 4 series.",[160,164,165,166,170],{},"A plugin dialog, created in code or Qt Designer, as in ",[26,167,169],{"href":168},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fload-ui-file-at-runtime-pyqgis\u002F","loading a .ui file at runtime",".",[152,172,174],{"id":173},"pick-files-and-folders-with-qgsfilewidget","Pick files and folders with QgsFileWidget",[14,176,177,179],{},[18,178,79],{}," combines a line edit, a browse button and drag-and-drop. Its storage mode decides whether it picks an existing file, a file to save, or a folder.",[181,182,187],"pre",{"className":183,"code":184,"language":185,"meta":186,"style":186},"language-python shiki shiki-themes github-dark","from qgis.gui import QgsFileWidget\nfrom qgis.PyQt.QtWidgets import QDialog, QFormLayout\n\ndlg = QDialog()\nform = QFormLayout(dlg)\n\ninput_file = QgsFileWidget()\ninput_file.setStorageMode(QgsFileWidget.GetFile)\ninput_file.setFilter(\"GeoPackage (*.gpkg);;Shapefile (*.shp);;All files (*)\")\ninput_file.setDialogTitle(\"Choose the input layer\")\ninput_file.setDefaultRoot(\"\u002Fdata\u002Finbox\")\n\noutput_dir = QgsFileWidget()\noutput_dir.setStorageMode(QgsFileWidget.GetDirectory)\n\nreport = QgsFileWidget()\nreport.setStorageMode(QgsFileWidget.SaveFile)\nreport.setFilter(\"PDF (*.pdf)\")\nreport.setConfirmOverwrite(True)\n\nform.addRow(\"Input\", input_file)\nform.addRow(\"Output folder\", output_dir)\nform.addRow(\"Report\", report)\ninput_file.fileChanged.connect(lambda path: print(\"input:\", path))\n","python","",[18,188,189,208,221,228,240,251,256,267,273,286,297,308,313,323,329,334,344,350,361,373,378,390,401,412],{"__ignoreMap":186},[190,191,194,198,202,205],"span",{"class":192,"line":193},"line",1,[190,195,197],{"class":196},"snl16","from",[190,199,201],{"class":200},"s95oV"," qgis.gui ",[190,203,204],{"class":196},"import",[190,206,207],{"class":200}," QgsFileWidget\n",[190,209,211,213,216,218],{"class":192,"line":210},2,[190,212,197],{"class":196},[190,214,215],{"class":200}," qgis.PyQt.QtWidgets ",[190,217,204],{"class":196},[190,219,220],{"class":200}," QDialog, QFormLayout\n",[190,222,224],{"class":192,"line":223},3,[190,225,227],{"emptyLinePlaceholder":226},true,"\n",[190,229,231,234,237],{"class":192,"line":230},4,[190,232,233],{"class":200},"dlg ",[190,235,236],{"class":196},"=",[190,238,239],{"class":200}," QDialog()\n",[190,241,243,246,248],{"class":192,"line":242},5,[190,244,245],{"class":200},"form ",[190,247,236],{"class":196},[190,249,250],{"class":200}," QFormLayout(dlg)\n",[190,252,254],{"class":192,"line":253},6,[190,255,227],{"emptyLinePlaceholder":226},[190,257,259,262,264],{"class":192,"line":258},7,[190,260,261],{"class":200},"input_file ",[190,263,236],{"class":196},[190,265,266],{"class":200}," QgsFileWidget()\n",[190,268,270],{"class":192,"line":269},8,[190,271,272],{"class":200},"input_file.setStorageMode(QgsFileWidget.GetFile)\n",[190,274,276,279,283],{"class":192,"line":275},9,[190,277,278],{"class":200},"input_file.setFilter(",[190,280,282],{"class":281},"sU2Wk","\"GeoPackage (*.gpkg);;Shapefile (*.shp);;All files (*)\"",[190,284,285],{"class":200},")\n",[190,287,289,292,295],{"class":192,"line":288},10,[190,290,291],{"class":200},"input_file.setDialogTitle(",[190,293,294],{"class":281},"\"Choose the input layer\"",[190,296,285],{"class":200},[190,298,300,303,306],{"class":192,"line":299},11,[190,301,302],{"class":200},"input_file.setDefaultRoot(",[190,304,305],{"class":281},"\"\u002Fdata\u002Finbox\"",[190,307,285],{"class":200},[190,309,311],{"class":192,"line":310},12,[190,312,227],{"emptyLinePlaceholder":226},[190,314,316,319,321],{"class":192,"line":315},13,[190,317,318],{"class":200},"output_dir ",[190,320,236],{"class":196},[190,322,266],{"class":200},[190,324,326],{"class":192,"line":325},14,[190,327,328],{"class":200},"output_dir.setStorageMode(QgsFileWidget.GetDirectory)\n",[190,330,332],{"class":192,"line":331},15,[190,333,227],{"emptyLinePlaceholder":226},[190,335,337,340,342],{"class":192,"line":336},16,[190,338,339],{"class":200},"report ",[190,341,236],{"class":196},[190,343,266],{"class":200},[190,345,347],{"class":192,"line":346},17,[190,348,349],{"class":200},"report.setStorageMode(QgsFileWidget.SaveFile)\n",[190,351,353,356,359],{"class":192,"line":352},18,[190,354,355],{"class":200},"report.setFilter(",[190,357,358],{"class":281},"\"PDF (*.pdf)\"",[190,360,285],{"class":200},[190,362,364,367,371],{"class":192,"line":363},19,[190,365,366],{"class":200},"report.setConfirmOverwrite(",[190,368,370],{"class":369},"sDLfK","True",[190,372,285],{"class":200},[190,374,376],{"class":192,"line":375},20,[190,377,227],{"emptyLinePlaceholder":226},[190,379,381,384,387],{"class":192,"line":380},21,[190,382,383],{"class":200},"form.addRow(",[190,385,386],{"class":281},"\"Input\"",[190,388,389],{"class":200},", input_file)\n",[190,391,393,395,398],{"class":192,"line":392},22,[190,394,383],{"class":200},[190,396,397],{"class":281},"\"Output folder\"",[190,399,400],{"class":200},", output_dir)\n",[190,402,404,406,409],{"class":192,"line":403},23,[190,405,383],{"class":200},[190,407,408],{"class":281},"\"Report\"",[190,410,411],{"class":200},", report)\n",[190,413,415,418,421,424,427,430,433],{"class":192,"line":414},24,[190,416,417],{"class":200},"input_file.fileChanged.connect(",[190,419,420],{"class":196},"lambda",[190,422,423],{"class":200}," path: ",[190,425,426],{"class":369},"print",[190,428,429],{"class":200},"(",[190,431,432],{"class":281},"\"input:\"",[190,434,435],{"class":200},", path))\n",[14,437,438,442,443,446,447,446,450,453,454,457,458,461,462,465,466,469,470,473],{},[439,440,441],"strong",{},"Breakdown:"," ",[18,444,445],{},"GetFile",", ",[18,448,449],{},"GetMultipleFiles",[18,451,452],{},"GetDirectory"," and ",[18,455,456],{},"SaveFile"," cover the cases; for saving, ",[18,459,460],{},"setConfirmOverwrite"," asks before replacing an existing file. Filters use the familiar Qt syntax and appear in the browse dialog; QGIS can also generate a filter of every supported vector format with ",[18,463,464],{},"QgsProviderRegistry.instance().fileVectorFilters()",". ",[18,467,468],{},"setDefaultRoot"," sets the starting folder; the widget also remembers the last folder used. ",[18,471,472],{},"fileChanged"," fires whether the user browses, types or drops a file, so one handler covers all input methods.",[152,475,477],{"id":476},"pick-a-crs-with-qgsprojectionselectionwidget","Pick a CRS with QgsProjectionSelectionWidget",[14,479,480],{},"CRS choice is where hand-built dialogs are weakest. The projection selection widget offers the project CRS, layer CRS, recently used systems and a full searchable dialog.",[14,482,483],{},[34,484,487,490,493,496,499,503,509,514,518,522,525,529,533,537,540,545,550],{"viewBox":485,"role":37,"ariaLabel":486,"xmlns":39},"0 0 760 240","The CRS selector drop-down offering project, layer, default and recent CRSs plus a searchable dialog",[41,488,489],{},"Options in the CRS selector",[45,491,492],{},"The CRS selector's drop-down lists the project CRS, the CRS of a chosen layer, a default, recently used systems and an option to open the full CRS dialog with search by name or code. Options can be hidden or added with setOptionVisible. The current selection is read with crs() and changes are signalled by crsChanged.",[49,494],{"x":51,"y":51,"width":52,"height":495,"fill":54},"240",[56,497,498],{"x":58,"y":59,"style":60,"fill":61,"textAnchor":62},"Common choices first, search when needed",[49,500],{"x":66,"y":67,"width":501,"height":502,"rx":70,"fill":71,"stroke":72,"style":73},"222","160",[56,504,508],{"x":505,"y":506,"style":507,"fill":72,"textAnchor":62},"135","97.78","text-anchor:middle;font-size:11.5px;font-family:sans-serif;font-weight:bold","quick choices",[56,510,513],{"x":505,"y":511,"style":512,"fill":84,"textAnchor":62},"125.78","text-anchor:middle;font-size:10.5px;font-family:sans-serif","project CRS",[56,515,517],{"x":505,"y":516,"style":512,"fill":84,"textAnchor":62},"153.78","layer CRS",[56,519,521],{"x":505,"y":520,"style":512,"fill":84,"textAnchor":62},"181.78","recently used",[49,523],{"x":524,"y":67,"width":501,"height":502,"rx":70,"fill":98,"stroke":99,"style":73},"269",[56,526,528],{"x":58,"y":527,"style":507,"fill":99,"textAnchor":62},"111.78","full dialog",[56,530,532],{"x":58,"y":531,"style":512,"fill":84,"textAnchor":62},"139.78","search name\u002Fcode",[56,534,536],{"x":58,"y":535,"style":512,"fill":93,"textAnchor":62},"167.78","any CRS",[49,538],{"x":539,"y":67,"width":501,"height":502,"rx":70,"fill":135,"stroke":136,"style":73},"514",[56,541,544],{"x":542,"y":543,"style":78,"fill":140,"textAnchor":62},"625","111.6","read it",[56,546,549],{"x":542,"y":547,"style":548,"fill":84,"textAnchor":62},"139.6","text-anchor:middle;font-size:9.5px;font-family:monospace","crs()",[56,551,553],{"x":542,"y":552,"style":548,"fill":84,"textAnchor":62},"167.6","crsChanged",[181,555,557],{"className":183,"code":556,"language":185,"meta":186,"style":186},"from qgis.gui import QgsProjectionSelectionWidget\nfrom qgis.core import QgsCoordinateReferenceSystem, QgsProject\n\ncrs_widget = QgsProjectionSelectionWidget()\ncrs_widget.setCrs(QgsProject.instance().crs())\ncrs_widget.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, True)\ncrs_widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, False)\ncrs_widget.setLayerCrs(QgsCoordinateReferenceSystem(\"EPSG:25832\"))\ncrs_widget.crsChanged.connect(lambda crs: print(\"target CRS:\", crs.authid()))\nform.addRow(\"Target CRS\", crs_widget)\n",[18,558,559,570,582,586,596,601,610,620,631,651],{"__ignoreMap":186},[190,560,561,563,565,567],{"class":192,"line":193},[190,562,197],{"class":196},[190,564,201],{"class":200},[190,566,204],{"class":196},[190,568,569],{"class":200}," QgsProjectionSelectionWidget\n",[190,571,572,574,577,579],{"class":192,"line":210},[190,573,197],{"class":196},[190,575,576],{"class":200}," qgis.core ",[190,578,204],{"class":196},[190,580,581],{"class":200}," QgsCoordinateReferenceSystem, QgsProject\n",[190,583,584],{"class":192,"line":223},[190,585,227],{"emptyLinePlaceholder":226},[190,587,588,591,593],{"class":192,"line":230},[190,589,590],{"class":200},"crs_widget ",[190,592,236],{"class":196},[190,594,595],{"class":200}," QgsProjectionSelectionWidget()\n",[190,597,598],{"class":192,"line":242},[190,599,600],{"class":200},"crs_widget.setCrs(QgsProject.instance().crs())\n",[190,602,603,606,608],{"class":192,"line":253},[190,604,605],{"class":200},"crs_widget.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, ",[190,607,370],{"class":369},[190,609,285],{"class":200},[190,611,612,615,618],{"class":192,"line":258},[190,613,614],{"class":200},"crs_widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, ",[190,616,617],{"class":369},"False",[190,619,285],{"class":200},[190,621,622,625,628],{"class":192,"line":269},[190,623,624],{"class":200},"crs_widget.setLayerCrs(QgsCoordinateReferenceSystem(",[190,626,627],{"class":281},"\"EPSG:25832\"",[190,629,630],{"class":200},"))\n",[190,632,633,636,638,641,643,645,648],{"class":192,"line":275},[190,634,635],{"class":200},"crs_widget.crsChanged.connect(",[190,637,420],{"class":196},[190,639,640],{"class":200}," crs: ",[190,642,426],{"class":369},[190,644,429],{"class":200},[190,646,647],{"class":281},"\"target CRS:\"",[190,649,650],{"class":200},", crs.authid()))\n",[190,652,653,655,658],{"class":192,"line":288},[190,654,383],{"class":200},[190,656,657],{"class":281},"\"Target CRS\"",[190,659,660],{"class":200},", crs_widget)\n",[14,662,663,665,666,669,670,672,673,676,677,170],{},[439,664,441],{}," Starting with the project CRS matches what users usually want. Hiding \"not set\" prevents an invalid choice when a CRS is mandatory; keep it visible when \"no change\" is a valid answer. ",[18,667,668],{},"setLayerCrs"," adds the input layer's CRS as a quick option — update it when the input changes. ",[18,671,549],{}," returns a ",[18,674,675],{},"QgsCoordinateReferenceSystem",", so no parsing of strings is needed. For geographic versus projected checks before analysis, see ",[26,678,680],{"href":679},"\u002Fspatial-data-processing-automation\u002Fcoordinate-reference-systems\u002Fchoose-projected-crs-for-analysis-pyqgis\u002F","choosing a projected CRS for analysis",[152,682,684],{"id":683},"pick-an-extent-with-qgsextentgroupbox","Pick an extent with QgsExtentGroupBox",[14,686,687],{},"Clip, export and download dialogs need an area. The extent group box lets users take the current canvas extent, a layer's extent, draw on the map, or type coordinates — and reports the extent with its CRS.",[181,689,691],{"className":183,"code":690,"language":185,"meta":186,"style":186},"from qgis.gui import QgsExtentGroupBox\nfrom qgis.utils import iface\n\nextent_box = QgsExtentGroupBox()\nextent_box.setMapCanvas(iface.mapCanvas())\nextent_box.setOriginalExtent(iface.mapCanvas().extent(), iface.mapCanvas().mapSettings().destinationCrs())\nextent_box.setCurrentExtent(iface.mapCanvas().extent(), iface.mapCanvas().mapSettings().destinationCrs())\nextent_box.setOutputCrs(crs_widget.crs())\nextent_box.setCheckable(True)\nextent_box.setChecked(False)\nform.addRow(extent_box)\ncrs_widget.crsChanged.connect(extent_box.setOutputCrs)\n",[18,692,693,704,716,720,730,735,740,745,750,759,768,773],{"__ignoreMap":186},[190,694,695,697,699,701],{"class":192,"line":193},[190,696,197],{"class":196},[190,698,201],{"class":200},[190,700,204],{"class":196},[190,702,703],{"class":200}," QgsExtentGroupBox\n",[190,705,706,708,711,713],{"class":192,"line":210},[190,707,197],{"class":196},[190,709,710],{"class":200}," qgis.utils ",[190,712,204],{"class":196},[190,714,715],{"class":200}," iface\n",[190,717,718],{"class":192,"line":223},[190,719,227],{"emptyLinePlaceholder":226},[190,721,722,725,727],{"class":192,"line":230},[190,723,724],{"class":200},"extent_box ",[190,726,236],{"class":196},[190,728,729],{"class":200}," QgsExtentGroupBox()\n",[190,731,732],{"class":192,"line":242},[190,733,734],{"class":200},"extent_box.setMapCanvas(iface.mapCanvas())\n",[190,736,737],{"class":192,"line":253},[190,738,739],{"class":200},"extent_box.setOriginalExtent(iface.mapCanvas().extent(), iface.mapCanvas().mapSettings().destinationCrs())\n",[190,741,742],{"class":192,"line":258},[190,743,744],{"class":200},"extent_box.setCurrentExtent(iface.mapCanvas().extent(), iface.mapCanvas().mapSettings().destinationCrs())\n",[190,746,747],{"class":192,"line":269},[190,748,749],{"class":200},"extent_box.setOutputCrs(crs_widget.crs())\n",[190,751,752,755,757],{"class":192,"line":275},[190,753,754],{"class":200},"extent_box.setCheckable(",[190,756,370],{"class":369},[190,758,285],{"class":200},[190,760,761,764,766],{"class":192,"line":288},[190,762,763],{"class":200},"extent_box.setChecked(",[190,765,617],{"class":369},[190,767,285],{"class":200},[190,769,770],{"class":192,"line":299},[190,771,772],{"class":200},"form.addRow(extent_box)\n",[190,774,775],{"class":192,"line":310},[190,776,777],{"class":200},"crs_widget.crsChanged.connect(extent_box.setOutputCrs)\n",[14,779,780,782,783,786,787,790],{},[439,781,441],{}," Giving the box the map canvas enables \"draw on canvas\" and \"map canvas extent\" buttons. The output CRS is the CRS in which ",[18,784,785],{},"outputExtent()"," returns coordinates — linking it to the CRS widget keeps the two consistent when the user changes the target CRS. A checkable group box makes the extent optional: unchecked means \"whole layer\". Read ",[18,788,789],{},"extent_box.isChecked()"," before using the extent.",[152,792,794],{"id":793},"pick-a-field-and-link-widgets-together","Pick a field and link widgets together",[14,796,797],{},"Dialogs are easier to use when widgets react to each other: choosing a layer fills the field list, choosing an input file sets a sensible output name.",[14,799,800],{},[34,801,804,807,810,813,828,831,837,842,846,853,857,862,866,870,873,877,881,884,888,892],{"viewBox":802,"role":37,"ariaLabel":803,"xmlns":39},"0 0 760 216","Dialog widgets linked by signals: layer selection updating fields and CRS, and input file suggesting an output name",[41,805,806],{},"Widgets that update each other",[45,808,809],{},"A map layer combo box drives a field combo box, which lists only that layer's numeric fields. The layer's CRS is offered in the CRS selector. Choosing an input file suggests an output file name in the output folder. Each link is one signal connection.",[49,811],{"x":51,"y":51,"width":52,"height":812,"fill":54},"216",[814,815,816],"defs",{},[817,818,824],"marker",{"id":819,"viewBox":820,"refX":70,"refY":821,"markerWidth":822,"markerHeight":822,"orient":823},"wLinksArrow","0 0 10 10","5","7","auto-start-reverse",[825,826],"path",{"d":827,"fill":84},"M0 0 L10 5 L0 10 z",[56,829,830],{"x":58,"y":59,"style":60,"fill":61,"textAnchor":62},"One signal per link",[49,832],{"x":66,"y":833,"width":834,"height":835,"rx":70,"fill":836,"stroke":93,"style":73},"60","200","120","#fffdf7",[56,838,841],{"x":839,"y":840,"style":507,"fill":61,"textAnchor":62},"124","110.78","layer combo",[56,843,845],{"x":839,"y":844,"style":512,"fill":93,"textAnchor":62},"136.78","layerChanged",[192,847],{"x1":848,"y1":849,"x2":850,"y2":851,"stroke":84,"style":852},"224","90","266","70","stroke-width:1.8;marker-end:url(#wLinksArrow)",[192,854],{"x1":848,"y1":855,"x2":850,"y2":856,"stroke":84,"style":852},"150","170",[49,858],{"x":859,"y":860,"width":861,"height":833,"rx":70,"fill":135,"stroke":136,"style":73},"270","40","220",[56,863,865],{"x":58,"y":864,"style":507,"fill":140,"textAnchor":62},"63.78","field combo",[56,867,869],{"x":58,"y":868,"style":512,"fill":93,"textAnchor":62},"83.78","setLayer()",[49,871],{"x":859,"y":872,"width":861,"height":833,"rx":70,"fill":98,"stroke":99,"style":73},"140",[56,874,876],{"x":58,"y":875,"style":507,"fill":99,"textAnchor":62},"163.78","CRS selector",[56,878,880],{"x":58,"y":879,"style":512,"fill":93,"textAnchor":62},"183.78","setLayerCrs()",[49,882],{"x":883,"y":833,"width":834,"height":835,"rx":70,"fill":116,"stroke":117,"style":73},"536",[56,885,887],{"x":886,"y":506,"style":507,"fill":117,"textAnchor":62},"636","file widget",[56,889,891],{"x":886,"y":890,"style":512,"fill":93,"textAnchor":62},"123.78","suggests output",[56,893,895],{"x":886,"y":894,"style":512,"fill":93,"textAnchor":62},"149.78","name",[181,897,899],{"className":183,"code":898,"language":185,"meta":186,"style":186},"from qgis.gui import QgsMapLayerComboBox, QgsFieldComboBox\nfrom qgis.core import QgsMapLayerProxyModel, QgsFieldProxyModel\nfrom pathlib import Path\n\nlayer_combo = QgsMapLayerComboBox()\nlayer_combo.setFilters(QgsMapLayerProxyModel.PolygonLayer)\nfield_combo = QgsFieldComboBox()\nfield_combo.setFilters(QgsFieldProxyModel.Numeric)\nfield_combo.setAllowEmptyFieldName(False)\n\ndef on_layer(layer):\n    field_combo.setLayer(layer)\n    if layer is not None:\n        crs_widget.setLayerCrs(layer.crs())\n\nlayer_combo.layerChanged.connect(on_layer)\non_layer(layer_combo.currentLayer())\n\ndef suggest_output(path):\n    if path and not report.filePath():\n        report.setFilePath(str(Path(path).with_name(Path(path).stem + \"_report.pdf\")))\ninput_file.fileChanged.connect(suggest_output)\nform.insertRow(0, \"Layer\", layer_combo)\nform.insertRow(1, \"Value field\", field_combo)\n",[18,900,901,912,923,935,939,949,954,964,969,978,982,994,999,1019,1024,1028,1033,1038,1042,1052,1067,1087,1092,1107],{"__ignoreMap":186},[190,902,903,905,907,909],{"class":192,"line":193},[190,904,197],{"class":196},[190,906,201],{"class":200},[190,908,204],{"class":196},[190,910,911],{"class":200}," QgsMapLayerComboBox, QgsFieldComboBox\n",[190,913,914,916,918,920],{"class":192,"line":210},[190,915,197],{"class":196},[190,917,576],{"class":200},[190,919,204],{"class":196},[190,921,922],{"class":200}," QgsMapLayerProxyModel, QgsFieldProxyModel\n",[190,924,925,927,930,932],{"class":192,"line":223},[190,926,197],{"class":196},[190,928,929],{"class":200}," pathlib ",[190,931,204],{"class":196},[190,933,934],{"class":200}," Path\n",[190,936,937],{"class":192,"line":230},[190,938,227],{"emptyLinePlaceholder":226},[190,940,941,944,946],{"class":192,"line":242},[190,942,943],{"class":200},"layer_combo ",[190,945,236],{"class":196},[190,947,948],{"class":200}," QgsMapLayerComboBox()\n",[190,950,951],{"class":192,"line":253},[190,952,953],{"class":200},"layer_combo.setFilters(QgsMapLayerProxyModel.PolygonLayer)\n",[190,955,956,959,961],{"class":192,"line":258},[190,957,958],{"class":200},"field_combo ",[190,960,236],{"class":196},[190,962,963],{"class":200}," QgsFieldComboBox()\n",[190,965,966],{"class":192,"line":269},[190,967,968],{"class":200},"field_combo.setFilters(QgsFieldProxyModel.Numeric)\n",[190,970,971,974,976],{"class":192,"line":275},[190,972,973],{"class":200},"field_combo.setAllowEmptyFieldName(",[190,975,617],{"class":369},[190,977,285],{"class":200},[190,979,980],{"class":192,"line":288},[190,981,227],{"emptyLinePlaceholder":226},[190,983,984,987,991],{"class":192,"line":299},[190,985,986],{"class":196},"def",[190,988,990],{"class":989},"svObZ"," on_layer",[190,992,993],{"class":200},"(layer):\n",[190,995,996],{"class":192,"line":310},[190,997,998],{"class":200},"    field_combo.setLayer(layer)\n",[190,1000,1001,1004,1007,1010,1013,1016],{"class":192,"line":315},[190,1002,1003],{"class":196},"    if",[190,1005,1006],{"class":200}," layer ",[190,1008,1009],{"class":196},"is",[190,1011,1012],{"class":196}," not",[190,1014,1015],{"class":369}," None",[190,1017,1018],{"class":200},":\n",[190,1020,1021],{"class":192,"line":325},[190,1022,1023],{"class":200},"        crs_widget.setLayerCrs(layer.crs())\n",[190,1025,1026],{"class":192,"line":331},[190,1027,227],{"emptyLinePlaceholder":226},[190,1029,1030],{"class":192,"line":336},[190,1031,1032],{"class":200},"layer_combo.layerChanged.connect(on_layer)\n",[190,1034,1035],{"class":192,"line":346},[190,1036,1037],{"class":200},"on_layer(layer_combo.currentLayer())\n",[190,1039,1040],{"class":192,"line":352},[190,1041,227],{"emptyLinePlaceholder":226},[190,1043,1044,1046,1049],{"class":192,"line":363},[190,1045,986],{"class":196},[190,1047,1048],{"class":989}," suggest_output",[190,1050,1051],{"class":200},"(path):\n",[190,1053,1054,1056,1059,1062,1064],{"class":192,"line":375},[190,1055,1003],{"class":196},[190,1057,1058],{"class":200}," path ",[190,1060,1061],{"class":196},"and",[190,1063,1012],{"class":196},[190,1065,1066],{"class":200}," report.filePath():\n",[190,1068,1069,1072,1075,1078,1081,1084],{"class":192,"line":380},[190,1070,1071],{"class":200},"        report.setFilePath(",[190,1073,1074],{"class":369},"str",[190,1076,1077],{"class":200},"(Path(path).with_name(Path(path).stem ",[190,1079,1080],{"class":196},"+",[190,1082,1083],{"class":281}," \"_report.pdf\"",[190,1085,1086],{"class":200},")))\n",[190,1088,1089],{"class":192,"line":392},[190,1090,1091],{"class":200},"input_file.fileChanged.connect(suggest_output)\n",[190,1093,1094,1097,1099,1101,1104],{"class":192,"line":403},[190,1095,1096],{"class":200},"form.insertRow(",[190,1098,51],{"class":369},[190,1100,446],{"class":200},[190,1102,1103],{"class":281},"\"Layer\"",[190,1105,1106],{"class":200},", layer_combo)\n",[190,1108,1109,1111,1114,1116,1119],{"class":192,"line":414},[190,1110,1096],{"class":200},[190,1112,1113],{"class":369},"1",[190,1115,446],{"class":200},[190,1117,1118],{"class":281},"\"Value field\"",[190,1120,1121],{"class":200},", field_combo)\n",[14,1123,1124,1126,1127,1130,1131,1135],{},[439,1125,441],{}," Filtering the layer combo to polygon layers and the field combo to numeric fields means users can only choose valid inputs, which removes a whole class of validation code. Calling ",[18,1128,1129],{},"on_layer"," once at setup initialises the field list for the preselected layer. Suggesting an output name from the input saves typing but never overwrites a name the user already entered. ",[26,1132,1134],{"href":1133},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fuse-qgsmaplayercombobox-in-plugin-dialog-pyqgis\u002F","Using a QgsMapLayerComboBox in a plugin dialog"," covers layer combo options in more depth.",[152,1137,1139],{"id":1138},"other-qgis-widgets-worth-knowing","Other QGIS widgets worth knowing",[14,1141,1142],{},"The same family includes widgets for most other values a GIS dialog asks for. Each replaces a plain Qt widget with one that understands QGIS conventions.",[181,1144,1146],{"className":183,"code":1145,"language":185,"meta":186,"style":186},"from qgis.gui import (QgsDoubleSpinBox, QgsColorButton, QgsScaleWidget,\n                      QgsFieldExpressionWidget, QgsDateTimeEdit)\nfrom qgis.PyQt.QtGui import QColor\n\ndistance = QgsDoubleSpinBox()\ndistance.setRange(0, 10000)\ndistance.setSuffix(\" m\")\ndistance.setClearValue(100)            # reset button returns to 100\n\ncolour = QgsColorButton()\ncolour.setColor(QColor(\"#2563eb\"))\ncolour.setAllowOpacity(True)\n\nscale = QgsScaleWidget()\nscale.setMapCanvas(iface.mapCanvas())  # \"current scale\" button\n\nexpr = QgsFieldExpressionWidget()\nexpr.setLayer(layer_combo.currentLayer())\nlayer_combo.layerChanged.connect(expr.setLayer)\n\nfor label, w in ((\"Buffer distance\", distance), (\"Highlight colour\", colour),\n                 (\"Export scale\", scale), (\"Filter\", expr)):\n    form.addRow(label, w)\n",[18,1147,1148,1159,1164,1176,1180,1190,1204,1214,1229,1233,1243,1253,1262,1266,1276,1284,1288,1298,1303,1308,1312,1338,1355],{"__ignoreMap":186},[190,1149,1150,1152,1154,1156],{"class":192,"line":193},[190,1151,197],{"class":196},[190,1153,201],{"class":200},[190,1155,204],{"class":196},[190,1157,1158],{"class":200}," (QgsDoubleSpinBox, QgsColorButton, QgsScaleWidget,\n",[190,1160,1161],{"class":192,"line":210},[190,1162,1163],{"class":200},"                      QgsFieldExpressionWidget, QgsDateTimeEdit)\n",[190,1165,1166,1168,1171,1173],{"class":192,"line":223},[190,1167,197],{"class":196},[190,1169,1170],{"class":200}," qgis.PyQt.QtGui ",[190,1172,204],{"class":196},[190,1174,1175],{"class":200}," QColor\n",[190,1177,1178],{"class":192,"line":230},[190,1179,227],{"emptyLinePlaceholder":226},[190,1181,1182,1185,1187],{"class":192,"line":242},[190,1183,1184],{"class":200},"distance ",[190,1186,236],{"class":196},[190,1188,1189],{"class":200}," QgsDoubleSpinBox()\n",[190,1191,1192,1195,1197,1199,1202],{"class":192,"line":253},[190,1193,1194],{"class":200},"distance.setRange(",[190,1196,51],{"class":369},[190,1198,446],{"class":200},[190,1200,1201],{"class":369},"10000",[190,1203,285],{"class":200},[190,1205,1206,1209,1212],{"class":192,"line":258},[190,1207,1208],{"class":200},"distance.setSuffix(",[190,1210,1211],{"class":281},"\" m\"",[190,1213,285],{"class":200},[190,1215,1216,1219,1222,1225],{"class":192,"line":269},[190,1217,1218],{"class":200},"distance.setClearValue(",[190,1220,1221],{"class":369},"100",[190,1223,1224],{"class":200},")            ",[190,1226,1228],{"class":1227},"sjoCn","# reset button returns to 100\n",[190,1230,1231],{"class":192,"line":275},[190,1232,227],{"emptyLinePlaceholder":226},[190,1234,1235,1238,1240],{"class":192,"line":288},[190,1236,1237],{"class":200},"colour ",[190,1239,236],{"class":196},[190,1241,1242],{"class":200}," QgsColorButton()\n",[190,1244,1245,1248,1251],{"class":192,"line":299},[190,1246,1247],{"class":200},"colour.setColor(QColor(",[190,1249,1250],{"class":281},"\"#2563eb\"",[190,1252,630],{"class":200},[190,1254,1255,1258,1260],{"class":192,"line":310},[190,1256,1257],{"class":200},"colour.setAllowOpacity(",[190,1259,370],{"class":369},[190,1261,285],{"class":200},[190,1263,1264],{"class":192,"line":315},[190,1265,227],{"emptyLinePlaceholder":226},[190,1267,1268,1271,1273],{"class":192,"line":325},[190,1269,1270],{"class":200},"scale ",[190,1272,236],{"class":196},[190,1274,1275],{"class":200}," QgsScaleWidget()\n",[190,1277,1278,1281],{"class":192,"line":331},[190,1279,1280],{"class":200},"scale.setMapCanvas(iface.mapCanvas())  ",[190,1282,1283],{"class":1227},"# \"current scale\" button\n",[190,1285,1286],{"class":192,"line":336},[190,1287,227],{"emptyLinePlaceholder":226},[190,1289,1290,1293,1295],{"class":192,"line":346},[190,1291,1292],{"class":200},"expr ",[190,1294,236],{"class":196},[190,1296,1297],{"class":200}," QgsFieldExpressionWidget()\n",[190,1299,1300],{"class":192,"line":352},[190,1301,1302],{"class":200},"expr.setLayer(layer_combo.currentLayer())\n",[190,1304,1305],{"class":192,"line":363},[190,1306,1307],{"class":200},"layer_combo.layerChanged.connect(expr.setLayer)\n",[190,1309,1310],{"class":192,"line":375},[190,1311,227],{"emptyLinePlaceholder":226},[190,1313,1314,1317,1320,1323,1326,1329,1332,1335],{"class":192,"line":380},[190,1315,1316],{"class":196},"for",[190,1318,1319],{"class":200}," label, w ",[190,1321,1322],{"class":196},"in",[190,1324,1325],{"class":200}," ((",[190,1327,1328],{"class":281},"\"Buffer distance\"",[190,1330,1331],{"class":200},", distance), (",[190,1333,1334],{"class":281},"\"Highlight colour\"",[190,1336,1337],{"class":200},", colour),\n",[190,1339,1340,1343,1346,1349,1352],{"class":192,"line":392},[190,1341,1342],{"class":200},"                 (",[190,1344,1345],{"class":281},"\"Export scale\"",[190,1347,1348],{"class":200},", scale), (",[190,1350,1351],{"class":281},"\"Filter\"",[190,1353,1354],{"class":200},", expr)):\n",[190,1356,1357],{"class":192,"line":403},[190,1358,1359],{"class":200},"    form.addRow(label, w)\n",[14,1361,1362,442,1364,1367,1368,1371,1372,1375,1376,1379],{},[439,1363,441],{},[18,1365,1366],{},"QgsDoubleSpinBox"," adds a clear button that resets to a defined value — handy for \"back to default\". ",[18,1369,1370],{},"QgsColorButton"," opens QGIS's colour picker with palettes, recent colours and opacity. ",[18,1373,1374],{},"QgsScaleWidget"," accepts scales in the familiar 1:x form and can take the current canvas scale. ",[18,1377,1378],{},"QgsFieldExpressionWidget"," lets users pick a field or write an expression with the full expression builder, linked to the chosen layer — far more flexible than a field combo where users might want \"area \u002F 10000\" instead of a column. All of them can be placed in Qt Designer like the widgets above.",[152,1381,1383],{"id":1382},"use-the-widgets-in-qt-designer","Use the widgets in Qt Designer",[14,1385,1386,1387,1390],{},"All these widgets are available in Qt Designer's QGIS widget palette when Designer is started with QGIS's plugin path; in the ",[18,1388,1389],{},".ui"," file they appear with their QGIS class names and are created automatically when the form loads.",[181,1392,1394],{"className":183,"code":1393,"language":185,"meta":186,"style":186},"from qgis.PyQt import uic\nimport os\n\nFORM, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), \"export_dialog.ui\"))\n\nclass ExportDialog(QDialog, FORM):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        self.setupUi(self)\n        self.mOutputFolder.setStorageMode(QgsFileWidget.GetDirectory)\n        self.mLayer.layerChanged.connect(self.mField.setLayer)\n        self.mField.setLayer(self.mLayer.currentLayer())\n\n    def values(self):\n        return {\"layer\": self.mLayer.currentLayer(), \"field\": self.mField.currentField(),\n                \"crs\": self.mCrs.crs(), \"folder\": self.mOutputFolder.filePath()}\n",[18,1395,1396,1408,1415,1419,1443,1447,1467,1485,1499,1512,1519,1531,1543,1547,1557,1586],{"__ignoreMap":186},[190,1397,1398,1400,1403,1405],{"class":192,"line":193},[190,1399,197],{"class":196},[190,1401,1402],{"class":200}," qgis.PyQt ",[190,1404,204],{"class":196},[190,1406,1407],{"class":200}," uic\n",[190,1409,1410,1412],{"class":192,"line":210},[190,1411,204],{"class":196},[190,1413,1414],{"class":200}," os\n",[190,1416,1417],{"class":192,"line":223},[190,1418,227],{"emptyLinePlaceholder":226},[190,1420,1421,1424,1427,1429,1432,1435,1438,1441],{"class":192,"line":230},[190,1422,1423],{"class":369},"FORM",[190,1425,1426],{"class":200},", _ ",[190,1428,236],{"class":196},[190,1430,1431],{"class":200}," uic.loadUiType(os.path.join(os.path.dirname(",[190,1433,1434],{"class":369},"__file__",[190,1436,1437],{"class":200},"), ",[190,1439,1440],{"class":281},"\"export_dialog.ui\"",[190,1442,630],{"class":200},[190,1444,1445],{"class":192,"line":242},[190,1446,227],{"emptyLinePlaceholder":226},[190,1448,1449,1452,1455,1457,1460,1462,1464],{"class":192,"line":253},[190,1450,1451],{"class":196},"class",[190,1453,1454],{"class":989}," ExportDialog",[190,1456,429],{"class":200},[190,1458,1459],{"class":989},"QDialog",[190,1461,446],{"class":200},[190,1463,1423],{"class":369},[190,1465,1466],{"class":200},"):\n",[190,1468,1469,1472,1475,1478,1480,1483],{"class":192,"line":258},[190,1470,1471],{"class":196},"    def",[190,1473,1474],{"class":369}," __init__",[190,1476,1477],{"class":200},"(self, parent",[190,1479,236],{"class":196},[190,1481,1482],{"class":369},"None",[190,1484,1466],{"class":200},[190,1486,1487,1490,1493,1496],{"class":192,"line":269},[190,1488,1489],{"class":369},"        super",[190,1491,1492],{"class":200},"().",[190,1494,1495],{"class":369},"__init__",[190,1497,1498],{"class":200},"(parent)\n",[190,1500,1501,1504,1507,1510],{"class":192,"line":275},[190,1502,1503],{"class":369},"        self",[190,1505,1506],{"class":200},".setupUi(",[190,1508,1509],{"class":369},"self",[190,1511,285],{"class":200},[190,1513,1514,1516],{"class":192,"line":288},[190,1515,1503],{"class":369},[190,1517,1518],{"class":200},".mOutputFolder.setStorageMode(QgsFileWidget.GetDirectory)\n",[190,1520,1521,1523,1526,1528],{"class":192,"line":299},[190,1522,1503],{"class":369},[190,1524,1525],{"class":200},".mLayer.layerChanged.connect(",[190,1527,1509],{"class":369},[190,1529,1530],{"class":200},".mField.setLayer)\n",[190,1532,1533,1535,1538,1540],{"class":192,"line":310},[190,1534,1503],{"class":369},[190,1536,1537],{"class":200},".mField.setLayer(",[190,1539,1509],{"class":369},[190,1541,1542],{"class":200},".mLayer.currentLayer())\n",[190,1544,1545],{"class":192,"line":315},[190,1546,227],{"emptyLinePlaceholder":226},[190,1548,1549,1551,1554],{"class":192,"line":325},[190,1550,1471],{"class":196},[190,1552,1553],{"class":989}," values",[190,1555,1556],{"class":200},"(self):\n",[190,1558,1559,1562,1565,1568,1571,1573,1576,1579,1581,1583],{"class":192,"line":331},[190,1560,1561],{"class":196},"        return",[190,1563,1564],{"class":200}," {",[190,1566,1567],{"class":281},"\"layer\"",[190,1569,1570],{"class":200},": ",[190,1572,1509],{"class":369},[190,1574,1575],{"class":200},".mLayer.currentLayer(), ",[190,1577,1578],{"class":281},"\"field\"",[190,1580,1570],{"class":200},[190,1582,1509],{"class":369},[190,1584,1585],{"class":200},".mField.currentField(),\n",[190,1587,1588,1591,1593,1595,1598,1601,1603,1605],{"class":192,"line":336},[190,1589,1590],{"class":281},"                \"crs\"",[190,1592,1570],{"class":200},[190,1594,1509],{"class":369},[190,1596,1597],{"class":200},".mCrs.crs(), ",[190,1599,1600],{"class":281},"\"folder\"",[190,1602,1570],{"class":200},[190,1604,1509],{"class":369},[190,1606,1607],{"class":200},".mOutputFolder.filePath()}\n",[14,1609,1610,1612,1613,1616,1617,1620,1621,1625,1626,170],{},[439,1611,441],{}," Widgets placed in Designer are configured in code after ",[18,1614,1615],{},"setupUi"," for anything Designer does not expose, such as storage modes and signal links. A ",[18,1618,1619],{},"values()"," method gathering everything into a dictionary keeps the rest of the plugin independent of widget names. Validate the dictionary before running — empty paths, invalid CRSs — as in ",[26,1622,1624],{"href":1623},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fvalidate-plugin-dialog-input-pyqgis\u002F","validating plugin dialog input",". Setting up Designer with QGIS widgets is covered in ",[26,1627,1629],{"href":1628},"\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fuse-qgis-custom-widgets-in-qt-designer\u002F","using QGIS custom widgets in Qt Designer",[152,1631,1633],{"id":1632},"qgis-version-compatibility","QGIS version compatibility",[14,1635,1636,446,1638,446,1641,446,1643,453,1646,1648,1649,446,1652,446,1655,1658,1659,1662,1663,1666],{},[18,1637,79],{},[18,1639,1640],{},"QgsProjectionSelectionWidget",[18,1642,121],{},[18,1644,1645],{},"QgsMapLayerComboBox",[18,1647,141],{}," work on QGIS 3.34 LTR, 3.40 LTR and QGIS 4. On QGIS 4, filter and mode enums are scoped — ",[18,1650,1651],{},"QgsFileWidget.StorageMode.GetFile",[18,1653,1654],{},"Qgis.LayerFilter.PolygonLayer",[18,1656,1657],{},"QgsFieldProxyModel.Filter.Numeric"," — and ",[18,1660,1661],{},"QgsMapLayerProxyModel"," filters moved to ",[18,1664,1665],{},"Qgis.LayerFilter"," in 3.34.",[152,1668,1670],{"id":1669},"troubleshooting","Troubleshooting",[157,1672,1673,1682,1688,1694],{},[160,1674,1675,1678,1679,1681],{},[439,1676,1677],{},"The field list stays empty."," The field combo was never given a layer; connect ",[18,1680,845],{}," and initialise once.",[160,1683,1684,1687],{},[439,1685,1686],{},"The extent is in the wrong CRS."," The extent box's output CRS was not set or not updated with the CRS widget.",[160,1689,1690,1693],{},[439,1691,1692],{},"The file widget returns an empty string."," The user typed nothing; validate before running.",[160,1695,1696,1699],{},[439,1697,1698],{},"QGIS widgets are missing in Designer."," Designer was not started with QGIS's widget plugin path.",[152,1701,1703],{"id":1702},"conclusion","Conclusion",[14,1705,1706,1707,1709,1710,1712,1713,1715,1716,1718],{},"Use ",[18,1708,79],{}," with the right storage mode and filters, ",[18,1711,1640],{}," with sensible quick options, ",[18,1714,121],{}," linked to the canvas and output CRS, and filtered layer and field combo boxes linked by signals; configure Designer-placed widgets after ",[18,1717,1615],{},", gather values in one method and validate them before running.",[152,1720,1722],{"id":1721},"frequently-asked-questions","Frequently Asked Questions",[14,1724,1725,1728,1729,1731,1732,170],{},[439,1726,1727],{},"Can QgsFileWidget pick multiple files?","\nYes — ",[18,1730,449],{}," mode, read with ",[18,1733,1734],{},"splitFilePaths(filePath())",[14,1736,1737,1740,1741,1744],{},[439,1738,1739],{},"Can a file widget accept URLs?","\nYes — users can paste a URL into the line edit, and ",[18,1742,1743],{},"filePath()"," returns it; check whether your code accepts remote sources before allowing it.",[14,1746,1747,1750,1751,1754,1755,170],{},[439,1748,1749],{},"How do I remember the last values between sessions?","\nStore them with ",[18,1752,1753],{},"QgsSettings"," on accept and restore them on open, as in ",[26,1756,1758],{"href":1757},"\u002Fqgis-plugin-development\u002Fplugin-settings-and-localization\u002Fremember-last-used-folder-in-plugin-pyqgis\u002F","remembering the last used folder",[14,1760,1761,1764],{},[439,1762,1763],{},"Do these widgets respect QGIS's theme and language?","\nYes. They use QGIS's own icons, styling and translations, which is one reason dialogs built from them feel native in every language QGIS supports.",[14,1766,1767,1770,1771,1774],{},[439,1768,1769],{},"Can I disable typing so users must browse?","\nSet the file widget's line edit read-only with ",[18,1772,1773],{},"lineEdit().setReadOnly(True)","; browsing and drag-and-drop still work.",[14,1776,1777,1780],{},[439,1778,1779],{},"Is there a widget for picking a Processing output?","\nProcessing parameter widgets exist, but for plugins the widgets here are simpler.",[14,1782,1783,1786,1787,1790],{},[439,1784,1785],{},"Can the CRS widget show only projected systems?","\nValidate the choice instead; the widget lists all CRSs, and a check on ",[18,1788,1789],{},"isGeographic()"," with a message is clearer.",[152,1792,1794],{"id":1793},"related","Related",[157,1796,1797,1802,1807,1812,1817],{},[160,1798,1799,1801],{},[26,1800,29],{"href":28}," — the guide this recipe belongs to",[160,1803,1804],{},[26,1805,1806],{"href":1133},"Use a QgsMapLayerComboBox in a Plugin Dialog",[160,1808,1809],{},[26,1810,1811],{"href":1623},"Validate Plugin Dialog Input in PyQGIS",[160,1813,1814],{},[26,1815,1816],{"href":1628},"Use QGIS Custom Widgets in Qt Designer",[160,1818,1819],{},[26,1820,1821],{"href":1757},"Remember the Last Used Folder in a Plugin",[1823,1824,1825],"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 .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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 .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}",{"title":186,"searchDepth":210,"depth":210,"links":1827},[1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839],{"id":154,"depth":210,"text":155},{"id":173,"depth":210,"text":174},{"id":476,"depth":210,"text":477},{"id":683,"depth":210,"text":684},{"id":793,"depth":210,"text":794},{"id":1138,"depth":210,"text":1139},{"id":1382,"depth":210,"text":1383},{"id":1632,"depth":210,"text":1633},{"id":1669,"depth":210,"text":1670},{"id":1702,"depth":210,"text":1703},{"id":1721,"depth":210,"text":1722},{"id":1793,"depth":210,"text":1794},"Build plugin dialogs with QGIS's own input widgets — QgsFileWidget for files and folders with filters and remembered locations, QgsProjectionSelectionWidget for CRS choice, QgsExtentGroupBox for extents and QgsFieldComboBox for fields — set up in code or Qt Designer and read reliably.","md",{"slug":1843,"type":1844,"breadcrumb":1845,"datePublished":1846,"dateModified":1846},"use-file-and-crs-selection-widgets-pyqgis","article","Use File and CRS Selection Widgets","2026-10-02","\u002Fqgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fuse-file-and-crs-selection-widgets-pyqgis",{"title":5,"description":1840},"qgis-plugin-development\u002Fqt-designer-for-gis-interfaces\u002Fuse-file-and-crs-selection-widgets-pyqgis\u002Findex","xFgt3PtUbjnS4kGB0hiLnRZTjdzR3zYKQV2hJ09iYDs",1790966259180]