Qtableview verticalheader show icon instead of numbers



  • Hi, every body

    i have Qtableview with Qsqlquerymodel,

    i want to show an icon on each vertical header when the the selection is active in that header

    should i sublcass QHeaderView class and implement neccessary function

    after setting up vertical header

    @setVerticalHeader(QHeaderView * header);@
    

    or i can use another solution without subclassing QheaderView ???

    i try to this way without subclassing

    @ ui->tableView->verticalHeader()->model()->
    setData(ui->tableView->verticalHeader()->model()->index(1,1),"**",Qt::DisplayRole) ;
    @

    but nothing is work correctly



  • You should subclass either QSqlQueryModel or QIdentityProxyModel. There, you reimplement the headerData function to return the data you want to have appearing in your header. If you use the proxy, you use it between your current QSqlQueryModel and your QTableView, while if you use the QSqlQueryModel subclass you use that subclass instead of your current QSqlQueryModel. The role you are looking for is the DecorationRole.



  • Yes! andre i know how i can use proxymodel between mymodel and myvie

    thank's for guideing me

    but the only problem now is

    how i can get selection even inside HeaderData() function

    her is my code @QVariant MytableModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    if( orientation == Qt::Vertical && role == Qt::DecorationRole)
    // how i can know when the user select a row
    // So, i will use condition like so
    if(row.IsSelectedByUser) // this is my main idea
    return QPixmap("imgs/arrow.png");

    return QVariant();
    

    }@



  • Ah, well, that was something you did not specify in your question.
    The simple answer is: you can not. The selection state is something that is not a property of the model, but of the view in the Qt model/view setup. So, your model knows nothing of the selection state.

    To me, that is a reason to use a proxy model here, and give it a setter for a QItemSelectionModel. Then, set the item selection model from your view on your proxy model, and use the item selection model to find out if the current row is selected or not.



  • this is waht you mean ??
    for example my proxy model is : mytablemodel
    myview is : tableView;

    i will implement a setter in mytablemodel like so

    @QItemSelectionModel SetSelectionModel(QItemSelectionModel *selection) ;@

    then in main coeur return the selection

    @QItemSelectionModel MytableModel::SetSelectionModel(QItemSelectionModel *selection)
    {
    return selection;
    }
    @

    then get the selectionmdel from the tableView

    @tableView->selectionModel() ;@

    then
    @mytablemdoel->SetSelectionModel(tableView->selectionModel() )@

    plz check it out



  • No, that's not what I mean. I mean:

    @
    class MyProxyModel: public QIdentityModel
    {
    public:
    void setSelectionModel(QItemSelectionModel* selection)
    {
    m_selectionModel = selection;
    }

    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    

    private:
    QItemSelectionModel* m_selectionModel;
    };

    QVariant MyProxyModel::headerData(...)
    {
    if (m_selectionModel)
    {
    //use the selection model to figure out if the current row is selected
    // if so, return your arrow icon for the decoration role
    }

    return QIdentityProxyModel::headerData(...);
    

    }

    //where you create the models and view stuff
    MyProxyModel* proxy = new MyProxyModel(myTableView);
    proxy->setSourceModel(mySqlModel);
    myTableView->setModel(proxy);
    proxy->setSelectionModel(myTableView->selectionModel());
    @



  • Yes, this what i write in code above

    mytablemodel is my proxymodel :)

    i don't write the code, i just want to check if it's the idea that you want

    finally, thank's for quick answers, complet example :)

    regards, abdeu



  • i have implemented the functions but the programme crashed

    her is my header file @#include <QSortFilterProxyModel>
    #include <QItemSelectionModel>
    class MytableModel : public QSortFilterProxyModel
    {
    public:
    explicit MytableModel(QObject parent = 0);
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    QVariant data(const QModelIndex &proxyIndex, int role) const;
    void SetSelectionModel(QItemSelectionModel
    selection) ;
    private:
    QItemSelectionModel *m_selectionModel;

    };
    @

    myfunction her :
    @
    void MytableModel::SetSelectionModel(QItemSelectionModel* selection)
    {
    m_selectionModel = selection ;
    }
    @

    her is my main

    @
    // my main model venteModel
    // my proxy model ProxyProduitModel
    // my view listProduitTableView

    ProxyProduitModel->SetSelectionModel(listProduitTableView->selectionModel());
    venteModel->setQuery("select *from Produit");
    ProxyProduitModel->setSourceModel(venteModel);
    listProduitTableView->setModel(ProxyProduitModel);

    @



  • You'll have to do better than "it crashes". Fire up your debugger when that happens, and figure out what is going wrong from that.



  • i'm not familiare with debugger but, i have try to figure out ,what's the problem, and i get the line where the problem is happned

    this @
    // Her i get the index(0,0) from proxymodel
    QModelIndex index = this->index(0,0) ;
    // then i have maked the test

    if( orientation == Qt::Vertical)
         if( orientation == Qt::Vertical && Qt::DecorationRole )
          // her is the line , the programme crashes her 
    

    if(m_selectionModel->isRowSelected(index.row(),index)) ;
    return QPixmap("imgs/arrow.png");@



  • Now, the problem is in the index of selected row

    i try to get then selected index in view like so, but isn't works
    @proxyModel->sourceModel()->index(0,0) ;@
    or @proxyModel->index(0,0) ;@

    i want to know how i get the selected row index, to be able to use it in

    @isRowSelected(int row, const QModelIndex & parent)
    and
    isSelected(const QModelIndex & index)
    @



  • Now, it's clear that some thing is wrong with index, but i can't figured out
    where is the problem

    her is my code @
    if( orientation == Qt::Vertical)
    {
    if( role == Qt::DecorationRole )
    {
    QModelIndexList indexes = m_selectionModel->selection().indexes();
    QModelIndex index = m_selectionModel->selection().indexes().at(0);
    if(m_selectionModel->isSelected(index))
    return QPixmap("imgs/arrow.png");
    }
    }@


  • Lifetime Qt Champion

    Hi,

    indexes might be empty, you don't check that case



  • i have checked is the list isempty or no but the same problem

    @if( role == Qt::DecorationRole )
    {
    QModelIndexList IndexsList = m_selectionModel->selection().indexes();
    if(!IndexsList.isEmpty())
    {
    QModelIndex index = m_selectionModel->selection().indexes().at(0);
    if(m_selectionModel->isSelected(index))
    return QPixmap("imgs/square.png");
    }
    }
    }@



  • this is another code but, unfortunately also not working
    @if( role == Qt::DecorationRole )
    {
    //i have used debugger and, the app crashed when execute the line below
    bool indexListOk = m_selectionModel->selection().indexes().isEmpty() ;
    if(!indexListOk)
    {
    QModelIndex index = m_selectionModel->selection().indexes().at(0);
    if(m_selectionModel->isSelected(index))
    return QPixmap("imgs/square.png");

            }@

  • Lifetime Qt Champion

    Did you set m_selectionModel to something valid ?

    If you follow the code from Andre carefully, you'll see that it checks first whether m_selectionModel is not NULL. Which also means that you must set it to NULL in your constructor.



  • Oh! , i forgot to do this , thank's SGaist, andre, i will try to implement this
    :)


  • Lifetime Qt Champion

    Always initializes all your pointers in the constructor either to something valid or NULL like in this case.

    And check for NULL for all pointer variables that are initialized to NULL each time you'll be using these variables



  • Yes, the probem caused by non initialisation of m_selectionModel pointer

    but still i have a small a problem

    when i select a row the icon show up, but when i leave the row (i can't get the icon disappear
    @if(m_selectionModel)
    {
    QModelIndexList indexList = m_selectionModel->selection().indexes();
    if(!indexList.isEmpty())
    {
    QModelIndex index = indexList.at(0);
    if(index.isValid() )
    return QPixmap("imgs/arrow.png");
    }else{
    return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);

                }
    
            }else{
                return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
            }
    

    @


  • Moderators

    @Andre: The headerDataChanged() signal doesn't get emitted with this method, correct? Thus the view won't be notified to update the headers when it's meant to?

    [quote author="advseo32" date="1375459821"]i'm not familiare with debugger[/quote]Take time to learn. It's a very valuable tool for programmers: http://qt-project.org/doc/qtcreator-2.8/creator-debugging.html



  • [quote author="SGaist" date="1375475299"]Always initializes all your pointers in the constructor either to something valid or NULL like in this case.

    And check for NULL for all pointer variables that are initialized to NULL each time you'll be using these variables[/quote]
    Ok, i got it now :)



  • bq.
    [quote author="advseo32" date="1375459821"]i'm not familiare with debugger[/quote]Take time to learn. It's a very valuable tool for programmers: http://qt-project.org/doc/qtcreator-2.8/creator-debugging.html[/quote]

    thanks JKSH, i will learn how i can use debugger



  • the icon showed randomly in vertical header

    her is my code @switch (role) {
    case Qt::DecorationRole :
    if(m_selectionModel)
    {
    QModelIndexList indexList = m_selectionModel->selection().indexes();
    if(!indexList.isEmpty())
    {
    QModelIndex index = indexList.at(0);
    if(index.isValid() )
    {
    for (int i=0;i<this->rowCount();++i)
    {
    if(i == index.row())
    return QPixmap("imgs/arrow.png");
    else
    return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
    }
    }
    }else
    return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);

            }else
                return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
    
    
            break;
        default:
            QSortFilterProxyModel::headerData(section,orientation,role);
            break;
        }@


  • [quote author="JKSH" date="1375487264"]@Andre: The headerDataChanged() signal doesn't get emitted with this method, correct? Thus the view won't be notified to update the headers when it's meant to?[/quote]

    The point of my answer was not to provide a complete, ready to use solution, but give a pointer in the right direction. Emitting the changed signal was considered as an excersise for the reader, as was properly initializing the pointer to the selection model. The code I showed was just typed in quickly directly in the forum editor...



  • i have emitted a signal to inform changes in vertical header but it won't
    compile

    and show me this error @E:\apprendreQt\gestionstock5\mytablemodel.cpp:54: erreur : passing 'const MytableModel' as 'this' argument of 'void QAbstractItemModel::headerDataChanged(Qt::Orientation, int, int)' discards qualifiers [-fpermissive]@

    @if(m_selectionModel)
    {

                QModelIndexList indexList = m_selectionModel->selection().indexes();
                if(!indexList.isEmpty())
                {
                    QModelIndex index =   indexList.at(0);
                    if(index.isValid() )
                    {
                        emit headerDataChanged(Qt::Vertical,0,this->rowCount()-1);
                        return  QPixmap("imgs/arrow.png");
    
                    }
    
                }else
                    return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
            }else
                return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);@

  • Lifetime Qt Champion

    Because you can't emit a signal from a const function



  • [quote author="SGaist" date="1375558375"]Because you can't emit a signal from a const function[/quote]
    I don't know about this, thank's, but really i haven't an idea on
    where i will place this emit



  • i have tried many ways to infrome view that the data is changed
    with out any success

    @void MytableModel::SetSelectionModel(QItemSelectionModel* selection)
    {
    m_selectionModel = selection ;
    emit headerDataChanged(Qt::Vertical,0,this->rowCount()-1);
    }
    @

    i can't emit signal in const functions !! where i can emit that signal ?


  • Lifetime Qt Champion

    Well, you want that arrow showed when you select a row, right ? In that case you need to detect that a selection has been made/changed, then tell the world that your header data has changed.



  • [quote author="SGaist" date="1375652135"]Well, you want that arrow showed when you select a row, right ? In that case you need to detect that a selection has been made/changed, then tell the world that your header data has changed.[/quote]

    Yes,

    i have use this in my main and still not working, i don't know if is the correct place @ connect(listProduitTableView->selectionModel(),
    SIGNAL(selectionChanged(QItemSelection,QItemSelection)),listProduitTableView->verticalHeader(),
    SLOT(headerDataChanged(Qt::Vertical,int,int)));@


  • Lifetime Qt Champion

    You can't connect two signals with different signatures like that. When starting the application you should have seen an error about that on the console.

    Please read the Signals and Slots chapter in Qt's documentation.



  • [quote author="SGaist" date="1375653308"]You can't connect two signals with different signatures like that. When starting the application you should have seen an error about that on the console.

    Please read the Signals and Slots chapter in Qt's documentation.[/quote]
    Yeah! the console show me an error,

    i don't know what the signature , it's the parameters ???
    if yes , how i can connect Signal selectionChanged() with cheaderDataChanged()

    i tried to get this work, but it won't work for me , i miss many many concepts in model/view programming

    @ connect(listProduitTableView->selectionModel(),SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),listProduitTableView->verticalHeader(),SLOT(dataChanged(QModelIndex,QModelIndex)));
    @

    or maybe my implement is wrong, plz check it out
    her is the header file of custommodel
    @#include <QSortFilterProxyModel>
    #include <QItemSelectionModel>
    class MytableModel : public QSortFilterProxyModel
    {
    public:
    explicit MytableModel(QObject parent = 0);
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    QVariant data(const QModelIndex &proxyIndex, int role) const;
    void SetSelectionModel(QItemSelectionModel
    selection) ;
    private:
    QItemSelectionModel *m_selectionModel;

    };@
    her is the cpp file of custommodel

    @#include "mytablemodel.h"
    #include <QPixmap>
    MytableModel::MytableModel(QObject *parent) : QSortFilterProxyModel(parent)

    {
    m_selectionModel = 0;

    }

    QVariant MytableModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    switch (orientation) {
    case Qt::Horizontal :
    switch (role) {
    case Qt::DisplayRole :
    switch (section) {
    case 0: return "Id";break;
    case 1: return "Reference";break;
    case 2: return "Designation";break;
    case 3: return "localisation";break;
    case 4: return "Famille";break;
    case 5: return "Qte min";break;
    case 6: return "Qte max";break;
    case 7: return "Qte disponible";break;
    case 8: return "Unité";break;
    case 9: return "Prix achat";break;
    case 10: return "Prix vente";break;
    default:
    return QString("Column %1").arg(section + 1);
    break;

               }
    
            break;
        default:
            QSortFilterProxyModel::headerData(section,orientation,role);
            break;
        }
        break;
    case Qt::Vertical :
        switch (role) {
        case Qt::DecorationRole :
            if(m_selectionModel)
            {
    
                QModelIndexList indexList = m_selectionModel->selection().indexes();
                if(!indexList.isEmpty())
                {
                    QModelIndex index =   indexList.at(0);
                    if(index.isValid() )
                    {
    
                        return  QPixmap("imgs/arrow.png");
    
                    }
    
                }else
                    return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
            }else
                return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
    
            break;
        default:
            return QSortFilterProxyModel::headerData(section,orientation,role);
            break;
        }
        break;
    default:
        return QSortFilterProxyModel::headerData(section,orientation,role);
        break;
    }
    
    
    
    return QVariant();
    

    }

    QVariant MytableModel::data(const QModelIndex &proxyIndex, int role) const
    {
    if(role == Qt::TextAlignmentRole)
    return Qt::AlignCenter;
    else if (role == Qt::DisplayRole)
    return QSortFilterProxyModel::data(proxyIndex , role);

    return QVariant();
    

    }

    void MytableModel::SetSelectionModel(QItemSelectionModel* selection)
    {
    m_selectionModel = selection ;
    }
    @
    @@



  • The signature of a function consists of the return type, the parameter types and constness of the function. You're expected to do your own debugging though.


  • Lifetime Qt Champion

    To add to what Andre said, function signature is not Qt specific, it's pure C/C++.

    Please take some time to look at the "Signal & Slots chapter":http://qt-project.org/doc/qt-4.8/signalsandslots.html of the documentation as well as the examples given.



  • i tried many solutions, i'm completly lost

    i have created a slots in my proxyModel
    @void emitHeaderChangedData(QModelIndex &current,QModelIndex &prev) ;@

    her code is
    @void MytableModel::emitHeaderChangedData(QModelIndex &current, QModelIndex &prev)
    {
    int currentRow = current.row();
    int previousRow = prev.row() ;
    emit headerDataChanged(Qt::Vertical,currentRow,previousRow);
    }

    @

    and i connect the signal currentRowChanged to that slots in my constructor , but it's still not working

    @MytableModel::MytableModel(QObject *parent) : QSortFilterProxyModel(parent)

    {
    m_selectionModel = 0;
    connect(m_selectionModel,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
    this,SLOT(emitHeaderChangedData(QModelIndex&,QModelIndex&)));

    }

    @


  • Lifetime Qt Champion

    Just a quick question, why didn't you follow Andre's suggestion and use a QIdentityProxyModel ?



  • I'm using Andre's method her is the complete code

    header file

    i create a function to emit headerDatachanged but not works,

    @void MytableModel::emitHeaderChangedData(QModelIndex &current, QModelIndex &prev)@

    and i try to use connect in my constrector, also not working

    i don't know exactly what's the best way to emit that signal

    @#ifndef MYTABLEMODEL_H
    #define MYTABLEMODEL_H

    #include <QSortFilterProxyModel>
    #include <QItemSelectionModel>
    class MytableModel : public QSortFilterProxyModel
    {
    public:
    explicit MytableModel(QObject parent = 0);
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    QVariant data(const QModelIndex &proxyIndex, int role) const;
    void SetSelectionModel(QItemSelectionModel
    selection) ;
    public slots:
    void emitHeaderChangedData(QModelIndex &current,QModelIndex &prev) ;
    private:
    QItemSelectionModel *m_selectionModel;

    };

    #endif // MYTABLEMODEL_H
    @

    her is mytablemodel.cpp

    @#include "mytablemodel.h"
    #include <QPixmap>
    MytableModel::MytableModel(QObject *parent) : QSortFilterProxyModel(parent)

    {
    m_selectionModel = 0;
    connect(m_selectionModel,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),m_selectionModel,SLOT(emitHeaderChangedData(QModelIndex&,QModelIndex&)));

    }

    QVariant MytableModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    switch (orientation) {
    case Qt::Horizontal :
    switch (role) {
    case Qt::DisplayRole :
    switch (section) {
    case 0: return "Id";break;
    case 1: return "Reference";break;
    case 2: return "Designation";break;
    case 3: return "localisation";break;
    case 4: return "Famille";break;
    case 5: return "Qte min";break;
    case 6: return "Qte max";break;
    case 7: return "Qte disponible";break;
    case 8: return "Unité";break;
    case 9: return "Prix achat";break;
    case 10: return "Prix vente";break;
    default:
    return QString("Column %1").arg(section + 1);
    break;
    }
    break;
    default:
    QSortFilterProxyModel::headerData(section,orientation,role);
    break;
    }
    break;
    case Qt::Vertical :
    switch (role) {
    case Qt::DecorationRole :
    if(m_selectionModel)
    {
    QModelIndexList indexList = m_selectionModel->selection().indexes();
    if(!indexList.isEmpty())
    {
    QModelIndex index = indexList.at(0);
    if(index.isValid() )
    {
    return QPixmap("imgs/arrow.png");

                    }
    
                }else
                    return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
            }else
                return QSortFilterProxyModel::headerData(section,Qt::Vertical,Qt::DecorationRole);
    
            break;
        default:
            return QSortFilterProxyModel::headerData(section,orientation,role);
            break;
        }
        break;
    default:
        return QSortFilterProxyModel::headerData(section,orientation,role);
        break;
    }
    
    
    
    return QVariant();
    

    }

    QVariant MytableModel::data(const QModelIndex &proxyIndex, int role) const
    {
    if(role == Qt::TextAlignmentRole)
    return Qt::AlignCenter;
    else if (role == Qt::DisplayRole)
    return QSortFilterProxyModel::data(proxyIndex , role);

    return QVariant();
    

    }

    void MytableModel::SetSelectionModel(QItemSelectionModel* selection)
    {
    m_selectionModel = selection ;
    }

    void MytableModel::emitHeaderChangedData(QModelIndex &current, QModelIndex &prev)
    {
    int currentRow = current.row();
    int previousRow = prev.row() ;
    emit headerDataChanged(Qt::Vertical,currentRow,previousRow);
    }

    @



  • In your constructor, you first set m_selectionModel to 0, meaning that it does not refer to a valid object. And on the next line, you try to connect to it anyway? You should make the connection from your SetSelectionModel method where you actually have the valid object, at line 92 of your cpp.

    Note that because you are not changing the stucture or sort order of your model, it is more efficient to use QIdentityProxyModel than QSortFilterProxyModel as your base class.



  • unfortunately, i can't get this work

    i don't know where i'm wrong @void MytableModel::SetSelectionModel(QItemSelectionModel *selection)
    {
    m_selectionModel = selection ;
    QObject::connect(m_selectionModel,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
    this,SLOT(emitHeaderDataChanged(QModelIndex&,QModelIndex&))) ;
    }

    void MytableModel::emitHeaderDataChanged(QModelIndex &current, QModelIndex &prev)
    {
    int currentRow = current.row();
    int previousRow = prev.row() ;
    emit headerDataChanged(Qt::Vertical,currentRow,previousRow);

    }
    @



    • Why do you use QObject:: before your connect?

    • What does this call return?

    • Do you see any application output for this connect statement?

    • Where do you call SetSelectionModel? And how?

    • What exactly does not work?

    • Does emitHeaderDataChanged get called or not?


Log in to reply
 

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