I want to implement a User editable checkbox in QTableView
which is created using QAbstractModel. I am able to assign a checked and unchecked Checkbox but unable to make it editable.
flag is set to QItemIsUserCheckable
.
问题:
回答1:
You can do it easily by implementing model's setData()
method like this:
bool yourModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
if (role == Qt::CheckStateRole)
{
if ((Qt::CheckState)value.toInt() == Qt::Checked)
{
//user has checked item
return true;
}
else
{
//user has unchecked item
return true;
}
}
return false;
}
And don't forget about your model's data()
method:
QVariant ProxyModelSubobjects::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::CheckStateRole && index.column() == COLUMN_WITH_CHECKBOX)
{
//return Qt::Checked or Qt::Unchecked here
}
//...
}
回答2:
First things first.
A QAbstractItemModel is a good choice for a model only if you're creating a tree model, while in most of other cases it is better to use a QAbstractTableModel or even a QAbstractListModel, since they save you the work of implementing virtual methods for the specific model type (table or list).
The documentation on these models is quite thorough and tells you which functions to implement for the model to be editable. I'm going to go with the table model for this short explanation. The main functions are:
- QVariant data(index, role) : returns the QVariant value for the current index & role
- bool setData(index, value, role) : returns whether the passed value was written to the index
- QItemFlags flags() : returns the QItemFlags value for the passed index
The others I will ignore for this case.
All the Qt views work the same way - when they are shown, they populate themselves with the data from the model, their elements are editable/selectable etc. according to the value returned by flags() for their index. When they are edited, the value is passed to the model via the setData() function.
What you seem to be missing is the Qt::ItemIsEditable flag in the flags() method.
回答3:
What you want to implement is a custom delegate. Take a look at the QAbstractItemDelegat class for more information on the actual implementation.
回答4:
after i went through a bunch of forums trying to figure out how to do this and nothing worked i ended up finding a note in http://doc.qt.io/qt-4.8/modelview.html
At the end of 2.2 Extending the Read Only Example with Roles the texts notes "Now we need to determine how using a separated model impacts the application's performance, so let's trace how often the view calls the data() method. In order to track how often the view calls the model, we have put a debug statement in the data() method, which logs onto the error output stream. In our small example, data() will be called 42 times. Each time you hover the cursor over the field, data() will be called again — 7 times for each cell. That's why it is important to make sure that your data is available when data() is invoked and expensive lookup operations are cached."
This made me come to the realize that "yourModal::data()" is called continuously, however, for extra update i added a time in the setup to run checks for the selection. Mine has been a little trickier because i am actually opening a groupBox pop-up window from my MainWindow, enjoy the extra code.
So basically this is my code i came up with and it runs great:
#ifndef ADD_PARAMETERS_GROUPBOX
#define ADD_PARAMETERS_GROUPBOX
#include <QGroupBox>
#include <QAbstractTableModel>
namespace Ui {
class AdditionalParameters;
}
class AdditionalParameters : public QGroupBox
{
Q_OBJECT
public:
explicit AdditionalParameters(QWidget *parent = 0);
~AdditionalParameters();
private:
Ui::AdditionalParameters *ui;
signals:
void stateChanged(int state);
private slots:
void PARAMTER_SEL(QModelIndex box);
};
#endif // ADD_PARAMETERS_GROUPBOX
#ifndef ADD_PARAMETERS_SELECTION_TABLE
#define ADD_PARAMETERS_SELECTION_TABLE
#include <QAbstractTableModel>
#include <QString>
class MainWindow;
const int ROWS = 63;
const int COLS = 5;
class ParametersTable : public QAbstractTableModel
{
Q_OBJECT
public:
ParametersTable(QObject *parent);
int rowCount(const QModelIndex &parent = QModelIndex()) const ;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
//bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::CheckStateRole);
Qt::ItemFlags flags(const QModelIndex & index) const;
private:
//QString m_gridData[ROWS][COLS]; //holds text entered into QTableView
//bool m_gridData[ROWS][COLS]; //holds state entered into QTableView
signals:
void editCompleted(const QString &);
void stateChanged(int state);
private slots:
//void updateTable();
//void PARAMTER_SEL(QModelIndex box);
};
#include "add_parameters_groupbox.h"
#include "ui_add_parameters_groupbox.h"
#include "add_parameters_selection_table.h"
#include <QTableView>
#include <QAbstractTableModel>
#include <QList>
#include <QTimer>
#include <QDebug>
#include <qcheckbox.h>
QStringList paraHold;
QStringList paraSymbols;
QString Parameters[500][5];
QAbstractTableModel *paraTable;
QItemSelectionModel *selectionModel;
bool m_gridData[ROWS][COLS];
AdditionalParameters::AdditionalParameters(QWidget *parent) :
QGroupBox(parent),
ui(new Ui::AdditionalParameters)
{
ui->setupUi(this);
paraTable = new ParametersTable(this);
ui->AddPara_tableView->setModel(paraTable);
connect(ui->AddPara_tableView,SIGNAL(clicked(QModelIndex)),
this, SLOT(PARAMTER_SEL(QModelIndex)));
paraHold
<< "60 xxxx"
<< "lines"
<< "of strings";
paraSymbols
<< "60+/-"
<< "lines"
<< "of strings";
for(int i = 0; i<(paraHold.size()); i++)
{
Parameters[i][0] = paraHold.at(i);
m_gridData[i][0] = false;
// qDebug() << "m_gridData[i][0]:" << m_gridData[i][0];
if((!Parameters[i][0].contains("T",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("FET",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("NT",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("LT",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("TAT",Qt::CaseInsensitive))){
Parameters[i][1] = "Current/Voltage";
m_gridData[i][1] = true;
// qDebug() << "m_gridData[i][1]:" << m_gridData[i][1];
}
if(!((Parameters[i][0].contains("V",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("I_",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("cell",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("FET",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("NT",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("LT",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("_SCD",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("_CFA",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("_OWD",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("_CHG",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("_DSG",Qt::CaseInsensitive))
|| (Parameters[i][0].contains("OC",Qt::CaseInsensitive)))){
Parameters[i][2] = "Tempurature";
m_gridData[i][2] = true;
// qDebug() << "m_gridData[i][2]:" << m_gridData[i][2];
}
Parameters[i][3] = paraSymbols.at(i);
}
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), ui->AddPara_tableView, SLOT(doItemsLayout()));
// connect(timer, SIGNAL(timeout()), ui->AddPara_tableView, SLOT(resizeColumnsToContents()));
// QTimer::singleShot(20000, ui->AddPara_tableView, SLOT(doItemsLayout()));
QTimer::singleShot(1000, ui->AddPara_tableView, SLOT(resizeColumnsToContents()));
timer->start(1000);
}
AdditionalParameters::~AdditionalParameters()
{
delete ui;
}
ParametersTable::ParametersTable(QObject *parent)
:QAbstractTableModel(parent)
{
}
int ParametersTable::rowCount(const QModelIndex & /*parent*/) const
{
//int pararow = Parameters.size();
//return pararow;
return 62;
}
int ParametersTable::columnCount(const QModelIndex & /*parent*/) const
{
//int paracol;
return 5;
}
QVariant ParametersTable::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole)
{
if (orientation == Qt::Horizontal) {
switch (section)
{
case 0:
return QString("Parameter");
case 1:
return QString("Current/Voltage Chart");
case 2:
return QString("Tempurature Chart");
case 3:
return QString("Symbol");
case 4:
return QString("Color");
}
}
}
return QVariant();
}
QVariant ParametersTable::data(const QModelIndex &index, int role) const
{
int row = index.row();
int col = index.column();
switch(role){
case Qt::DisplayRole:
return QString("%1")
.arg(Parameters[row][col]);
break;
case Qt::FontRole:
if (Parameters[row][col] != "_")
{
QFont boldFont;
boldFont.setBold(true);
return boldFont;
}
break;
case Qt::BackgroundRole:
if(col == 4)
{
if (Parameters[row][0].contains("cell1",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::blue);
return redBackground;
}
if (Parameters[row][0].contains("cell2",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::cyan);
return redBackground;
}
if (Parameters[row][0].contains("cell3",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::magenta);
return redBackground;
}
if (Parameters[row][0].contains("cell4",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::yellow);
return redBackground;
}
if (Parameters[row][0].contains("cell5",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::darkGray);
return redBackground;
}
if (Parameters[row][0].contains("cell6",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::red);
return redBackground;
}
if (Parameters[row][0].contains("cell7",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::darkGreen);
return redBackground;
}
if (Parameters[row][0].contains("I_",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::green);
return redBackground;
}
if ((Parameters[row][0].contains("CH",Qt::CaseInsensitive))
|| (Parameters[row][3].contains("+",Qt::CaseInsensitive)))
{
QBrush redBackground(Qt::green);
return redBackground;
}
if ((Parameters[row][0].contains("DS",Qt::CaseInsensitive))
|| (Parameters[row][3].contains("-",Qt::CaseInsensitive)))
{
QBrush redBackground(Qt::red);
return redBackground;
}
if (Parameters[row][0].contains("V_Pack",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::darkRed);
return redBackground;
}
if (Parameters[row][0].contains("T_ISL",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::darkMagenta);
return redBackground;
}
if (Parameters[row][0].contains("T_HS",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::darkYellow);
return redBackground;
}
if (Parameters[row][0].contains("T_LS",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::darkCyan);
return redBackground;
}
if (Parameters[row][0].contains("T_B",Qt::CaseInsensitive))
{
QBrush redBackground(Qt::darkBlue);
return redBackground;
}
}
break;
case Qt::TextAlignmentRole:
if (col == 3) //change text alignment only for colum 3
{
return Qt::AlignCenter;//+ Qt::AlignVCenter;
}
break;
case Qt::CheckStateRole:
if((col == 0) && (m_gridData[row][0] == false)){ //add a checkbox to all rows in colum 0
// qDebug() << "m_gridData[" << row << "][0]:" << m_gridData[row][0];
return Qt::Unchecked;
}
else if((col == 0) && (m_gridData[row][0] == true)){
// qDebug() << "m_gridData[" << row << "][0]:" << m_gridData[row][0];
return Qt::Checked;
}
if((Parameters[row][1].contains("Current/Voltage",Qt::CaseSensitive)
&& (col == 1)) && (m_gridData[row][1] == true)){
// qDebug() << "m_gridData[" << row << "][1]:" << m_gridData[row][1];
return Qt::Checked;
}
else if((Parameters[row][1].contains("Current/Voltage",Qt::CaseSensitive) && (col == 1))
&& (m_gridData[row][1] == false)){
// qDebug() << "m_gridData[" << row << "][1]:" << m_gridData[row][1];
return Qt::Unchecked;
}
if(Parameters[row][2].contains("Tempurature",Qt::CaseSensitive)
&& (col == 2) && (m_gridData[row][2] == true)){
// qDebug() << "m_gridData[" << row << "][2]:" << m_gridData[row][2];
return Qt::Checked;
}
else if((Parameters[row][2].contains("Tempurature",Qt::CaseSensitive)
&& (col == 2)) && (m_gridData[row][2] == false)){
// qDebug() << "m_gridData[" << row << "][2]:" << m_gridData[row][2];
return Qt::Unchecked;
}
}
return QVariant();
}
Qt::ItemFlags ParametersTable::flags(const QModelIndex & /*index*/) const
{
return Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
}
void AdditionalParameters::PARAMTER_SEL(QModelIndex Box)
{
int row = Box.row();
int col = Box.column();
if(!Parameters[row][col].isEmpty()){
m_gridData[row][col] = (!(m_gridData[row][col]));
qDebug() << "PARA_SEL @ m_gridData[row][col]:(" << row << "," << col << "):" << m_gridData[row][col];
}
emit stateChanged(m_gridData[row][col]);
}