Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

get the content from a tableview and change it



  • Hi,

    I'm new in Qt and c++.
    I want get the content of a cell and if the requirement is true i will change the content in the tableview.
    But I make something wrong but I don't know wat exactly.

    there I'm getting the background color of the cell and it works fine

    QVariant TableCustomise::data(const QModelIndex &index, int role) const
    {
        if(role == Qt::BackgroundRole )
        {
    
        QString content = index.sibling(index.row(), 0).data(Qt::DisplayRole).toString();
            if ( content == "red" )
            {
                return QBrush(Qt::red);
            }
        }
    
        return QSqlQueryModel::data(index, role);
    }
    

    therefore I thried to change the content of the cell the same way
    but this doesn't work
    why?

    QVariant TableCustomise::data(const QModelIndex &index, int role)const
    {
            if(role == Qt::DisplayRole())
            {
                QString content = index.sibling(index.row(), index.column()).data(Qt::DisplayRole).toString();
                if (content == "1")
                {
                       return "red";
                }
            }
        return QSqlQueryModel::data(index, role) ;
    }
    

    I hope someone can help me.

    Thank you



  • @Mogli123
    In your QSqlQueryModel::data(), when you start looking at another cell in order to determine the result for one cell you have to be very careful. And that's your problem here!

    In your working example, to return a cell's Qt::BackgroundRole you look at another cell's Qt::DisplayRole, and that's OK.

    However, in your second example to return a cell's Qt::DisplayRole you look at another cell's Qt::DisplayRole, the same role. Now if you think about it, that causes a potentially "infinite recursion", because when you look at the other cell's Qt::DisplayRole you will be re-executing the same pathway in your TableCustomise::data(), and that in turn will look at that cell's sibling, and so on....

    The first, most obvious problem is that when you come to look at the right-most cell, your code still asks for that one's sibling(), but there isn't one. http://doc.qt.io/qt-5/qmodelindex.html#sibling :

    Returns the sibling at column for the current row. If there is no sibling at this position, an invalid QModelIndex is returned.

    So you must check for your index.sibling(index.row(), index.column()) returning invalid, which you are not presently doing.

    Beyond that, you need to think out what you want here. You keep saying that each cell's Qt::DisplayRole depends on its sibling's Qt::DisplayRole value. That can't be right: it needs to stop somewhere. Perhaps this only applies where index.column() has a certain value?

    There are other approaches which may help. But since you're a beginner I won't go into them yet, don't want to overload you with information. And it may not be necessary, depending on what you wish to change your code to do.

    Let us know!



  • Thank you for your answer

    I want only know what the content of the cells from each row is.
    Than I decide which color get the background of the complet row.
    Therefore I want to write the color in the first column

    Furthermore is it possible to split the two funktions above?
    I dont't want the two code in the same method



  • @Mogli123
    I'm afraid I don't understand what you are saying in the 3 line-paragraph in your response. So it's difficult to answer! If you are saying you only want "red" returned when index.column() == 0 then you need code for that for a start.

    For the 2 line-paragraph: I think you are saying that when trying to return the Qt::DisplayRole of "red" for a cell, you would rather not have to call the same TableCustomise::data() code to read the Qt::DisplayRole of the sibling, which is what causes the potential recursion?

    Unfortunately, so far as I know once you have written a QSqlQueryModel::data() override you cannot help but have that called to query all cells' data --- there is no way to call another cell's base QSqlQueryModel::data() instead of your overridden method. Because that would have made it easier....

    Unless a C++ expert knows better, the way I can think of to do this is: You can define your own, additional roles. They start at something like Qt::UserRole + 1, or something like that, it's in the docs. I would define that, and have your TableCustomise::data() if called with that as role go

    if (role == Qt::UserRole + 1)
        return QSqlQueryModel::data(index, Qt::DisplayRole);
    

    The intention is that route should return the original display-role value, not the one altered by your override, so no recursion/alteration. You'll have to check this, as I'm not a C++-er.

    Then when looking for the sibling's value you can go

    if (role == Qt::DisplayRole())
    {
        QString content = index.sibling(index.row(), index.column()).data(Qt::UserRole + 1).toString();
        ....
    }
    

    That's assuming this is what you mean by

    Furthermore is it possible to split the two funktions above?
    I dont't want the two code in the same method

    Sorry, I know you're a beginner, you'll have to do a bit of work to read & implement what I've written. Because I don't have time, I really must get on with my own work....!



  • 2 minor notes:
    index.sibling(index.row(), index.column()) is index

    @JonB said in get the content from a tableview and change it:

    there is no way to call another cell's base QSqlQueryModel::data() instead of your overridden method.

    There is and you are using it 2 rows below QSqlQueryModel::data(index, Qt::DisplayRole);



  • @VRonin

    index.sibling(index.row(), index.column()) is index

    What does this mean? QModelIndex::sibling() returns some (next?) "sibling" of index, no (err, now I wonder..)? I said the OP that he must check that is valid.

    QSqlQueryModel::data(index, Qt::DisplayRole);

    I'm getting lost here in C++ vs the Python I have to use for PyQt/Qt. I thought this would still call his TableCustomise::data() override on the cell specified by index, no? I'm sure when I tried this via PyQt (we can't use the same syntax as C++, and we cannot directly call C++ function, only their PyQt wrappers) it did.... :(



  • sorry my enlish ist not the best

    The first code example just shows where I got the idea for the code in the second example.
    And how I color the rows.

    I just want to know how I can read the information of a cell and, because of the content, write content in a cell of my choice

    For example:
    I want color the row red if in one of the cells of the row stands a 0.
    therefore I want to write "red" in the first cell of the row if that is true.

    I hope you understand what I mean

    I understand if you haven't time to help me.



  • @Mogli123
    Very briefly:

    I want color the row red if in one of the cells of the row stands a 0.
    therefore I want to write "red" in the first cell of the row if that is true.

    Do you want to color the row (use role == Qt::BackgroundRole like first example) or do you want to write the string "red" in the first column's cell (use role == Qt::DisplayRole()) like your second example, or both, or what?



  • At first thank you for your answers

    First I want to write the color in a cell (for example "red")
    After that I want to color the row with the wantet color like the first example

    I know that I could color the lines with the desired condition without writing the color in the cell
    but i would like to separate these two methods if possible



  • @Mogli123
    My literally last scribbled ideas:

    • You will need your function to have two cases, one for role == Qt::BackgroundRole and another for Qt::DisplayRole(), respectively.

    • If you have multiple cells in a row, and you want to know if any of them contains something to affect the coloring, you'll need to look at all the cells after the first one, calling sibling() or similar in a loop to look at each one.

    • I think you'll need to set the Qt::BackgroundRole for each cell (unless there's a way to do it one for a whole row), but set the Qt::DisplayRole() only for column 0.

    • Do not examine the value of column 0 itself when calculating, as you may recurse infinitely.



  • @JonB said in get the content from a tableview and change it:

    What does this mean?

    QModelIndex QAbstractItemModel::sibling(int row, int column, const QModelIndex &idx) const
    {
        return (row == idx.row() && column == idx.column()) ? idx : index(row, column, parent(idx));
    }
    

    so if you pass the same rows and columns as the original index you get back the original index



  • I have changed

    QString content = index.sibling(index.row(), 0).data(Qt::DisplayRole).toString();
    

    to

     QString content = index.sibling(index.row(), index.column()).data(Qt::EditRole).toString();
    

    and it seems that it works
    is this the right way?

    my only problem now is that i would separate the to mehods

    the problem is that they have the same nam
    but on which place I can change the name that I can separate the methods?

    sorry for that if this is basic



  • @Mogli123
    You cannot "separate the methods", per se.

    The way Qt works is that its infrastructure always calls QSqlQueryModel::data(index, role) (and thus your TableCustomise::data() override) for different attributes/effects/results, passing in varying values for role accordingly. That's just the way it is, and you cannot alter that.

    Usually you just write your overload stuff in the one function, using if (role == ...) ... else if (role == ) ... else ... (or similar, you may be able to use a switch statement instead for neatness) for the various cases, and your code is all in that function.

    If you feel your code is too big, you would have to write your own separate, new functions for each case and just call them in your code, like:

    QVariant TableCustomise::data(const QModelIndex &index, int role)const
    {
        if (role == Qt::DisplayRole())
            return displayData(index);
        else if (role == Qt::backgroundRole())
            return backgroundData(index);
        else
            return QSqlQueryModel::data(index, role) ;
    }
    
    QVariant TableCustomise::displayData(const QModelIndex &index )const
    {
        return ...;
    }
    
    QVariant TableCustomise::backgroundData(const QModelIndex &index )const
    {
        return ...;
    }
    


  • Thank you very much

    that looks great

    I will trie it


Log in to reply