[GIS] Connecting Qt GUI to python code in QGIS Plugin

pyqgispyqgis-3pyqtqgis-3qt-designer

I am completely new to PyQGIS/PyQt and am having lots of trouble getting started. I have managed to create my base dialog box like so:

base_dialog

The (automatically generated) code for the dialog is:

import os

from qgis.PyQt import uic
from qgis.PyQt import QtWidgets

# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'offshore_interpretation_dialog_base.ui'))


class InterpretationDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(InterpretationDialog, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)

In my run method for my plugin I have tried this (and various other things):

def run(self):
        """Run method that performs all the real work"""

        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started
        if self.first_start == True:
            self.first_start = False
            self.dlg = OffshoreInterpretationDialog()

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            #interpret_checkBox/qc_checkBox are names I gave in QT designer for the checkboxes
            if self.dlg.interpret_checkBox.isChecked(): 
                print ('You have selected interpretation')
            elif self.dlg.qc_checkBox.isChecked():
                print ('You have selected qc')
            else:
                print ('Please select an option')

Content of .ui file:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>OffshoreInterpretationDialogBase</class>
 <widget class="QDialog" name="OffshoreInterpretationDialogBase">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>350</width>
    <height>166</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>OffshoreInterpretation</string>
  </property>
  <widget class="QDialogButtonBox" name="button_box">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>120</y>
     <width>161</width>
     <height>32</height>
    </rect>
   </property>
   <property name="orientation">
    <enum>Qt::Horizontal</enum>
   </property>
   <property name="standardButtons">
    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
   </property>
  </widget>
  <widget class="QLabel" name="Title">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>351</width>
     <height>21</height>
    </rect>
   </property>
   <property name="font">
    <font>
     <pointsize>13</pointsize>
     <weight>50</weight>
     <bold>false</bold>
    </font>
   </property>
   <property name="text">
    <string>Offshore Exploration Slick Interpretation Tool</string>
   </property>
   <property name="textFormat">
    <enum>Qt::AutoText</enum>
   </property>
  </widget>
  <widget class="QCheckBox" name="interpret_checkBox">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>50</y>
     <width>151</width>
     <height>31</height>
    </rect>
   </property>
   <property name="font">
    <font>
     <pointsize>11</pointsize>
    </font>
   </property>
   <property name="text">
    <string>Interpret New Slicks</string>
   </property>
   <property name="iconSize">
    <size>
     <width>16</width>
     <height>16</height>
    </size>
   </property>
  </widget>
  <widget class="QCheckBox" name="qc_checkBox">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>80</y>
     <width>151</width>
     <height>31</height>
    </rect>
   </property>
   <property name="font">
    <font>
     <pointsize>11</pointsize>
    </font>
   </property>
   <property name="text">
    <string>QC Existing Slicks</string>
   </property>
   <property name="iconSize">
    <size>
     <width>16</width>
     <height>16</height>
    </size>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>button_box</sender>
   <signal>accepted()</signal>
   <receiver>OffshoreInterpretationDialogBase</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>20</x>
     <y>20</y>
    </hint>
    <hint type="destinationlabel">
     <x>20</x>
     <y>20</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>button_box</sender>
   <signal>rejected()</signal>
   <receiver>OffshoreInterpretationDialogBase</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>20</x>
     <y>20</y>
    </hint>
    <hint type="destinationlabel">
     <x>20</x>
     <y>20</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

I get an Error saying AttributeError: 'InterpretationDialog' object has no attribute 'interpret_checkBox'

I don't understand how I can access the methods and attributes of the checkBox buttons (or any other buttons) in the code. Where do I find the documentation for all of this? I have tried to follow many tutorials but none explain how I can see which methods are available for each object?

I am using QGIS 3.4 and am horribly lost.

Best Answer

Your "check boxes" don't work because you're putting your lines in the wrong place (run method). However, you need first to declare objects in __init__ method for connecting them to a 'change_status' function (preferably one for each check box). I'm going to exemplify this only for "Interpretation" Check Box. Snippet code is as follows:

.
.
.
def __init__(self, iface): 
        """Constructor."""
.
.
.
    chkBox1 = self.dlg.interpret_checkBox
    chkBox1.setChecked(True)
    chkBox1.setText('Interpretation')
    chkBox1.stateChanged.connect(self.change_status_interpretation)

    chkBox2 = self.dlg.qc_checkBox
    chkBox2.stateChanged.connect(self.change_status_qc)
.
.
.
    def change_status_interpretation(self):

        if self.dlg.interpret_checkBox.isChecked():
            self.dlg.interpret_checkBox.setText("Interpretation")
            print ('You have selected interpretation')
        else:
            self.dlg.interpret_checkBox.setText("Check to activate interpretation")

    def change_status_qc(self):

        pass #your code here

    def run(self):
        """Run method that performs all the real work"""
.
.
.

I put above lines in my test plugin and launched it. It can be observed in following image. It is checked by default.

enter image description here

When it is unchecked, text in Check Box automatically changes to "Check to activate interpretation"; as it can be observed in following image:

enter image description here

When it is checked again, it is printed in Python Console "You have selected interpretation" and text Check Box changes to "Interpretation". This can be observed in following image:

enter image description here

Related Question