Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. creating list with variable number of entries
Forum Updated to NodeBB v4.3 + New Features

creating list with variable number of entries

Scheduled Pinned Locked Moved Unsolved General and Desktop
26 Posts 5 Posters 4.0k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • mzimmersM Offline
    mzimmersM Offline
    mzimmers
    wrote on last edited by mzimmers
    #1

    Hi all -

    It turns out that I need to give the user a dialog that enables him to enter a small number (single digits) of IP addresses. The exact number is up to the user.

    Never having actually done this before, the first thing that came to mind was something like a box in which the user could put exactly 1 IP address. To the right of the box would be a "+" sign, which, when pressed, would cause another box and "+" to appear below. The dialog would have commit and cancel buttons as well, of course.

    1. opinions on this?
    2. which Qt GUI construct might be best for this? I've looked through the "long" list, and don't see anything that provided quite the degree of automation I hoped for.

    ADDED: it's probably worth pointing out that this need not be model data; a simple QList will be adequate.

    Thanks...

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      A QListWidget with a + button at bottom comes to mind for that.

      Add a custom QStyledItemDelegate that returns a QLineEdit with a validator to ensure the content is a valid IP address.

      An alternative is to have a QLineEdit on top of the QListWidget with an Add button beside and when the button is clicked clear the line edit after having added its content to the QListWidget.

      Don't forget to add a - button to delete entries from the list widget.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      mzimmersM 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi,

        A QListWidget with a + button at bottom comes to mind for that.

        Add a custom QStyledItemDelegate that returns a QLineEdit with a validator to ensure the content is a valid IP address.

        An alternative is to have a QLineEdit on top of the QListWidget with an Add button beside and when the button is clicked clear the line edit after having added its content to the QListWidget.

        Don't forget to add a - button to delete entries from the list widget.

        mzimmersM Offline
        mzimmersM Offline
        mzimmers
        wrote on last edited by
        #3

        @SGaist thanks for the suggestion. I've created the QListWidget in Designer, and am attempting to populate it with this slot:

        void Informacast::serversReceived(Message *msg)
        {
            vector<string> ipList;
            vector<string>::iterator it;
            string value;
            QListWidgetItem ip;
        
            ipList = msg->findKeys(MsgTagText[TAG_IC_SERVER]);
            ui->listWidgetServers->clear();
            for (it = ipList.begin(); it != ipList.end(); ++it)
            {
                value = msg->getValue(*it);
                ip.setText(QString::fromStdString(value));
                ui->listWidgetServers->addItem(&ip);
            }
        }
        

        Stepping through the debugger, everything looks OK to me, but nothing displays. Do I need to forcibly update the display? I don't see how I would be blocking the event loop.

        Also, you mentioned buttons -- are you talking about regular push buttons?

        Thanks...

        jsulmJ 1 Reply Last reply
        0
        • mzimmersM mzimmers

          @SGaist thanks for the suggestion. I've created the QListWidget in Designer, and am attempting to populate it with this slot:

          void Informacast::serversReceived(Message *msg)
          {
              vector<string> ipList;
              vector<string>::iterator it;
              string value;
              QListWidgetItem ip;
          
              ipList = msg->findKeys(MsgTagText[TAG_IC_SERVER]);
              ui->listWidgetServers->clear();
              for (it = ipList.begin(); it != ipList.end(); ++it)
              {
                  value = msg->getValue(*it);
                  ip.setText(QString::fromStdString(value));
                  ui->listWidgetServers->addItem(&ip);
              }
          }
          

          Stepping through the debugger, everything looks OK to me, but nothing displays. Do I need to forcibly update the display? I don't see how I would be blocking the event loop.

          Also, you mentioned buttons -- are you talking about regular push buttons?

          Thanks...

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @mzimmers said in creating list with variable number of entries:

          QListWidgetItem ip;

          This only exists inside serversReceived()!
          It can't work like that.
          You need to create one QListWidgetItem instance on the heap for each entry in ui->listWidgetServers.

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          mzimmersM 1 Reply Last reply
          0
          • jsulmJ jsulm

            @mzimmers said in creating list with variable number of entries:

            QListWidgetItem ip;

            This only exists inside serversReceived()!
            It can't work like that.
            You need to create one QListWidgetItem instance on the heap for each entry in ui->listWidgetServers.

            mzimmersM Offline
            mzimmersM Offline
            mzimmers
            wrote on last edited by
            #5

            @jsulm ahh...I had assumed that the QListWidget actually contained a list (in the C++ STL sense), so I didn't think I needed to keep a separate copy of the contents. Thanks for the clarification.

            This seems to work a bit better:

            void Informacast::serversReceived(Message *msg)
            {
                list<string>::iterator it;
                QString value;
            
                ui->listWidgetServers->clear();
            
                // get the aaddress from the message; store in a STL list.
                m_ipList = msg->findKeys(MsgTagText[TAG_IC_SERVER]);
            
                // for each element in the list
                for (it = m_ipList.begin(); it != m_ipList.end(); ++it)
                {
                    //get the value(the IP address) from the key.
                    value = QString::fromStdString(msg->getValue(*it));
            
                    // add the element to the QListWidget.
                    ui->listWidgetServers->addItem(value);
                }
            }
            
            1 Reply Last reply
            0
            • mzimmersM Offline
              mzimmersM Offline
              mzimmers
              wrote on last edited by
              #6

              The code above wasn't storing the correct information in my member list, so I've modified it:

              vector<QListWidgetItem> m_ipList;
              
              void Informacast::serversReceived(Message *msg)
              {
                  list<string> keys;
                  list<string>::iterator it;
                  QString value;
              
                
                  ui->listWidgetServers->clear();
              
                  // get the address from the message; store in a STL list.
                  keys = msg->findKeys(MsgTagText[TAG_IC_SERVER]);
              
                  // for each element in the list
                  for (it = keys.begin(); it != keys.end(); ++it)
                  {
                      //get the value(the IP address) from the key.
                      value = QString::fromStdString(msg->getValue(*it));
              
                      // add the element to our list of IPs.
                      m_ipList.push_back(QListWidgetItem(value));
                    
                      // add the element to the QListWidget.
                      ui->listWidgetServers->addItem(value);
                  }
              }
              

              So, do I correctly infer that, because the QListWidget doesn't use a model, it's up to me to update my data that is reflected in the list? For example, when the user adds, edits or deletes a row in the list, I need to maintain my list of items as well as the QListWidget?

              Also, to SGaist: I definitely do want to validate the entries, but it's not clear how to use the QStyledItemDelegate if I'm not using a model.

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #7

                QListWidget has an internal model.

                You can get its content using the item method and then get the string from item.

                The custom delegate in this case should only implement the createEditor method where you will return the customized QLineEdit.

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                mzimmersM 1 Reply Last reply
                3
                • SGaistS SGaist

                  QListWidget has an internal model.

                  You can get its content using the item method and then get the string from item.

                  The custom delegate in this case should only implement the createEditor method where you will return the customized QLineEdit.

                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #8

                  @SGaist said in creating list with variable number of entries:

                  QListWidget has an internal model.

                  You can get its content using the item method and then get the string from item.

                  OK, this sounds like I don't need to maintain my own list then, correct? So, the list does actually contain a "real" list of information about its contents?

                  The custom delegate in this case should only implement the createEditor method where you will return the customized QLineEdit.

                  I guess I need to read more on delegates. The way I've currently implemented it, when the list emits a itemClicked() signal, I call openPersistentEditor(). Is this not the preferred way of doing this?

                  I already have a validator for IP addresses:

                  class IpValidator : public QValidator
                  {
                  public:
                      IpValidator(QObject *parent = nullptr) : QValidator(parent) {}
                      QValidator::State validate(QString &input, int &pos) const;
                  };
                  

                  So, do I need to extract the text from the selected item, set the validator on it, and then call createEditor()?

                  Thanks...

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    No, you don't have to maintain a copy.

                    In the createEditor function, you just create a QLineEdit, your validator that you apply to your QLineEdit and then return it.

                    The loading of the editor content is done for you automatically later on.

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    mzimmersM 1 Reply Last reply
                    1
                    • SGaistS SGaist

                      No, you don't have to maintain a copy.

                      In the createEditor function, you just create a QLineEdit, your validator that you apply to your QLineEdit and then return it.

                      The loading of the editor content is done for you automatically later on.

                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #10

                      @SGaist so, I subclass QItemDelegate and override the createEditor() method? What do I specify as the model?

                      Thanks...

                      1 Reply Last reply
                      0
                      • SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        No, QStyledItemDelegate.

                        The item delegate is applied on the view.

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        mzimmersM 1 Reply Last reply
                        1
                        • SGaistS SGaist

                          No, QStyledItemDelegate.

                          The item delegate is applied on the view.

                          mzimmersM Offline
                          mzimmersM Offline
                          mzimmers
                          wrote on last edited by
                          #12

                          @SGaist OK, I looked at the StarDelegate example. I don't really know what I'm doing, but I created this:

                          class ICdelegate : public QStyledItemDelegate
                          {
                              Q_OBJECT
                          private:
                          public:
                              QLineEdit *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                                                    const QModelIndex &index) const override
                              {
                                  static QLineEdit qle;
                                  const IpValidator *ipValidator;
                                  qle.setValidator(ipValidator);
                          
                                  return const_cast<QLineEdit *>(&qle);
                              }
                          };
                          

                          I get a segfault on the call to setValidator(). I'm sure I'm overlooking something obvious (I know I'm not using any of the arguments passed to the function), but I can't see what it is.

                          Thanks...

                          jsulmJ 1 Reply Last reply
                          0
                          • mzimmersM mzimmers

                            @SGaist OK, I looked at the StarDelegate example. I don't really know what I'm doing, but I created this:

                            class ICdelegate : public QStyledItemDelegate
                            {
                                Q_OBJECT
                            private:
                            public:
                                QLineEdit *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                                                      const QModelIndex &index) const override
                                {
                                    static QLineEdit qle;
                                    const IpValidator *ipValidator;
                                    qle.setValidator(ipValidator);
                            
                                    return const_cast<QLineEdit *>(&qle);
                                }
                            };
                            

                            I get a segfault on the call to setValidator(). I'm sure I'm overlooking something obvious (I know I'm not using any of the arguments passed to the function), but I can't see what it is.

                            Thanks...

                            jsulmJ Offline
                            jsulmJ Offline
                            jsulm
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            @mzimmers said in creating list with variable number of entries:

                            I get a segfault on the call to setValidator()

                            Of course you do as you're passing a dangling pointer - your ipValidator is not pointing to an IpValidator instance.

                            https://forum.qt.io/topic/113070/qt-code-of-conduct

                            1 Reply Last reply
                            3
                            • mrjjM Offline
                              mrjjM Offline
                              mrjj
                              Lifetime Qt Champion
                              wrote on last edited by
                              #14

                              Hi

                               QLineEdit *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                                                        const QModelIndex &index) const override
                                  {
                                      static QLineEdit qle; // not good idea as i think its deleted for you.. so new it
                                      const IpValidator *ipValidator; // this needs to be newed too
                                      qle.setValidator(ipValidator);
                              
                                      return const_cast<QLineEdit *>(&qle);
                                  }
                              
                              mzimmersM 1 Reply Last reply
                              1
                              • mrjjM mrjj

                                Hi

                                 QLineEdit *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                                                          const QModelIndex &index) const override
                                    {
                                        static QLineEdit qle; // not good idea as i think its deleted for you.. so new it
                                        const IpValidator *ipValidator; // this needs to be newed too
                                        qle.setValidator(ipValidator);
                                
                                        return const_cast<QLineEdit *>(&qle);
                                    }
                                
                                mzimmersM Offline
                                mzimmersM Offline
                                mzimmers
                                wrote on last edited by
                                #15

                                @mrjj do I correctly understand that using "new" to create Qt objects here, without a corresponding "delete," will not cause a memory leak?

                                In any event, I made the fixes suggested, and the program runs now. A couple of issues remain, though:

                                1. the QLineEdit shows up in its own window
                                2. the widget from which the QLineEdit is created retains control (I can't access the QLineEdit window until the main widget is closed). I'm guessing I can fix this with a call to activateWindow(), but I really don't want a separate window for this edit in the first place. I was hoping for "in-place" editing -- is this possible with a QListWidget?

                                Thanks for the help.

                                mrjjM 1 Reply Last reply
                                0
                                • mzimmersM mzimmers

                                  @mrjj do I correctly understand that using "new" to create Qt objects here, without a corresponding "delete," will not cause a memory leak?

                                  In any event, I made the fixes suggested, and the program runs now. A couple of issues remain, though:

                                  1. the QLineEdit shows up in its own window
                                  2. the widget from which the QLineEdit is created retains control (I can't access the QLineEdit window until the main widget is closed). I'm guessing I can fix this with a call to activateWindow(), but I really don't want a separate window for this edit in the first place. I was hoping for "in-place" editing -- is this possible with a QListWidget?

                                  Thanks for the help.

                                  mrjjM Offline
                                  mrjjM Offline
                                  mrjj
                                  Lifetime Qt Champion
                                  wrote on last edited by
                                  #16

                                  @mzimmers

                                  Hi , yes normally a new without delete is a leak but the design for the delegate is that you create editor and
                                  the View deletes it when finished editing.

                                  1. you dont assign the parent when you new it
                                    QLineEdit *ql = new QLineEdit(parent)
                                    Any widget without a parent becomes a window.

                                  2. fix 1 and 2 is non issue i think :)

                                  mzimmersM 1 Reply Last reply
                                  2
                                  • mrjjM mrjj

                                    @mzimmers

                                    Hi , yes normally a new without delete is a leak but the design for the delegate is that you create editor and
                                    the View deletes it when finished editing.

                                    1. you dont assign the parent when you new it
                                      QLineEdit *ql = new QLineEdit(parent)
                                      Any widget without a parent becomes a window.

                                    2. fix 1 and 2 is non issue i think :)

                                    mzimmersM Offline
                                    mzimmersM Offline
                                    mzimmers
                                    wrote on last edited by
                                    #17

                                    @mrjj Oh, that's a thing of beauty. Thanks for the reminder on that.

                                    And you're correct, adding the parent to the creation of the QLineEdit eliminated the new window.

                                    This issue is mostly fixed now, but there's still a bit of tuning I need to do:

                                    1. When editing a line, pressing the enter key exits the window. This is logical, but probably not what a lot of users expect. I need to cause it to exit the editor (I think). I think I could fix this by overriding the EditorEvent() method, but I don't know what I'd furnish for the model argument.
                                    2. It appears that the editor also remains open when the user clicks on a different line. Basically, the same issue as above (I think).

                                    Thanks again...

                                    mrjjM 1 Reply Last reply
                                    0
                                    • mzimmersM mzimmers

                                      @mrjj Oh, that's a thing of beauty. Thanks for the reminder on that.

                                      And you're correct, adding the parent to the creation of the QLineEdit eliminated the new window.

                                      This issue is mostly fixed now, but there's still a bit of tuning I need to do:

                                      1. When editing a line, pressing the enter key exits the window. This is logical, but probably not what a lot of users expect. I need to cause it to exit the editor (I think). I think I could fix this by overriding the EditorEvent() method, but I don't know what I'd furnish for the model argument.
                                      2. It appears that the editor also remains open when the user clicks on a different line. Basically, the same issue as above (I think).

                                      Thanks again...

                                      mrjjM Offline
                                      mrjjM Offline
                                      mrjj
                                      Lifetime Qt Champion
                                      wrote on last edited by
                                      #18

                                      @mzimmers
                                      Hi
                                      I don't recall pressing enter would do anything but finish editing so not sure all code is as it should be.
                                      Can you check your code against
                                      https://stackoverflow.com/questions/26614678/validating-user-input-in-a-qtableview
                                      As this is the same you want to do, using a Validator.
                                      It don't matters its other type of view. The delegate is the same.

                                      mzimmersM 1 Reply Last reply
                                      1
                                      • mrjjM mrjj

                                        @mzimmers
                                        Hi
                                        I don't recall pressing enter would do anything but finish editing so not sure all code is as it should be.
                                        Can you check your code against
                                        https://stackoverflow.com/questions/26614678/validating-user-input-in-a-qtableview
                                        As this is the same you want to do, using a Validator.
                                        It don't matters its other type of view. The delegate is the same.

                                        mzimmersM Offline
                                        mzimmersM Offline
                                        mzimmers
                                        wrote on last edited by mzimmers
                                        #19

                                        My code had some minor differences, but I changed them to match the example, and the behavior is the same.

                                        I did realize something, though -- I still had my itemClicked() signal calling a slot that used openPersistentEditor(). I'm guessing that this wasn't what I wanted. But when I disabled this, I get no editor at all. Here's where I use the delegate:

                                            ICdelegate *icDelegate = new ICdelegate;
                                            ui->listWidgetServers->setItemDelegate(icDelegate);
                                        

                                        Does this look OK to you?
                                        EDIT:
                                        PS: I didn't mention that I took SGaist's suggestion above to mean that the only method I overrode was createEditor() -- is this correct?
                                        UPDATE:
                                        here's my slot for when the item is double-clicked:

                                        connect(ui->listWidgetServers, &QListWidget::itemDoubleClicked, this, &Informacast::editItem);
                                        void Informacast::editItem(QListWidgetItem *item)
                                        {
                                            Qt::ItemFlags flags;
                                            flags = item->flags();
                                            flags |= Qt::ItemIsEditable;
                                            item->setFlags(Qt::ItemIsEditable);
                                            ui->listWidgetServers->editItem(item);
                                        }
                                        

                                        Still not editable, though the coloring changes:
                                        icast.PNG
                                        I feel that I'm close to getting this to work, but am overlooking something.

                                        1 Reply Last reply
                                        0
                                        • SGaistS Offline
                                          SGaistS Offline
                                          SGaist
                                          Lifetime Qt Champion
                                          wrote on last edited by
                                          #20

                                          AFAIR, items are editable by defaults.

                                          Did you set the edit triggers ?

                                          Interested in AI ? www.idiap.ch
                                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                          mzimmersM 1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved