QTableView & CheckBox delegate alignmnent
-
[quote author="hsfougaris" date="1301551606"]That's why the QTableView class should be much richer in my opinion (like almost every other grid developed). It could have properties like setColumnWidget(...) ...
The fact of the matter is that trying to use QSql*** with a QTableView with anything other than text is a pain, and there is no straightforward way to handle very common needs and scenarios.
You can't even center align a column without a delegate![/quote]If you need a richer table view, look at some of the commercial solutions that exist. I also found some things I would like to have in a TableView, but I'm sure, not 90% of the user would like to have it, perhaps on 10 %. And I think, it's the same with the SQL stuff. In our company, we use many tables, but not a single QSqlXXX class. We have custom data providers.
And I think, a QSFPM as "Man in the middle" to achieve this, is not the worst solution.
And via the delegates, you achieve exaclty the same as with setColumnWidget. Create a delegate and use setColumnDelegate. Model - View - Delegate is a very good pattern indeed. It's a derivate of the Model-View-Controler which is very common.
-
Is there anything other that one ICS makes? (because that is priced insanely...)
I had a look at one from DevMachines, which looks promising but is not ready for prime time yet.I haven't been able to find other ones, so I would appreciate any directions.
-
Also if QSFPM means QSortFilterProxyModel, I agree it's not bad as a solution (especially after what I managed to build with a little help); I just wish I could do a few more things with it...
-
Ok, I created my own subclass of QSqlRelationalDelegate and now everyhting works.
Here is the related code:
@QWidget *mySqlRelationalDelegate::createEditor(QWidget *aParent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
const QSqlRelationalTableModel *sqlModel = qobject_cast<const QSqlRelationalTableModel *>(index.model()); QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0; if (!childModel ) { const QSortFilterProxyModel* proxyModel = qobject_cast<const QSortFilterProxyModel *>(index.model()); if (proxyModel) { sqlModel = qobject_cast<const QSqlRelationalTableModel *>(proxyModel->sourceModel()); childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0; } } if (!childModel) { return QItemDelegate::createEditor(aParent, option, index); } QComboBox *combo = new QComboBox(aParent); combo->setModel(childModel); combo->setModelColumn(childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn())); combo->installEventFilter(const_cast<mySqlRelationalDelegate *>(this)); return combo;
}
void mySqlRelationalDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString strVal = "";
const QSqlRelationalTableModel *sqlModel = qobject_cast<const QSqlRelationalTableModel >(index.model());
if (!sqlModel )
{
const QSortFilterProxyModel proxyModel = qobject_cast<const QSortFilterProxyModel *>(index.model());
if (proxyModel) {
strVal = proxyModel->data(index).toString();
}
} else {
strVal = sqlModel->data(index).toString();
}QComboBox *combo = qobject_cast<QComboBox *>(editor); if (strVal.isEmpty() || !combo) { QItemDelegate::setEditorData(editor, index); return; } combo->setCurrentIndex(combo->findText(strVal));
}
void mySqlRelationalDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (!index.isValid())
return;QSqlRelationalTableModel *sqlModel = qobject_cast<QSqlRelationalTableModel *>(model); QSortFilterProxyModel* proxyModel = NULL; if (!sqlModel ) { proxyModel = qobject_cast<QSortFilterProxyModel *>(model); if (proxyModel) sqlModel = qobject_cast<QSqlRelationalTableModel *>(proxyModel->sourceModel()); } QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0; QComboBox *combo = qobject_cast<QComboBox *>(editor); if (!sqlModel || !childModel || !combo) { QItemDelegate::setModelData(editor, model, index); return; } int currentItem = combo->currentIndex(); int childColIndex = childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn()); int childEditIndex = childModel->fieldIndex(sqlModel->relation(index.column()).indexColumn()); if (proxyModel) { proxyModel->setData(index, childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole), Qt::DisplayRole); proxyModel->setData(index, childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole), Qt::EditRole); } else { sqlModel->setData(index, childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole), Qt::DisplayRole); sqlModel->setData(index, childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole), Qt::EditRole); }
}
@I'll try making it a Wiki!
-
[quote author="hsfougaris" date="1301553694"]Also if QSFPM means QSortFilterProxyModel, I agree it's not bad as a solution (especially after what I managed to build with a little help); I just wish I could do a few more things with it...[/quote]
Yes, QSFPM is a (here) common abbreveation for QSortFilterProxyModel :-)
Perhaps we should add a wiki page with common abbreveation sused here :-)
-
<dreaming>
We should have a feature where such abbreviations are automatically underlined with a dotted line (perhaps only for the first use in a post), which show an explanation on the meaning of that abbreviation (perhaps automagically retreived from that wiki page you talk about).
</dreaming> -
I tried to post the source as a wiki ( I created 2 separate pages - one for the delegate and one for the sortproxy thing), but I'm sure I messed it up.
Am I supposed to add them to a category, or does an admin do that?I tried adding the [[Category... thing but it appeared as plain text.
-
-
author="Andre" date="1301563925"]<dreaming>
We should have a feature where such abbreviations are automatically underlined with a dotted line (perhaps only for the first use in a post), which show an explanation on the meaning of that abbreviation (perhaps automagically retreived from that wiki page you talk about).
</dreaming>
[/quote]Make a feature request from this in Jira :-) The idea is cool.
[quote author="hsfougaris" date="1301564361"]I tried to post the source as a wiki ( I created 2 separate pages - one for the delegate and one for the sortproxy thing), but I'm sure I messed it up.
Am I supposed to add them to a category, or does an admin do that?I tried adding the [[Category... thing but it appeared as plain text.[/quote]
I added the category for you. Just have a look with edit :-)
-
Thanks... Do you have any references for suppliers of tableView alternatives?
-
Hi,
not more than you already found: devmachines and ICS. I'm sure, there are more, but I don't know who. You can search "Qt apps":http://www.qt-apps.org/
One side note to your wiki:
I found one error:
the data/setdata and flags methods should be public, as they are public in the base class. Making the protected in your derived class leads to strange behavior:
People using the base class pointers are able to call them, people using the pointers of type of your class may not. Please make them public.
-
[quote author="hsfougaris" date="1301564749"]http://developer.qt.nokia.com/wiki/QSortFilterProxyModel_subclass_for_readonly_columns_columns_with_checkboxes_and_password_columns
[/quote]
Pages, including categories, look fine to me.
-
Did you already do it in the wiki? Because I just looked at the wiki, and it's been removed.
-
[quote author="Andre" date="1301565818"]
[quote author="hsfougaris" date="1301564749"]http://developer.qt.nokia.com/wiki/QSortFilterProxyModel_subclass_for_readonly_columns_columns_with_checkboxes_and_password_columns[/quote]
Pages, including categories, look fine to me.
[/quote]
Yes, Gerolf was nice enough to fix them for me.
-
[quote author="harry" date="1301564361"]I tried to post the source as a wiki ( I created 2 separate pages - one for the delegate and one for the sortproxy thing), but I'm sure I messed it up.
Am I supposed to add them to a category, or does an admin do that?I tried adding the [[Category... thing but it appeared as plain text.[/quote]
I have modified your wiki page to add a link to "another solution":https://developer.qt.nokia.com/wiki/QSortFilterProxyModel_subclass_to_add_a_checkbox for adding checkboxes to an abstract item model. The use cases for both approaches are different, and I think they nicely supplement each other. I hope you don't mind.
Edit:
I have opened "this topic":https://developer.qt.nokia.com/forums/viewthread/5544/ to discuss the API of the class you posted in the snippet, as I think there is room for improvement. -
[quote author="harry" date="1301486015"]Ok I found something that seems to work.
(based on this http://www.qtcentre.org/archive/index.php/t-18675.html)I'm putting the code here, in case it helps someone else:
The basic idea is that there is something like a QList that holds the indexes of the columns that you want to have checkboxes (I'm already thinking of adding another QList for readonly columns).
Actual usage would be
@
CheckableSortFilterProxyModel *cfpm = new CheckableSortFilterProxyModel(this);
QList<int> boolCols;
boolCols.append( usrModel->fieldIndex("isActive") );
boolCols.append( usrModel->fieldIndex("isOk") );
cfpm->setParameters(boolCols);
cfpm->setSourceModel( mySqlTableModel );
myTableView->setModel(cfpm);
@Here is the code:
checkablesortfilterproxymodel.h:
@
#ifndef CHECKABLESORTFILTERPROXYMODEL_H
#define CHECKABLESORTFILTERPROXYMODEL_H#include <QSortFilterProxyModel>
class CheckableSortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit CheckableSortFilterProxyModel(QObject *parent = 0);void setParameters(QList<int> boolCols);
protected:
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
Qt::ItemFlags flags ( const QModelIndex & index ) const;signals:
public slots:
private:
QList<int> booleanSet;};
#endif // CHECKABLESORTFILTERPROXYMODEL_H
@checkablesortfilterproxymodel.cpp:
@
#include "checkablesortfilterproxymodel.h"CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) :
QSortFilterProxyModel(parent)
{
}void CheckableSortFilterProxyModel::setParameters(QList<int> boolCols) {
booleanSet.clear();
if (!boolCols.isEmpty()) {
foreach(int column , boolCols)
{
booleanSet.append(column);
}
}
}QVariant CheckableSortFilterProxyModel::data(const QModelIndex &index, int role) const {
if(!index.isValid())
return QVariant();if(booleanSet.contains(index.column()) && (role == Qt::CheckStateRole || role == Qt::DisplayRole)) { if (role == Qt::CheckStateRole) return index.data(Qt::EditRole).toBool() ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked); else if (role == Qt::DisplayRole) return QVariant(); } else return QSortFilterProxyModel::data(index,role);
}
bool CheckableSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) {
if(!index.isValid())
return false;if(booleanSet.contains(index.column()) && role==Qt::CheckStateRole) { QVariant data = (value.toInt()==Qt::Checked) ? QVariant(1) : QVariant (0); return QSortFilterProxyModel::setData(index, data, Qt::EditRole); } else return QSortFilterProxyModel::setData(index,value,role);
}
Qt::ItemFlags CheckableSortFilterProxyModel::flags ( const QModelIndex & index ) const {
if(!index.isValid())
return Qt::ItemIsEnabled;if(booleanSet.contains(index.column())) return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsEnabled; else return QSortFilterProxyModel::flags(index);
}
@
[/quote]I know its been over a year since this was las posted but I just wanted to say thank you to Harry for solving this because I have been struggeling with making a check box in a column for a while!