Model/View, Delegates for my Data
Hi,
I am quite new tho Model/View approach and I need your help. I am reading a text file and want to display data in a tableview. I already looked at example codes but they are very basic and my requirements are very different.
Text from file looks like:
Code:
Page Address Name
....
1 0000abda _CpuTimer1
1 0000abe2 _CpuTimer2
1 0000abea _CpuTimer0
1 0000abf2 _msg
1 0000abf4 _res
....
I store those information to a QVector of following typedef:
Code:
typedef struct St_Register
{
quint16 page;
quint16 address;
quint32 currValue;
quint32 wrValue;
bool wrProtect;
} Register;
...
QVector<Register *> Registers;
But as soon as I store the data into Registers vector, It should update the table automatically.
I want to show Name, Page, Address, currValue information in the table as not editable strings. I want to show wrProtect as editable checkbox and wrValue as editable spinbox.
When I check the checkbox, the wrValue should be editable, otherwise not editable.
So, Is my data-model only this QVector? QVector<Register *> Registers;
Do I need customized checkbox delegate and spinbox delegate? If yes, how? How can I "connect" those specialized delegates to tableView (or to model)?
I need a step-by-step instruction for implementing of creating all required classes (pseude-code is enough).
Thanks.
Re: Model/View, Delegates for my Data
First, unless you have some specific need, do not use QVector< pointer to thing >. If you do, it means you are responsible for maunally creating and deleting the items in your vector each time the vector content changes. Simply use QVector< thing > (in other words, QVector< Register >) and the Register instances will automatically be created, copied, and go in and out of scope without you having to worry about memory leaks.
You can use Qt::CheckStateRole to return an enum (as a QVariant) indicating whether the item should be checked or not. If you want the user to be able to edit the check state, then implement the QAbstractItemModel::flags() method to return Qt:ItemFlags that have the Qt::ItemIsUserCheckable bit set.
For the spin box, you will have to create a custom delegate. The Qt documentation contains an example. You may have to modify this example to support hexadecimal and to disable the ability for a user to type into it, although you could also set it up to allow typing, but then also implement a QValidator to prohibit any non-hex input. See here and QRegularExpressionValidator.
You will also need to implement QAbstractItemModel::setData() so that these changes are put back into your model.
2 Attachment(s)
Re: Model/View, Delegates for my Data
Thanks for reply.
I try checkbox column without a delegate. The column is shown with checkbox but with "true" "false" text as well, as you can see in the attachment. It is only double-clickable.
I also want to edit chekcbox with only one click. If I click double, it turns to false as in the attachment.
What I want is: Single-clickable checkbox without true-false text.
Attachment 12976
Attachment 12977
Registermodel.cpp
Code:
.....
{
int row = index.row();
int col = index.column();
switch (role) {
case Qt::DisplayRole:
switch (col) {
case 0:
return Registers[row].name; // QString
break;
case 1:
return Registers[row].page; // quint16
break;
case 2:
return QString("%1").
arg(Registers
[row
].
address,
8,
16,
QChar('0')).
toUpper();
// quint32 break;
case 3:
return QString("%1").
arg(Registers
[row
].
currValue,
8,
16,
QChar('0')).
toUpper();
// quint32 break;
case 4:
return Registers[row].wrProtect; // bool
break;
case 5:
return QString("%1").
arg(Registers
[row
].
wrValue,
8,
16,
QChar('0')).
toUpper();
// quint32 break;
default:
break;
}
break;
case Qt::TextAlignmentRole:
if(col == 0)
return Qt::AlignLeft;
else
return Qt::AlignRight;
break;
case Qt::CheckStateRole:
if(col == 4)
{
if(Registers[row].wrProtect == true)
return Qt::Checked;
else
return Qt::Unchecked;
}
break;
case Qt::FontRole:
if(col != 0)
break;
default:
break;
}
}
{
if(role == Qt::EditRole)
{
setElement(index.row(), index.column(), value);
}
else if (role == Qt::CheckStateRole)
{
if((Qt::CheckState)value.toInt() == Qt::Checked)
{
setElement(index.row(), index.column(), value);
}
}
return true;
}
Qt
::ItemFlags RegisterModel
::flags(const QModelIndex &index
) const{
int col = index.column();
if (col == 5)
else if (col == 4)
else
}
....
Do I need custom delegate? If yes how?
Re: Model/View, Delegates for my Data
If you don't want the words "true" or "false", then you need to return QVariant() for the column 4 DisplayRole instead of "wrProtect", which the table will convert to "true" or "false".
The reason a double-click is needed is that for the table, the first click selects the item and activates the editor, the second click changes its state. You might be able to change this behavior by retrieving the QItemSelectionModel for the table view and connecting a slot to the QItemSelectionModel::currentChanged() signal. If the new current index is for column 4, change the state of the check box by changing the model and emitting dataChanged().
Re: Model/View, Delegates for my Data
I added QVariant to the code but the table still displays boolean as ture or false.
Code:
{
...
case 4:
return QVariant(Registers
[row
].
wrProtect);
// bool break;
...
case Qt::CheckStateRole:
if(col == 4)
{
if(Registers[row].wrProtect == true)
{
}
else
{
}
}
...
}
I want to use delegate. When I double-click the cell a new checkbox appers on the left in the cell. Checkbox is not displayed when I don't click.
checkboxdelegate.h
Code:
#ifndef CHECKBOXDELEGATE_H
#define CHECKBOXDELEGATE_H
#include <QStyledItemDelegate>
#include <QTableView>
#include <QObject>
#include <QDebug>
#include <QCheckBox>
#define DEB qDebug().noquote() <<
class CheckBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit CheckBoxDelegate
(QObject *parent
= 0);
void updateEditorGeometry
(QWidget *editor,
private slots:
void setData(bool value);
};
#endif // CHECKBOXDELEGATE_H
checkboxdelegate.cpp
Code:
#include "checkboxdelegate.h"
#include <QComboBox>
#include <QCheckBox>
#include <QRect>
#include <QPainter>
#include <QSpinBox>
#include <QApplication>
#include <QSignalMapper>
#include "booleanwidget.h"
CheckBoxDelegate
::CheckBoxDelegate(QObject *parent
) : QStyledItemDelegate(parent)
{
}
{
QObject::connect(checkBox,
SIGNAL(toggled
(bool)),
this,
SLOT(setData
(bool)));
return checkBox;
}
{
if(QCheckBox *cb
= static_cast<QCheckBox
*>
(editor
)) {
bool checked = index.model()->data(index, Qt::DisplayRole /* Qt::EditRole */).toBool();
DEB "Checked: " << checked;
cb->setChecked(checked);
}
}
{
if(QCheckBox *cb
= static_cast<QCheckBox
*>
(editor
)) // save the current text of the combo box as the current value of the item
model->setData(index, cb->isChecked());
else
QStyledItemDelegate::setModelData(editor, model, index);
}
void CheckBoxDelegate
::updateEditorGeometry(QWidget *editor,
editor->setGeometry(option.rect);
}
}
void CheckBoxDelegate::setData(bool value)
{
emit commitData(checkBox);
}
What am I missing?
Re: Model/View, Delegates for my Data
Quote:
I added QVariant to the code but the table still displays boolean as ture or false.
No, I meant return literally "QVariant()" (an empty QVariant instance). Returning QVariant( Qt::Checked ) still results in the table seeing a Boolean value instead of nothing.
Quote:
Checkbox is not displayed when I don't click.
I think you are misunderstanding what a delegate does. Delegates are -only- used when editing an item in a table or tree view. When the editing is finished, the editor is destroyed and the model is updated. So if you create a checkbox delegate, it will be displayed only when you are actually editing the cell with the Boolean item, otherwise it will not be visible.
If you want something to be visible all of the time, you will have to implement the paint() method to draw the checkbox -image-.
Personally, I think you are chasing this too far. You don't need a delegate for checkboxes, since QTableView already provides one. Did you try my suggestion of connecting a slot to the QItemSelectionModel?