Understanding QComboBox signals



  • I find that if I connect QComboBox signals @editTextChanged(QString)@ and @activated(QString)@ and then "select" a different item in the dropdown list, the slots for both signals get executed, when I am expecting only the slot for the @activated(QString)@ to execute. Is this expected behavior?

    More importantly, I would like a single slot to execute when I change/edit the text, and another single slot to fire when a selection change occurs. Is that possible? How?

    Thanks


  • Moderators

    I would use only the signal best fitting for your purposes. The editTextChanged signal is obviously when the text has been changed.

    [quote author="chax0" date="1313026145"]More importantly, I would like a single slot to execute when I change/edit the text, and another single slot to fire when a selection change occurs. Is that possible? How?[/quote]

    Apparently, you know already how to connect the signals and slots. So I spare the explanation.

    The only solution I see is to split the activities into both slots. One does the things for change/edit and the other the activation. If you do not need the functionality of activation after the execution of the edit/change functionality, you use a falg or something to ignore (immediately exit) the subsequent activation slot call.



  • The flag idea is definitely a good one, and would work if the sequence of slot execution was desired behavior, followed by undesired behavior. I could then set the flag indicating that desired behavior had been achieved, and side-step the undesired behavior.

    However on the QComboBox when both signals are connected, the slot execution sequence is reversed, and when a selection happens, FIRST the slot connected to the editTextChanged executes (not good, since the user did not actually "change" the text), and THEN the slot connected to activated executes.

    Since I cannot distinguish in the code that no text change actually occurred, I do not see a way to avoid the execution of the editTextChanged signal/slot. Am I being too dense, and is there a more elegant way of handling this?


  • Moderators

    [quote]This signal is sent when the user chooses an item in the combobox. The item's text is passed. Note that this signal is sent even when the choice is not changed. If you need to know when the choice actually changes, use signal currentIndexChanged(). [/quote]

    Did you see this under activated signal?

    The description is not very explicit in those regards. :-(



  • The API docs state:

    bq. Whenever the text of an editable combobox is changed the editTextChanged() signal is emitted.

    That signal is emitted before the others, apparently.

    Secondly:
    If you select the very same entry in the combobox, the line edit is filled with the text of that entry. It's insofar useful, as you have an editable line edit and you can reset the value to the original one this way.

    What I don't understand: why do you connect to both signals? Wouldn't it be enough to connect to activated(int) and get the selected text with currentText()? This way you would not care for not-changed texts, as activated is only emitted on a really new item.



  • Already tried the currentIndexChanged() signal, and it actually is worse than the activated() signal for my purposes, since it fires both when a programmatic change is made, as well as when a user-initiated selection change is made. What I REALLY need is a way to handle user-initiated "selections" that do not first invoke the "text changed" slot.

    Maybe some code will help illustrate what I am trying to achieve:

    @
    //
    // slotmachine.h
    //

    #ifndef SLOTMACHINE_H
    #define SLOTMACHINE_H

    #include <QObject>

    class SlotMachine : public QObject {
    Q_OBJECT
    public:
    explicit SlotMachine(QObject *parent = 0) : QObject(parent) {
    }

    ~SlotMachine() {
    }
    

    public slots:
    void SelectItem(QString item) {
    qDebug(QString("Item selected was: %1").arg(item).toLocal8Bit().data());
    }

    void UpdateItem(QString item) {
        qDebug(QString("Item updated was: %1").arg(item).toLocal8Bit().data());
    }
    

    };

    #endif // SLOTMACHINE_H
    @

    @
    //
    // main.cpp
    //

    #include <QObject>
    #include <QApplication>
    #include <QMainWindow>
    #include <QComboBox>

    #include "slotmachine.h"

    int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QMainWindow *window = new QMainWindow();
    window->setGeometry(QRect(QPoint(100, 100), QSize(600, 400)));
    
    QComboBox *comboBox = new QComboBox(window);
    comboBox->setGeometry(QRect(QPoint(50, 50), QSize(100, 20)));
    comboBox->setEditable(true);
    
    QStringList comboItems;
    comboItems << "Alpha" << "Bravo" << "Charlie" << "Delta" << "Echo";
    
    SlotMachine *slotMachine = new SlotMachine();
    QObject::connect(comboBox, SIGNAL(editTextChanged(QString)), slotMachine, SLOT(UpdateItem(QString)));
    QObject::connect(comboBox, SIGNAL(activated(QString)), slotMachine, SLOT(SelectItem(QString)));
    comboBox->addItems(comboItems);
    
    window->show();
    
    return app.exec();
    

    }
    @

    With this code watch what happens when you just change the selection. Since no text has been changed, I fail to understand why the editTextChanged() signal is emitted!!!


  • Moderators

    If I understand Volker correct it is a different focus of what is meant. "editText" is the name of the field. If you give it an arbitrary name like "xyz" the signals shall say "xyzChanged", we understood more "xyzEdited", but that is not the meaning.

    if you assume a combox with three entries:
    entry1
    entry2
    entry3

    I see basically different cases possible:

    case 1. the selection of the field has been changed e.g. from entry1 to entry3.
    case 2. the number of entries has been extended e.g. type over entry1 entry4.

    What are the signals for these two cases?

    case 1.
    editTextChanged()
    activated()

    case 2.
    ????

    I understand that the last case is your problem. You need to know when this happens, because of additional or other activities required. Is that write?



  • [quote author="chax0" date="1313061980"]Since no text has been changed, I fail to understand why the editTextChanged() signal is emitted!!![/quote]

    Because it's programmed this way:

    from qcombobox.cpp:

    @
    void QComboBoxPrivate::_q_itemSelected(const QModelIndex &item)
    {
    Q_Q(QComboBox);
    if (item != currentIndex) {
    setCurrentIndex(item);
    } else if (lineEdit) {
    lineEdit->selectAll();
    lineEdit->setText(q->itemText(currentIndex.row()));
    }
    emitActivated(currentIndex);
    }
    @

    • Suppose you have a editable line edit
    • select alpha, signals are emitted
    • type something into the line edit
    • the current item is not changed this way
    • want to reset the text, so open the popup, re-select the very same item "alpha"
    • the current item has not changed, but the line edit's text is reset to "alpha", thus editTextChanged is emitted

    Now leave out the "type something into the line edit" step and replay.

    I still don't get the use case. I don't see any relation between and editTextChanged/Update and activated/select.

    Why do you differentiate between both?
    Is it needed that the combo box is editable?

    Describe your use case in words, not in code :)



  • OK, here is the use case in words, and not in code :)

    Imagine that the combobox is a list of sandwiches and burgers in a sandwich shop. The list is initially populated with a list of sandwiches that the shop sells - burger, cheeseburger, BLT, PB&J etc. Selecting a sandwich shows the ingredients of the sandwich, the type of bread and so on in other widgets on the form. Next to the combo box are two buttons that allow the user to add and remove sandwiches to/from the list. Sandwiches are added to the list with system generated names. The user is allowed to edit new/existing sandwich names using the editable combobox.

    Given the scenario above, I would like that when the user edits the name of the sandwich in the combobox, the new/edited name is propagated back to the data store that contains the sandwich list, where the name is applied. I would also like that when an existing sandwich is selected in the combobox, the corresponding sandwich is made current in the list, and its list of ingredients is fetched/displayed. Selecting a sandwich from the list does not imply a change/edit, and therefore the editTextChanged signal seems inappropriate in that scenario.



  • I'm not sure if an editable combobox is the right approach for this... It usually is for selecting preexisting entities (a read-only combobox) or for giving some reasonable default values to choose of for a free text field.

    If you type on the text of an existing entry, that entry is not changed, but a new entry for the combobox is created.

    I'm not sure if it's possible at all to make the combo box work as you want.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.