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. [SOLVED]which widget would be the best to display the following data?
QtWS25 Last Chance

[SOLVED]which widget would be the best to display the following data?

Scheduled Pinned Locked Moved General and Desktop
18 Posts 4 Posters 6.5k Views
  • 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.
  • P Offline
    P Offline
    phamtv
    wrote on 7 Mar 2011, 17:26 last edited by
    #1

    I am implementing an application that communicates to an end device via usb/serial every second. I need a control that will list all the register name and the current value of the registers for the device. I was thinking about using a QTableview to do this but it looks like it may take a long time to do any updates to the table for I don´t see anyway to directly assign a register to a row. NOTE: my register data is stored in a struct array. Every second, I poll the device registers, store the data to my array, and emit a signal if the value I have stored for a particular register does not that of the value I just polled. Thanks ahead for your time and effort...

    1 Reply Last reply
    0
    • D Offline
      D Offline
      dialingo
      wrote on 7 Mar 2011, 17:52 last edited by
      #2

      Itemview widgets are very good candidates to solve your problem.
      Choose among QTableView, QListView or QTreeView depending on the structure of your data.
      1 record per second is not a problem at all. If your experiments showed a behaviour which was too sluggish I suspect that you did not emit the dataChanged signal when a new record arrived.

      If you do not want to mess around with model view programming your usecase can also be solved with QTableWidget or QTreeWidget.

      1 Reply Last reply
      0
      • G Offline
        G Offline
        giesbert
        wrote on 7 Mar 2011, 19:05 last edited by
        #3

        Item views would definitly fit best. The update frequency should also not be a problem, we have some similar szenario here. We use a table views for thos data displays. For some also trees.

        What we do is we have some background thread collecting the data and doing comparsion and only send data changes to the model which then updates the view. The tests for did for performance showed us that trees with many items (>10000) whould get a bit slowely....

        Nokia Certified Qt Specialist.
        Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

        1 Reply Last reply
        0
        • P Offline
          P Offline
          phamtv
          wrote on 7 Mar 2011, 21:50 last edited by
          #4

          Hi Gerolf,

          I am assuming you are using the model/view programming approach. Do you happen to have code snippets of your implementation that I can view? Since the first reply to this post, I´ve looked at the model/view tutorial. I kind of understand the concept, however, the auto-data population and the capturing of the user editing value is what I am still a little puzzled on. Thanks for your time and support...

          1 Reply Last reply
          0
          • A Offline
            A Offline
            andre
            wrote on 8 Mar 2011, 06:52 last edited by
            #5

            It sounds like that you don't have to bother with users editing the data, as your data is for display purposes and is updated by your backend. That makes implementing the model simpler.
            What is important to remember, is that you try to be as specific as possible in signalling what data has changed. Only then, the view can optimize properly what part of the view needs to be withdrawn.

            1 Reply Last reply
            0
            • G Offline
              G Offline
              giesbert
              wrote on 8 Mar 2011, 07:50 last edited by
              #6

              Hi phamtv,

              sorry, no code snippets here. It's closed source. But It's not difficult. I suggest to first implement the model displaying the data without updates from a background thread. Think of the data structures to display and display them (in a tree view, table view, however). When this is working, implement the collector thread and create the data tree there.

              What is then missing is just: compare old tree with new tree, build diff data and send it via signal/slot to the model.

              Nokia Certified Qt Specialist.
              Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

              1 Reply Last reply
              0
              • A Offline
                A Offline
                andre
                wrote on 8 Mar 2011, 08:05 last edited by
                #7

                My tip: try to stick to a simple model at first, a list or a table. Don't start your first model implementation with a tree model. They are just plain hard. For a table model, you can start with subclassing QAbstractTableModel, which simplifies the interface for QAbstractItemModel for the table case.

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  dialingo
                  wrote on 8 Mar 2011, 09:16 last edited by
                  #8

                  phamtv,
                  Qt 4.7.1 comes with a neat tutorial which shows also how to deal with changing models.
                  http://doc.qt.nokia.com/4.7/modelview.html

                  interesting for you: 2.3, a clock inside a table cell.

                  1 Reply Last reply
                  0
                  • P Offline
                    P Offline
                    phamtv
                    wrote on 11 Mar 2011, 17:08 last edited by
                    #9

                    dialingo/Andre/Gerolf,

                    I have the following code implementation, however, when I run the application, the tableview controls is shown but does not populate with the rows and columns data... Any idea what is going on? NOTE: I simplified it into 3 files...

                    @
                    // File: cls_device.h
                    #ifndef CLS_DEVICE_H
                    #define CLS_DEVICE_H

                    #include <QtGui>
                    #include <QObject>
                    #include <QThread>
                    #include <QMap>
                    #include <QtDebug>

                    struct RegData
                    {
                    QString Desc;
                    int Addr;
                    double Value;
                    };

                    class RegisterModel : public QAbstractTableModel
                    {
                    Q_OBJECT
                    public:
                    RegisterModel(){}

                    void setCurrencyMap(const QMap<QString, double> &map)
                    {
                        registerMap = map;
                        reset();
                    }
                    
                    int rowCount(const QModelIndex & /* parent */) const
                    {
                        qDebug() << registerMap.count();
                        return registerMap.count();
                    }
                    
                    int columnCount(const QModelIndex & /* parent */) const
                    {
                        return 2; //registerMap.count();
                    }
                    Qt::ItemFlags flags(const QModelIndex & index) const
                    {
                        if (index.column() == 0)
                            return Qt::ItemIsSelectable | Qt::ItemIsEnabled ;
                        else
                            return Qt::ItemIsSelectable |  Qt::ItemIsEditable | Qt::ItemIsEnabled ;
                    }
                    bool setData(const QModelIndex & index, const QVariant & value, int role)
                    {
                        if (index.isValid() && role == Qt::EditRole)
                        {
                            ValueAt(index.row()) = value.toString();
                        }
                        return true;
                     }
                    QVariant data(const QModelIndex &index, int role) const
                    {
                        // NOTE: int role == Qt.ItemDataRole
                    
                        if (!index.isValid())
                            return QVariant();
                    
                        switch(role)
                        {
                        case Qt::TextAlignmentRole:
                            if (index.column() == 0)
                                return int(Qt::AlignLeft | Qt::AlignVCenter);
                            else if (index.column() == 1)
                                return int(Qt::AlignHCenter | Qt::AlignVCenter);
                            else
                                return QVariant();
                            break;
                        case Qt::DisplayRole:
                            if (index.column() == 0)
                                return DescAt(index.row());
                            else if (index.column() == 1)
                                return ValueAt(index.row());
                            else
                                return QVariant();
                            break;
                        }
                        return QVariant();
                    }
                    
                    QVariant headerData(int section, Qt::Orientation orientation, int role) const
                    {
                        if (role != Qt::DisplayRole)
                            return QVariant();
                    
                        if (orientation == Qt::Horizontal)
                            return (section == 0) ? "Register" : "Value";
                        else
                            DescAt(section);
                    }
                    

                    private:
                    QString DescAt(int offset) const
                    {
                    return (registerMap.begin() + offset).key();
                    }

                    QString ValueAt(int offset) const
                    {
                        return QString("%1").arg((registerMap.begin() + offset).value());
                    }
                    
                    QMap<QString, double> registerMap;
                    

                    };

                    class cls_Device : public QThread
                    {
                    Q_OBJECT

                    public:
                    RegData* data[10];

                    cls_Device()
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            // example
                            if (i == 5)
                            {
                                data[i] = NULL;
                                continue;
                            }
                            data[i] = new RegData();
                            data[i]->Desc = QString("Register %1").arg(i);
                    
                            qDebug() << data[i]->Desc;
                    
                            data[i]->Addr = i;
                            data[i]->Value = 1;
                        }
                    }
                    ~cls_Device(){}   // destructor
                    
                    void run()
                    {
                        Read();
                    }
                    
                    void Read()
                    {
                        for (int i = 0; i < 10; i++)
                        {
                    
                        }
                    }
                    void Write()
                    {
                    }
                    

                    signals:

                    public slots:

                    };

                    #endif // CLS_DEVICE_H

                    // file: mainwindow.h
                    #ifndef MAINWINDOW_H
                    #define MAINWINDOW_H

                    #include <QMainWindow>
                    #include <QTableView>
                    #include <QLayout>
                    #include <cls_device.h>
                    #include <currencymodel.h>

                    //namespace Ui {
                    // class MainWindow;
                    //}

                    class MainWindow : public QMainWindow
                    {
                    Q_OBJECT

                    public:
                    QMap<QString, double> registerMap;
                    cls_Device* device;

                    explicit MainWindow(QWidget *parent = 0)
                    {
                        device = new cls_Device();
                        for (int i = 0; i < 10; i++)
                        {
                            if (device->data[i] != NULL)
                                registerMap.insert(device->data[i]->Desc, device->data[i]->Value);
                        }
                    
                        RegisterModel registerModel;
                        registerModel.setCurrencyMap(registerMap);
                    
                        QTableView* tableView = new QTableView();
                        tableView->setModel(&registerModel);
                        tableView->setAlternatingRowColors(true);
                        tableView->verticalHeader()->hide();
                        tableView->horizontalHeader()->setStretchLastSection(true);
                        tableView->resizeColumnsToContents();
                        tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
                        setCentralWidget(tableView);
                    
                        QTimer* timer = new QTimer(this);
                        timer->setInterval(1000);
                        connect(timer, SIGNAL(timeout()) , this, SLOT(timerHit()));
                        timer->start();
                    }
                    ~MainWindow()
                    {
                        disconnect();
                    
                        if (device != NULL)
                            delete device;
                    }
                    

                    public slots:
                    void timerHit()
                    {
                    }

                    };
                    #endif // MAINWINDOW_H

                    // File: main.cpp
                    #include <QObject>
                    #include <QtGui>
                    #include <mainwindow.h>

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

                    MainWindow window;
                    window.showMaximized();
                    return app.exec();
                    

                    }
                    @

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      andre
                      wrote on 11 Mar 2011, 17:15 last edited by
                      #10

                      You should create your model on the heap, not on the stack ( line 193 ). Now, your model is destroyed again before the data is actually shown.

                      1 Reply Last reply
                      0
                      • G Offline
                        G Offline
                        giesbert
                        wrote on 11 Mar 2011, 17:20 last edited by
                        #11

                        Hi,

                        the problem is pretty easy:

                        you create the register model on the stack
                        set it to the view and then, when the c'tor goes out of scope, the model is deleted.

                        create the reister model on the heap as follows:

                        @

                        explicit MainWindow(QWidget *parent = 0)
                        {
                            device = new cls_Device();
                            for (int i = 0; i < 10; i++)
                            {
                                if (device->data[i] != NULL)
                                    registerMap.insert(device->data[i]->Desc, device->data[i]->Value);
                            }
                        
                            RegisterModel* registerModel = new RegisterModel(this);
                            registerModel->setCurrencyMap(registerMap);
                        
                            QTableView* tableView = new QTableView();
                            tableView->setModel(registerModel);
                            tableView->setAlternatingRowColors(true);
                            tableView->verticalHeader()->hide();
                            tableView->horizontalHeader()->setStretchLastSection(true);
                            tableView->resizeColumnsToContents();
                            tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
                            setCentralWidget(tableView);
                        
                            QTimer* timer = new QTimer(this);
                            timer->setInterval(1000);
                            connect(timer, SIGNAL(timeout()) , this, SLOT(timerHit()));
                            timer->start();
                        }
                        

                        @

                        aditionally, the creator of RegisterModel should look like this:

                        @
                        RegisterModel(QObject* pParent) :
                        QAbstractTableModel(pParent)
                        {
                        }

                        @

                        Nokia Certified Qt Specialist.
                        Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                        1 Reply Last reply
                        0
                        • P Offline
                          P Offline
                          phamtv
                          wrote on 11 Mar 2011, 19:21 last edited by
                          #12

                          thanks Gerolf for the quick response!!!

                          1 Reply Last reply
                          0
                          • A Offline
                            A Offline
                            andre
                            wrote on 11 Mar 2011, 19:25 last edited by
                            #13

                            -Actually, the code Gerolf presents causes a memory leak. Don't forget to give the model a parent in on line 13 of that piece of code. Candidates for parents are the form, or the view itself.-

                            I misread the code, there is no leak.

                            1 Reply Last reply
                            0
                            • G Offline
                              G Offline
                              giesbert
                              wrote on 11 Mar 2011, 19:29 last edited by
                              #14

                              Andre, let me correct you.
                              The memory leak does not exist, as setCentralWidget reparents the widget (look at the docs) and takes the ownership.

                              But I also think, it looks better to give the QTableView a parent on construction....

                              Nokia Certified Qt Specialist.
                              Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                              1 Reply Last reply
                              0
                              • A Offline
                                A Offline
                                andre
                                wrote on 11 Mar 2011, 19:35 last edited by
                                #15

                                I am sorry, you are right. I misread the code, and thought you did not give the model a parent. But you do. I stand corrected.

                                1 Reply Last reply
                                0
                                • P Offline
                                  P Offline
                                  phamtv
                                  wrote on 11 Mar 2011, 19:54 last edited by
                                  #16

                                  Thanks guys for your support. I have a follow up question to my model/view implementation. I added some code to spawn another thread to generate some random number, however, I don´t know how to update the table view when I receive the signal to update the table view. Can you guys give me some input? Thanks!

                                  @
                                  // file: cls_device.h
                                  #ifndef CLS_DEVICE_H
                                  #define CLS_DEVICE_H

                                  #include <QtGui>
                                  #include <QObject>
                                  #include <QThread>
                                  #include <QMap>
                                  #include <QtDebug>

                                  struct RegData
                                  {
                                  QString Desc;
                                  int Addr;
                                  double Value;
                                  };

                                  class RegisterModel : public QAbstractTableModel
                                  {
                                  Q_OBJECT
                                  public:
                                  RegisterModel(QObject* pParent) :
                                  QAbstractTableModel(pParent){}

                                  void setCurrencyMap(const QMap<QString, double> &map)
                                  {
                                      registerMap = map;
                                      reset();
                                  }
                                  
                                  int rowCount(const QModelIndex & /* parent */) const
                                  {
                                      return registerMap.count();
                                  }
                                  
                                  int columnCount(const QModelIndex & /* parent */) const
                                  {
                                      return 2; //registerMap.count();
                                  }
                                  Qt::ItemFlags flags(const QModelIndex & index) const
                                  {
                                      if (index.column() == 0)
                                          return Qt::ItemIsSelectable | Qt::ItemIsEnabled ;
                                      else
                                          return Qt::ItemIsSelectable |  Qt::ItemIsEditable | Qt::ItemIsEnabled ;
                                  }
                                  bool setData(const QModelIndex & index, const QVariant & value, int role)
                                  {
                                      if (index.isValid() && role == Qt::EditRole)
                                      {
                                          ValueAt(index.row()) = value.toString();
                                      }
                                      return true;
                                   }
                                  QVariant data(const QModelIndex &index, int role) const
                                  {
                                      // NOTE: int role == Qt.ItemDataRole
                                  
                                      if (!index.isValid())
                                          return QVariant();
                                  
                                      switch(role)
                                      {
                                      case Qt::TextAlignmentRole:
                                          if (index.column() == 0)
                                              return int(Qt::AlignLeft | Qt::AlignVCenter);
                                          else if (index.column() == 1)
                                              return int(Qt::AlignHCenter | Qt::AlignVCenter);
                                          else
                                              return QVariant();
                                          break;
                                      case Qt::DisplayRole:
                                          if (index.column() == 0)
                                              return DescAt(index.row());
                                          else if (index.column() == 1)
                                              return ValueAt(index.row());
                                          else
                                              return QVariant();
                                          break;
                                      }
                                      return QVariant();
                                  }
                                  
                                  QVariant headerData(int section, Qt::Orientation orientation, int role) const
                                  {
                                      if (role != Qt::DisplayRole)
                                          return QVariant();
                                  
                                      if (orientation == Qt::Horizontal)
                                          return (section == 0) ? "Register" : "Value";
                                      else
                                          DescAt(section);
                                  }
                                  

                                  private:
                                  QString DescAt(int offset) const
                                  {
                                  return (registerMap.begin() + offset).key();
                                  }

                                  QString ValueAt(int offset) const
                                  {
                                      return QString("%1").arg((registerMap.begin() + offset).value());
                                  }
                                  
                                  QMap<QString, double> registerMap;
                                  

                                  };

                                  class cls_Device : public QThread
                                  {
                                  Q_OBJECT

                                  public:
                                  RegData* data[10];

                                  cls_Device()
                                  {
                                      for (int i = 0; i < 10; i++)
                                      {
                                          // example
                                          if (i == 5)
                                          {
                                              data[i] = NULL;
                                              continue;
                                          }
                                          data[i] = new RegData();
                                          data[i]->Desc = QString("Register %1").arg(i);
                                          data[i]->Addr = i;
                                          data[i]->Value = 1;
                                      }
                                  }
                                  ~cls_Device(){}   // destructor
                                  
                                  void run()
                                  {
                                      Read();
                                  }
                                  
                                  void Read()
                                  {
                                      int min = 0;
                                      int max = 255;
                                  
                                      for (int i = 0; i < 10; i++)
                                      {
                                          double val = int( random() / (RAND_MAX + 1.0) * (max + 1 - min) + min );
                                          if ((data[i] != NULL) && (data[i]->Value != val))
                                          {
                                              data[i]->Value = val;
                                              emit RegisterValueChanged(this, data[i]);
                                          }
                                      }
                                  }
                                  void Write()
                                  {
                                  }
                                  

                                  signals:
                                  void RegisterValueChanged(QObject* obj, RegData* e);
                                  public slots:

                                  };

                                  #endif // CLS_DEVICE_H

                                  // file: mainwindow.h
                                  #ifndef MAINWINDOW_H
                                  #define MAINWINDOW_H

                                  #include <QMainWindow>
                                  #include <QTableView>
                                  #include <QLayout>
                                  #include <cls_device.h>
                                  #include <currencymodel.h>

                                  class MainWindow : public QMainWindow
                                  {
                                  Q_OBJECT

                                  public:
                                  QMap<QString, double> registerMap;
                                  cls_Device* device;

                                  explicit MainWindow(QWidget *parent = 0)
                                  {
                                      device = new cls_Device();
                                      connect(device, SIGNAL(RegisterValueChanged(QObject*,RegData*)),
                                              this, SLOT(RegisterValueChanged(QObject*,RegData*)), Qt::QueuedConnection);
                                  
                                      for (int i = 0; i < 10; i++)
                                      {
                                          if (device->data[i] != NULL)
                                              registerMap.insert(device->data[i]->Desc, device->data[i]->Value);
                                      }
                                  
                                      RegisterModel* registerModel = new RegisterModel(this);
                                      registerModel->setCurrencyMap(registerMap);
                                  
                                      QTableView* tableView = new QTableView(this);
                                      tableView->setModel(registerModel);
                                      tableView->setAlternatingRowColors(true);
                                      tableView->verticalHeader()->hide();
                                      tableView->horizontalHeader()->setStretchLastSection(true);
                                      tableView->resizeColumnsToContents();
                                      tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
                                      setCentralWidget(tableView);
                                  
                                      QTimer* timer = new QTimer(this);
                                      timer->setInterval(1000);
                                      connect(timer, SIGNAL(timeout()) , this, SLOT(timerHit()));
                                      timer->start();
                                  }
                                  ~MainWindow()
                                  {
                                      disconnect();
                                  
                                      if (device != NULL)
                                          delete device;
                                  }
                                  

                                  public slots:
                                  void timerHit()
                                  {
                                  if (!device->isRunning())
                                  device->start();
                                  }

                                  private slots:
                                  void RegisterValueChanged(QObject* obj, RegData* e)
                                  {
                                  qDebug() << QString("How do I update the table view for Register address %1 with value %2").arg(e->Addr).arg(e->Value);
                                  }
                                  };

                                  #endif // MAINWINDOW_H

                                  // file main.cpp
                                  //use the previous code snippet

                                  @

                                  1 Reply Last reply
                                  0
                                  • G Offline
                                    G Offline
                                    giesbert
                                    wrote on 11 Mar 2011, 20:03 last edited by
                                    #17

                                    You should start reading the "docs":http://doc.qt.nokia.com/4.7/modelview.html :-)
                                    When you want to change a value, you have to emit a signal dataChange() and change the value before.
                                    If you want to add/remnove rows/columns, there are also signals, which are emitted by special functions

                                    [begin|end][insert|remove][Columns|rows]

                                    Nokia Certified Qt Specialist.
                                    Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                                    1 Reply Last reply
                                    0
                                    • P Offline
                                      P Offline
                                      phamtv
                                      wrote on 11 Mar 2011, 20:17 last edited by
                                      #18

                                      Hi Gerolf, Thanks!, :-) I have been reading the docs but just can´t seem to connect things together. As you can see in my implementation, I have an inherited QThread class that initializes my structure pointer array. If you have noticed, I intentionally place a null pointer to register 5 because I do not have a continguous set of register in my real world scenario. QMap basically is a subset of my structure pointer array without the null pointer. I can populate the table view with RegisterModel using QMap. However, as you can see, when my thread executes, it changes the structure array value. Do I have to loop through the QMap items, compare the description strings, and then update TableView by emitting a signal dataChange()? This seem time consuming if I have loop through the QMaps items for every registers that changes.... Please advise...

                                      1 Reply Last reply
                                      0

                                      1/18

                                      7 Mar 2011, 17:26

                                      • Login

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