QListView or Custom List of Widget?



  • Hi,

    I'm trying to achieve an interface similar to :
    https://www.dropbox.com/s/94sdayh0q5y4vfz/workoutList.png

    Of course this is not in QT. It is a web interface Copyright @Garmin for that.
    Basically It's a list, it's possible to add/remove/edit element to the list.
    The individual element of the list is a box containing info.

    I am thinking maybe a QList of custom QWidget to achieve that?
    Because I am not sure that QListView would be powerfull enought to let me customize my element in each row?
    Anyone with more experience in QT can recommend me?
    Thanks!



  • You can do that. You need to have custom delegate to alter the way the cells are shown in ListView. QList and Widget is not the right way and it require lot of custom code.

    You can look @ following link. It will help you.

    http://doc.qt.digia.com/qq/qq24-delegates.html



  • Inorder to do that you can follow the steps

    1. Create a custom widget that holds all the above data.
    2. You need to add the instance of the widget to the model.
    3. You need to have a custom delegate that should implement
    • paint()
    • createEditor()
    • setEditorData()
    • setModelData()

    for the delegate, in the paint() function you need to renders/fake's the widget with the data it holds for the current QModelIndex, then when a cell is clicked u need to create the actual widget and display.

    This method is recommended as there is another way to add the widget to the ListView using setIndexWidget() but it effects the performance heavily.

    Regards
    Sam



  • Thanks for your help guys.

    I finally opted to go for a custom QAbstractTableModel & TableView instead since I already used that one (reuse some of my code). I will try to find how to display widget in individual cell, but I guess delegate should be able to do it, after i'll have to connect those widget so that when they are edited the model get edited.
    I'll post back when I get some working code :0



  • Hey guys,

    I'm working on my Model, I used the "Address Book ":http://qt-project.org/doc/qt-5/qtwidgets-itemviews-addressbook-example.html and the "spinBox delegate":http://qt-project.org/doc/qt-5/qtwidgets-itemviews-spinboxdelegate-example.html example and it helped me a lot.

    I'm kind of stuck on a last thing. I have editor for normal field that work well (int, QString, QComboBox)
    But I have an editor that needs to edit 4 fields of my Object at the same time (int, double, double, int)

    I can retrieve that data from the model fine with data().
    but when it's time to update the model with setData(), I have some problem. I think it's a conversion problem with QVariant and my custom type.

    Here is my use case interface :
    https://www.dropbox.com/s/euguunbqx39eky7/QVariantConvert.png

    Here is my code :

    @//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {

    /// Type
    if (index.column() == 0) {
        IntervalComboBox *comboBox = static_cast<IntervalComboBox*>(editor);
        int value = comboBox->currentIndex();
        model->setData(index, value, Qt::EditRole);
    }
    
    /// Duration
    else if (index.column() == 1) {
        QTimeEdit *timeEdit = static_cast<QTimeEdit*>(editor);
        QTime time1 = timeEdit->time();
        model->setData(index, time1, Qt::EditRole);
    }
    
    /// Display Message
    else if (index.column() == 2) {
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        QString msg = lineEdit->text();
        model->setData(index, msg, Qt::EditRole);
    }
    
    /// Target Power (4 fields in Interval to change)
    else if (index.column() == 3) {
    
        EditTargetPowerWidget *targetWidget = static_cast<EditTargetPowerWidget*>(editor);
    
        int targetStepPower = targetWidget->stepComboBox->currentIndex();
        Interval::StepType stepType = static_cast<Interval::StepType>( targetStepPower );
        double startFTP = targetWidget->targetStartValue->value()/100;
        double endFTP = targetWidget->targetEndValue->value()/100;
        int range = targetWidget->targetRangeValue->value();
    
    
        std::shared_ptr<Interval> interval(new Interval() );
        interval->setPowerData(stepType, startFTP, endFTP, range);
        QVariant variant = interval;
        //        model->setData(index, variant, Qt::EditRole);
    
    
        /// CONVERT TEST (Should be done in setData() of the model when it works..)
        qDebug() << "Test CAN CONVERT2?" << variant.canConvert<std::shared_ptr<Interval>>();  //return false?
    
        /// Trying anyway...
        std::shared_ptr<Interval> interval2(qvariant_cast<std::shared_ptr<Interval>>( variant ));
        qDebug() << "TEST CONVERT:" << interval2->getFTP_start();
    
    
    }
    
    else {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
    

    }@

    SetEditorData (retrieve data) -- Working
    @
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void SpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {

    /// Type
    if (index.column() == 0) {
        int value =  index.model()->data(index, Qt::DisplayRole).toInt();
        IntervalComboBox *comboBox = static_cast<IntervalComboBox*>(editor);
        comboBox->setCurrentIndex(value);
    }
    
    /// Duration
    else if (index.column() == 1) {
        QTime time = index.model()->data(index, Qt::DisplayRole).toTime();
        QTimeEdit *timeEdit = static_cast<QTimeEdit*>(editor);
        timeEdit->setTime( time );
    }
    
    /// Display Message
    else if (index.column() == 2) {
    
        QString msg = index.model()->data(index, Qt::DisplayRole).toString();
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
        lineEdit->setText(msg);
    }
    
    /// Target Power
    else if (index.column() == 3) {
    
        std::shared_ptr<Interval> interval(qvariant_cast<std::shared_ptr<Interval>>( index.model()->data(index, Qt::DisplayRole) ));
    
        int targetStepPower = interval->getPowerStepType();
        double startFTP = interval->getFTP_start() * 100;
        double endFTP = interval->getFTP_end() * 100;
        int range = interval->getFTP_range();
    
        EditTargetPowerWidget *targetWidget = static_cast<EditTargetPowerWidget*>(editor);
        targetWidget->stepComboBox->setCurrentIndex(targetStepPower);
        targetWidget->targetStartValue->setValue(startFTP);
        targetWidget->targetEndValue->setValue(endFTP);
        targetWidget->targetRangeValue->setValue(range);
    
    }
    
    else {
        QStyledItemDelegate::setEditorData(editor, index);
    }
    

    }@

    Thanks if you can help me with QVariant, it is giving me headaches :)
    Forgot to say I already added :Q_DECLARE_METATYPE(std::shared_ptr<Interval>) in my Interval class



  • Fixed!

    Was a stupid error

    I changed
    "QVariant variant = interval;"
    with
    "QVariant variant = QVariant::fromValue( interval );"

    Thanks!



  • So I finally chose to use a QListView with a custom ListModel that subclass QAbstractListModel.

    1- Here is my current interface :
    https://www.dropbox.com/s/dg1n0kozcwoa2xm/currentWorkoutList.png
    It's just a QListView with 1 custom widget per row, that is returned in the createEditor function of my delegate. In the paint function of my delegate, I paint the widget directly in the painter.

    2- Here is what I would like :
    https://www.dropbox.com/s/uzu10fmv1w2r7fj/workoutEx.png

    My problem :
    I would like to have the kind of "repeat" box (see #2), to make possible a loop that is defined by the user.

    I have tought of multiple way to do that, maybe change my model to a treeItemModel, but I need a lot of coding and from the "documentation":http://qt-project.org/doc/qt-5.0/qtwidgets/qtreeview.html, it looks really complex for what I need.

    Another solution would be to have a List of QListView, each QListView has a main header that display the number of loop. But with this way, i'm not sure I would be able to drap&drop item from one QListView to another.
    Anyone with experience know if this is possible? Thanks in advance.

    Max
    http://maximumtrainer.com/

    [Edit: drag and drop possible between multiple ListView, when using" QMimeData":http://qt-project.org/doc/qt-5.0/qtcore/qmimedata.html#details with the same type, i'll post code when I get it working]


Log in to reply
 

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