QTableview:根据其他列中的值显示特定列中的数据

Posted

技术标签:

【中文标题】QTableview:根据其他列中的值显示特定列中的数据【英文标题】:QTableview: display data in specific column based on value in other column 【发布时间】:2017-09-12 06:28:45 【问题描述】:

我有一个包含(除其他外)“position”和“state”字段的 sqlite 表。

我想在QTableView 中显示此表,位置作为标题列,状态在右列中,如下所示:

id | 1 | 2 | 3
1  | A |   |  
2  |   |   | E

代表以下数据库条目:

id | position | state
1  | 1        | A
2  | 3        | E

做这样的事情最好的方法是什么?

编辑:不确定这是否会改变任何东西,但我需要 QTableView 也可以编辑(通过覆盖 QSqlQueryModelsetData() 方法)

【问题讨论】:

使用 QTableWidget ! 您可以共享数据库,以便您可以将其作为测试。 :P @NicolasA。 QTableView 是这些情况的最佳选择。 我已经通过删除放置索引的依赖来更新我的答案,现在它会自动解决。当您说它应该是可编辑的时,您可以向我解释您的意思,例如带有id = 2, position = 2 and state = S 的记录,因为您想编辑该记录。 非常感谢您的时间和更新。效果更好!如果我有任何问题,我会玩它并回复你。 【参考方案1】:

这种情况下最简单的选择是创建一个继承自QSqlTableModel 的类并修改必要的函数,如下所示:

sqltablemodel.h

#ifndef SQLTABLEMODEL_H
#define SQLTABLEMODEL_H

#include <QSqlTableModel>

class SqlTableModel : public QSqlTableModel

    const QString stateName = "state";
    const QString positionName = "position";

public:
    int columnCount(const QModelIndex &parent = QModelIndex()) const;
    void setTable(const QString &tableName);
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
    Qt::ItemFlags flags(const QModelIndex &index) const;

   bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
private:
    int max_position;

    int index_position;
    int index_state;

    void reset();
;

#endif // SQLTABLEMODEL_H

sqltablemodel.cpp

#include "sqltablemodel.h"

#include <QBrush>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QTimer>


int SqlTableModel::columnCount(const QModelIndex &parent) const

    return QSqlTableModel::columnCount(parent)+ max_position;;


void SqlTableModel::setTable(const QString &tableName)


    QSqlTableModel::setTable(tableName);

    index_position = fieldIndex(positionName);
    index_state = fieldIndex(stateName);

    reset();


QVariant SqlTableModel::data(const QModelIndex &index, int role) const

    if(role == Qt::ForegroundRole)
        return QBrush(Qt::black);
    
    const int number_of_columns = QSqlTableModel::columnCount();
    if(index.column()>= number_of_columns)
        if(role==Qt::DisplayRole)
            int position = QSqlTableModel::data(this->index(index.row(), index_position), Qt::DisplayRole).toInt();
            if(index.column() == number_of_columns + position - 1)
                return QSqlTableModel::data(this->index(index.row(), index_state), Qt::DisplayRole).toString();
            
        
    
    return QSqlTableModel::data(index, role);


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

    if(orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= QSqlTableModel::columnCount())
        return section -  QSqlTableModel::columnCount() + 1;
    return QSqlTableModel::headerData(section, orientation, role);


Qt::ItemFlags SqlTableModel::flags(const QModelIndex &index) const

    if(index.column() >= QSqlTableModel::columnCount())
        return Qt::ItemIsSelectable| Qt::ItemIsEditable| Qt::ItemIsEnabled;
    
    return QSqlTableModel::flags(index);


bool SqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)

    if(role==Qt::EditRole)
        const int number_of_columns =  QSqlTableModel::columnCount();
        if(index.column() >= number_of_columns)
            bool result1 = QSqlTableModel::setData(this->index(index.row(), index_position), index.column()-number_of_columns +1, role);
            bool result2 = QSqlTableModel::setData(this->index(index.row(), index_state), value, role);

            return result1 && result2;
        
        if(index.column() == index_position)
            QTimer::singleShot(0, this, &SqlTableModel::reset);
        
    

    return QSqlTableModel::setData(index, value, role);


void SqlTableModel::reset()

    QSqlQuery q;
    q.exec(QString("SELECT MAX(%1) FROM %2").arg(positionName).arg(tableName()));
    int val;
    while (q.next()) 
        val = q.value(0).toInt();
    

    if(val != max_position)
        beginResetModel();
        max_position = val;
        endResetModel();
    

输入:

id |position |state
1  |1        |A
2  |2        |S
3  |1        |C
4  |4        |B
5  |3        |V

输出:

完整的例子可以在下面的link找到

【讨论】:

您的代码似乎有问题:columnCount 用于在视图中绘制正确数量的列,但它也用于获取模型中两个不同的列数事物。在我的例子中,你所说的 position_col 是 6(我为示例简化了数据库)。当我尝试获取此列中的值时,我得到一个无效的 QVariant,因为它优于 columnCount 返回的 max_position。 无论如何,将显示表中的列与查询返回的实际列数混合在一起似乎是错误的。

以上是关于QTableview:根据其他列中的值显示特定列中的数据的主要内容,如果未能解决你的问题,请参考以下文章

熊猫数据框条件 .mean() 取决于特定列中的值

根据其他三列中的值设置 R 列中的值

熊猫根据索引标签选择特定列中的值[重复]

根据其他列中的条件更新一列中的值

Numpy - 如何根据其他列中的二进制值计算列中的值?

Python Pandas根据多个其他列中的条件替换一列中的值[重复]