Code Gorilla
Code Gorilla

Reputation: 980

Qt QTableVew selecting multiple rows

I have hit a problem with QTableView (Qt version 5.12.10). I have create a very basic table class which just has the the following code in the class constructor:

Screen shot

setModel(pModel); // pModel is of a class derived from QAbstractTableModel
setWindowTitle("The Title");
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::ExtendedSelection);

When I click on the left most column (not the id column) where it says 2, it will select the whole of row 2.
When I shift click on row 3 it also selects the whole of row 3. When I shift click on row 4 in the first name column (any column except the left most) it selects row 4 and deselects row 2.

According to the documentation tis could be expected behaviour, but if all clicks are performed in the Name column then row 2 is not deselected.

Further after doing the above clicking on row 8 and the left most column reselects row 1 where as row 8 anywhere else does not reselect row 1.

It appears that the left most column has a selection value that the rest of the table can't fully access.

Questions:

  1. Am I doing something wrong?
  2. Have I misunderstood the documented behaviour?
  3. Does anyone know if there is a way of making the two sides work in the same way?

Code: main.cpp

#include <sstream>
#include <QWidget>
#include <QApplication>
#include <QTableView>
#include "cmodeldata.h"
#include "cqtableview.h"

/// Display the row from a QItemSelection
std::string dumpQItemSelection (const QItemSelection& selection)
{
    int lastRow = -1;
    std::stringstream output;
    output << "(";
    for (auto index : selection.indexes())
    {
        if (index.row() != lastRow)
        {
            lastRow = index.row();
            output << index.row() << ",";
        }
    }
    output << ")";
    return output.str();
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CModelData m_model;
    CQTableView *m_table = new CQTableView (&m_model);
    m_table->show();

    return a.exec();
}

cqtableview.h

#ifndef CQTABLEVIEW_H
#define CQTABLEVIEW_H

#include <QWidget>
#include <QTableView>
#include "cmodeldata.h"

class CQTableView : public QTableView
{
    Q_OBJECT
public:
    explicit CQTableView(CModelData* pModel = nullptr, QWidget *parent = nullptr)
        : QTableView(parent)
    {
        setModel(pModel);
        setWindowTitle("The Title");
        setSelectionBehavior(QAbstractItemView::SelectRows);
        setSelectionMode(QAbstractItemView::ExtendedSelection);
    }

public slots:
public:
};

#endif // CQTABLEVIEW_H

cmodeldata.h

#ifndef CMODELDATA_H
#define CMODELDATA_H

#include <QAbstractTableModel>
#include <QStringListModel>


class CModelData : public QAbstractTableModel
{
    Q_OBJECT
public:
    enum class EColumns
    {   // The order of the columns
          eId = 0
        , eFirstName
        , eLastName
        , eEmail
        , ePhone
        , eColumnCount
    };
public:
    CModelData(QObject *parent = nullptr);

    /// Get the number of rows in the data source
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    /// Get the number of columns in the data source
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;

    /// Return a cell of data
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    /// Return a cell of data relevent to the header
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    /// Add a row of data
    bool addRow (const int i, const QString& fn, const QString& ln, const QString& e, const QString& pn);
private:
    struct DataRow
    {   // This is a row of data
        int     id;
        QString firstName;
        QString lastName;
        QString email;
        QString phone;
        DataRow (const int i = 0, const QString& fn = "", const QString& ln = "", const QString& e = "", const QString& pn = "")
            : id(i), firstName(fn), lastName(ln), email(e), phone(pn)
        {}
    };
    QVector<DataRow> m_rows;
};

#endif // CMODELDATA_H

cmodeldata.cpp

#include "cmodeldata.h"

CModelData::CModelData(QObject* pParent)
    : QAbstractTableModel(pParent)
{
    addRow(0, "Alan", "Alanson", "[email protected]", "0111 111111");
    addRow(1, "Bob", "Brown", "[email protected]", "0111 222222");
    addRow(2, "Charlie", "Carlson", "[email protected]", "0111 333333");
    addRow(3, "Dave", "Davis", "[email protected]", "0111 444444");
    addRow(4, "Eric", "Ericson", "[email protected]", "0111 555555");
    addRow(5, "Frank", "Fallows", "[email protected]", "0111 666666");
    addRow(6, "Geoff", "Geofferson", "[email protected]", "0111 777777");
    addRow(7, "Hugo", "Hadron", "[email protected]", "0111 888888");
    addRow(8, "Ian", "Indigo", "[email protected]", "0111 999999");
    addRow(9, "James", "Jamerson", "[email protected]", "0111 000000");
}

int CModelData::rowCount(const QModelIndex & /*parent*/) const
{
   return m_rows.count();
}

int CModelData::columnCount(const QModelIndex & /*parent*/) const
{
    return static_cast<int>(EColumns::eColumnCount);
}

QVariant CModelData::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
        /// return QString("Row%1, Column%2").arg(index.row() + 1).arg(index.column() +1);
        for (auto& item : m_rows)
        {
            if (item.id == index.row())
            {
                switch (index.column())
                {
                case static_cast<int>(EColumns::eId):
                    return item.id;
                case static_cast<int>(EColumns::eFirstName):
                    return item.firstName;
                case static_cast<int>(EColumns::eLastName):
                    return item.lastName;
                case static_cast<int>(EColumns::eEmail):
                    return item.email;
                case static_cast<int>(EColumns::ePhone):
                    return item.phone;
                default:
                    return QVariant();
                }
            }
        }
    }
    return QVariant();
}

QVariant CModelData::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
    {
        switch (section)
        {
        case static_cast<int>(EColumns::eId):
            return QString("Id");
        case static_cast<int>(EColumns::eFirstName):
            return QString("First Name");
        case static_cast<int>(EColumns::eLastName):
            return QString("Last Name");
        case static_cast<int>(EColumns::eEmail):
            return QString("Email");
        case static_cast<int>(EColumns::ePhone):
            return QString("Phone");
        }
    }
    // return QAbstractTableModel::headerData(section, orientation, role);
    return QAbstractTableModel::headerData(section, orientation, role);
}

bool CModelData::addRow (const int i, const QString& fn, const QString& ln, const QString& e, const QString& pn)
{
    m_rows.append(DataRow(i, fn, ln, e, pn));
    return true;
}

Upvotes: 0

Views: 520

Answers (1)

chehrlic
chehrlic

Reputation: 958

It's a bug in Qt, I've created a bug report here: https://bugreports.qt.io/browse/QTBUG-92561

Upvotes: 1

Related Questions