6

I am trying to write a plugin with a input control such as textbox on it. I looked around quite a bit for building plugins. But I can only find examples of how to build a plugin with buttons/icons in its toolbar.

How can I add other widgets such as a textbox on my plugin's toolbar?

For the button, there isn't much to handle except for a callback when it's clicked. I imagine it would be quite different for a textbox as one needs to associate the input control to e.g. a global variable??

For now, I need interaction with the textbox (QLineEdit). I want to implement a plugin for going to the next feature where I can display the row number of the current record, and jump to any given row by entering its row number.

I am using QGIS2.99 and Qt5, the standard Plugin Builder and pb_tool to create and deploy the plugin template. I suppose I need to add the QLineEdit in initGui() of the main py file(as shown below). I don't know much about Qt5, and only figured I might need addUserInputWidget() and/or connect it with the add_action() function? But I don't know how to put the pieces together, and register the events etc.

Here is what I have so far:

def initGui(self):
    """Create the menu entries and toolbar icons inside the QGIS GUI."""

    # Create & add a textbox
    self.textbox = QLineEdit(self.iface.mainWindow())
    self.textbox.resize(80,20)

    self.txtAction = self.toolbar.addWidget(self.textbox)
    #should I use addUserInputWidget(self.textbox) #??

    self.txtAction.setToolTip(self.tr(u'Current Row Number'))
    #callback=self.runTextChange   how to register an event handler?

The UI shows but there is no interaction.

Can someone help explain how to link the QLineEdit to the toolbar so that I can get/change the text value?

Also, a minor issue I can't figure out is that the textbox takes up the full width of the toolbar no matter what I use in its .resize() method. How should I limit its width?

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
tinlyx
  • 11,057
  • 18
  • 71
  • 119
  • Have a look at my answer. I'm not sure it can help you so, if you think it is very far from your needs or simply off-topic, please notify me it and I will delete the answer. – mgri Jun 20 '17 at 08:24

2 Answers2

5

This would be more a comment than an answer (and most probably a starting point rather than a solution), but I post it here since there is some code.

If you want to set up a basic textbox, you may use this code:

from PyQt4.QtGui import *

input_dialog = QInputDialog()
title = "Dialog Title"
label = "Enter some text here: "
enum_type = QLineEdit.Normal
default_text = "<your text here>"

res = QInputDialog.getText(input_dialog, title, label, enum_type, default_text)

The res variable is a tuple that stores your text (as a string) and a boolean which is used to verify that an input was typed. You can also change the last line in:

text_var, typed = QInputDialog.getText(input_dialog, title, label, enum_type, default_text)

for directly having your text stored in the text_var variable.

Note that this works for Qt4, but I think it should follow the same syntax also for Qt5.

mgri
  • 16,159
  • 6
  • 47
  • 80
  • Thanks a lot. I really appreciate your help. But I am looking for a more direct connection between the lineedit and the python code/global variable so that they notify each other of value changes and act accordingly. – tinlyx Jun 20 '17 at 09:55
  • @tinlyx You confirmed my doubts about the usefulness of my tip. Sorry, but these operations are not my cup of tea... Good luck! :) – mgri Jun 20 '17 at 09:57
5

Nice answer by @mgri (don't delete it as it is useful to use within QGIS!). I tested the following on QGIS 2.18 also with Qt4 but perhaps it might be useful too as the other answer. A couple of things to note:

  • You can use self.textbox.setFixedWidth(80) to set the width of the textbox.
  • You can use self.textbox.textChanged.connect(self.runTextChange) to connect the textbox to a function whenever the text is changed.

Here is the code used:

def initGui(self):
    """Create the menu entries and toolbar icons inside the QGIS GUI."""
    # Create & add a textbox
    self.textbox = QLineEdit(self.iface.mainWindow())
    # Set width
    self.textbox.setFixedWidth(80)
    # Add textbox to toolbar
    self.txtAction = self.toolbar.addWidget(self.textbox)
    # Set tooltip
    self.txtAction.setToolTip(self.tr(u'Current Row Number'))
    # Set callback
    self.textbox.textChanged.connect(self.runTextChange)


def runTextChange(self, rownum):
    # Set active layer
    layer = iface.activeLayer()
    # If textbox is empty or 0 then deselect all features
    if rownum == '' or int(rownum) == 0:
        layer.deselect([feat.id() for feat in layer.getFeatures()])
    else:
        # Else select row number matching the entered value
        for feat in layer.getFeatures():
            if feat.id() == int(rownum) - 1:
                layer.setSelectedFeatures([feat.id()])

Example:

Example

Joseph
  • 75,746
  • 7
  • 171
  • 282
  • 1
    Quite different from my answer, but I'm sure this will solve the issue :) – mgri Jun 20 '17 at 10:24
  • 1
    @mgri - Haven't used QGIS 2.99 or Qt5 so who knows :) Although I am dreading how much changes I will need to make to my plugins when QGIS 3 is officially released >_< – Joseph Jun 20 '17 at 10:26
  • 1
    I know, it will be a common nightmare for all of us (and probably for the whole community since there will be a lot of answers with deprecated APIs). – mgri Jun 20 '17 at 10:33
  • 1
    Thanks! I only needed to change the last line to layer.selectByIds(... to make it work.. – tinlyx Jun 20 '17 at 15:03