Set background of specific row in QListView



  • Re: Set background of specific row in QTableView
    Hi,

    I have copied the setRowColor() from the link above into my code base call it like:

    void Widget::on_HostList_doubleClicked(const QModelIndex &index)
    {
        QAbstractItemModel *model = ui->HostList->model();
        setRowColor(model,index.row(),Qt::red,index);
    }
    

    but it does not seem to work, the color is not changing. Can someone help me here?


  • Moderators

    @cerr You'll have to give a bit more info...

    1. Is model valid? Check to see if it is not null at least just to make sure. I usually just use a Q_ASSERT(model) when I'm having problems, as it's not something that needs to be checked in release mode.

    2. Is index.valid() true?

    3. is index.row() in the valid range?

    4. Based on the setRowColor VRonin posted you are passing the index you want to change as the parent. This is probably causing an issue, try setRowColor(model, index.row(), Qt::red);



  • @ambershark
    Thanks for your reply! I have changed my method now to look like:

    void Widget::on_HostList_doubleClicked(const QModelIndex &index)
    {
        QAbstractItemModel *model = ui->HostList->model();
        Q_ASSERT(model);
        Q_ASSERT(index.isValid());
        if (index.row() >= 0 && index.row() < model->rowCount()) {
            setRowColor(model,index.row(),Qt::red);
            qDebug() << "changing row " << index.row();
        } else
            qDebug() << "Row " << index.row() << " is out of range!";
    
    }
    

    But the color still isn't changing as I'd expect. Now, I think my model might be the issue, I'm loading my data into the list with this:

    int JTFTools::ListViewPopulate(QListView *listView, QStringList *stringList)
    {
        int rv = OK;
    
        QStringListModel* listModel = new QStringListModel(*stringList, listView);
        QItemSelectionModel *oldModel = listView->selectionModel();
        listView->setModel(listModel);
    
        delete oldModel;
    
        return rv;
    }
    

    do you have any further ideas?


  • Moderators

    @cerr It's probably something you are doing with the model or the view. I can write up a quick example in a bit that shows it in action if you want and you can take it from there.

    Your code in the second part you listed is wrong. You are using selectionModel() instead of model(). They are completely different things. I'm actually surprised by you deleting an owned selectionModel() that things aren't crashing.

    I also would continually delete then create new models like that. It's not really designed to be used that way. It would also cause heap fragmentation, which isn't as big a deal as it used to be back in the day, but still hurts your memory usage. You also double set your model by parenting it then using setModel().

    Here is a replacement function for that:

    int JTFTools::ListViewPopulate(QListView *listView, QStringList *stringList)
    {
        int rv = OK;
    
        auto model = qobject_cast<QStringListModel *>(listView->model());
       model->setStringList(*stringList);
    
        return rv;
    }
    

    Oh, and I wouldn't pass by non-const pointer if you don't edit the contents.. so I would change that stringList to const QStringList * or use a reference with const QStringList &. That's just protection for you as a developer and any other coders that come behind you though so not a huge deal. It's just a smart practice to get into.

    Changing that function may fix your problem, but I doubt it, so let me know if you want me to write up a quick example later on.



  • @ambershark
    Oh wow, Thank you very much! Hmm, let's see: I would love I you could provide me with an example whenever you get to it, definitely! Thanks in advance!
    So to the improved ListViewPopulate method you provided:
    I thought I read somewhere that you should delete the old model after you've set the new one... let me see... yeah here, I found it, it says:

    void QAbstractItemView::setModel ( QAbstractItemModel * model ) [virtual]
    Sets the model for the view to present.

    This function will create and set a new selection model, replacing any model that was previously set with setSelectionModel(). However, the old selection model will not be deleted as it may be shared between several views. We recommend that you delete the old selection model if it is no longer required. This is done with the following code:

    QItemSelectionModel *m = view->selectionModel();
    view->setModel(new model);
    delete m;
    

    plus, what you provided doesn't compile for me, I get:

         auto model = qobject_cast<QStringListModel *>(listView->model());
              ^
    

    shouldn't model just be of type QStringListModel *? I tried that but now it crashes with a SIGSEGV segmentation fault.


  • Moderators

    @cerr Sure I'll do an example later tonight or tomorrow.

    So that documentation looks like a copy/paste error. It references setSelectionModel inside a setModel docs. If you set a new model using setModel then yes you should clean your old one.

    Likewise if you set a new selection model using setSelectionModel then you should clean the old selection model.

    Your delete wasn't wrong or anything in your old code, just you mixed up setModel and setSelectionModel. They are 2 very different things. :)

    As for the not compiling, sorry I used c++11 syntax with the auto, yes you can safely change that to QStringListModel *model = .... Or you can add --std=c++11 (assuming gcc compiler) to your build.

    QItemSelectionModel *m = view->selectionModel();
    view->setModel(new model);
    delete m;
    

    You did it again in this code... you are mixing a selectionModel and a data model. Selection models are used to show what is currently selected in your view/model. Data models are used to store the contents of the entire model/view.

    So your crash is coming from you getting the selection model into m and then setting a new regular data model with setModel and then deleting a still in use selection model when you say delete m.



  • @ambershark said in Set background of specific row in QListView:

    QItemSelectionModel *m = view->selectionModel();
    view->setModel(new model);
    delete m;

    You did it again in this code...

    Hehe no, sorry! I just pasted the code braket from the example, it just wouldn't let me quote the code lines....
    Staying tuned and looking forward to seeing your example...
    Thank you!


  • Moderators

    @cerr Ok so by writing the example I figured out your problem. It looks like QStringListModel does not support coloring as part of a data role. You can do it via a delegate but not in the style you are trying to use in your example.

    Here is a screenshot of my example using a QStandardItemModel:
    alt text

    And the code --

    main.cpp:

    #include <QApplication>
    #include "window.h"
    
    int main(int ac, char **av)
    {
    	QApplication app(ac, av);
            Window w;
            w.show();
    	return app.exec();
    }
    

    window.h:

    #pragma once
    
    #include <QWidget>
    
    class QListView;
    
    class Window : public QWidget
    {
        Q_OBJECT
    
    public:
        Window(QWidget *parent = 0);
        
    private:
        QListView *view_;
    };
    

    window.cpp:

    #include "window.h"
    #include <QListView>
    #include <QVBoxLayout>
    #include <QStandardItemModel>
    
    Window::Window(QWidget *parent)
        : QWidget(parent)
    {
        resize(600,400);
        
        // create layout
        auto layout = new QVBoxLayout();
        
        // create view and model
        view_ = new QListView();
        auto model = new QStandardItemModel();
        model->appendRow(new QStandardItem("line 1"));
        model->appendRow(new QStandardItem("line 2"));
        model->appendRow(new QStandardItem("line 3"));
        model->appendRow(new QStandardItem("line 4"));
        view_->setModel(model);
        
        // add view to layout
        layout->addWidget(view_);
        setLayout(layout);
        
        // set the bg color of row 2
        model->setData(model->index(1, 0), QBrush(Qt::red), Qt::BackgroundRole);
    }
    

    In case you want to build here's my CMakeLists.txt
    CMakeLists.txt:

    cmake_minimum_required(VERSION 3.4)
    project(rowcolor)
    
    find_package(Qt5Gui REQUIRED)
    
    set(CMAKE_AUTOMOC ON)
    
    include_directories(
    	src
    	)
    
    set(SRCS
    	src/main.cpp
        src/window.cpp
        )
    
    add_executable(${PROJECT_NAME} ${SRCS})
    qt5_use_modules(${PROJECT_NAME} Core Gui Widgets)
    

    I can make a zip of the project if you need it.



  • @ambershark Hi Ambershark, Excellent, Thank you very much! I appreciate your efforts! I can't copy and duplicate work just yet but I'll get onto it asap! Thank you very much! :D
    I don't know why but it doesn't let me accept your reply as answer... ? :(
    Now maybe you can give me another hint: How would I have found out that I need to use a QStandardItemModel instead of QStringListModel as a newbie? Is there a good an easy to oversee index where I can find which features are supported by which components? Or did you "just know" it?


  • Moderators

    @cerr Not really any good docs/resource for that unfortunately. It will just come with time and experience. As for me just knowing, I actually didn't... I implemented it with the QStringListModel and was surprised when it didn't work. That's when I got the idea that it might be the model causing the issue so I used my default model which was the QStandardItemModel, and it worked.

    So I figured out there was an issue with QStringListModel and honoring data roles. Not a bug, but more of a lack of support. :)

    You can look up all the models in the Qt Docs though if that helps. And of course you can always create your own custom models.


Log in to reply
 

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