Changing selection behavior of a QTableView - qt

I am using QTableView in Qt and I have one table in which each cell has different text color. I have selection behavior select entire row. But when I select any row, text color changes to white for the selected row. I don't want to change text color while row is selected. I want original color to be displayed when I select any row.
I tried to use stylesheet but it is also changing entire row text color.
I am posting here sample code
QTableView * pQTableView = new QTableView();
QStandardItemModel *model = new QStandardItemModel(5,3);
pQTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
pQTableView->setModel(model);
for(int row = 0;row < 5;row++)
for(int column = 0; column < 3; column++)
{
QModelIndex index1= model->index(row,column);
QVariant value("Swaminarayan");
model->setData(index1, value,Qt::DisplayRole );
}
QModelIndex index1= model->index(0,0);
QVariant Obj(Qt::green);
model->setData(index1,Obj,Qt::TextColorRole );
index1= model->index(0,1);
QVariant Obj1(Qt::red);
model->setData(index1, Obj1,Qt::TextColorRole );
pQTableView->show();
Here you can see color of first cell is green and second sell is red once we select first row color changes to white.

You could also just set the selection mode to NoSelection for the TableView.
You could then use the itemClicked() signal to get the item index and set its color as you wish for each item in the row. Something like this:
connect( myTableView,
SIGNAL( clicked( const QModelIndex &) ),
this,
SLOT( onItemClicked(const QModelIndex &) ) ) ;
//....
void DataModel::onItemClicked(const QModelIndex &index)
{
//get the clicked item
QStandardItem *clickedItem = myDataModel->itemFromIndex(index);
// get the row
int selectedRow = clickedItem->row();
// for each col change the color as you want
for(int c = 0, colCount = myDataModel->columnCount(); c < colCount; ++c)
{
QStandardItem *itemToChange = myDataModel->item( selectedRow, c);
QBrush brush;
brush.setColor(Qt::red);
itemToChange ->setData(brush, Qt::ForegroundRole);
}
}

It seems you should implement your own table view based on QTableView and reload data() function:
QVariant YourTableViewClass::data(const QModelIndex &index, int role) const
{
if(!index.isValid()) {
return QVariant();
}
/* any other checks here */
switch(role) {
case Qt::BackgroundRole:
return QColor(/* background colour here */);
case Qt::ForegroundRole:
return QColor(/* foreground colour here */);
case Qt::DisplayRole:
/* any other actions here */
default:
break;
} /* switch(role) */
return QVariant();
}
For Qt::BackgroundRole and Qt::ForegroundRole you can implement your colours.
Please see http://qt-project.org/doc/qt-5.0/qtcore/qabstracttablemodel.html for QAbstractTableModel for reference. Hope it helps.

Related

How to add different types of delegates in QTreeView

I want to create same kind of QTreeView (not QTreeWidget) structure as shown in attached figure.. This is Property Editor of QT.
I am using QT-4.6
On 2nd column, depending on different condition, I can have either a spin box, or a drop down or a checkbox or text edit... and so on...
Please guide me on how to set different delegates in different cells of a particular column.
From docs, it is evident that there is no straight away API for setting delegate on a cell (rather is available for full widget or a row or a column).
All QAbstractItemDelegate methods, like createEditor or paint, have a model index as one of their parameters. You can access model data using that index and create an appropriate delegate widget. When you create your model you should set some value to every item that will be used to distinguish its type.
An example:
enum DelegateType
{
DT_Text,
DT_Checkbox,
DT_Combo
}
const int MyTypeRole = Qt::UserRole + 1;
QStandardItemModel* createModel()
{
QStandardItemModel *model = new QStandardItemModel;
QStandardItem *item = new QStandardItem;
item->setText("Hello!");
item->setData(DT_Checkbox, MyTypeRole);
model->appendRow(item);
return model;
}
QWidget* MyDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
int type = index.data(MyTypeRole).toInt();
// this is a simplified example
switch (type)
{
case DT_Text:
return new QLinedEdit;
case DT_Checkbox:
return new QCheckBox;
case DT_Combo:
return new QComboBox;
default:
return QItemDelegate::createEditor(parent, option, index);
}
}
#hank This is in response to your last comment... Do you see any flaw in it ?
MyItem* item2 = new MyItem(second);
item2->setData(delType, **MyTypeRole**);
if(delType == DT_Combo)
{
QString str1, str2, str3;
QStringList abc ;
abc << ("1" + str1.setNum(counter) ) << ("2" + str2.setNum(counter) )<< ( "3" + str3.setNum(counter) );
item2->setData(abc, MyTypeRole1);
}
QWidget* MyDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
int type = index.data(MyTypeRole).toInt();
// this is a simplified example
switch (type)
{
case DT_Text:
return new QLinedEdit;
case DT_Combo:
{
QComboBox* cb = new QComboBox(parent);
QStringList entries - index.data(MyTypeRole1).toStringList();
cb->addItems(entries)
return cb;
}
On different item2, I dynamically create entries with a counter variable that is different everytime it comes here...
Here, different combo boxes display different entries.
Does the approach looks fine to you ?

Set QItemDelegate on a particular QTreeWidgetItem

Is it possible to set a QItemDelegate on a particular QTreeWidgetItem? I need to color some of the QTreeWidgetItems with a particular color.
I assume it is possible as we have QAbstractItemView::setItemDelegateForRow but I can't figure out how. I can't use QAbstractItemView::setItemDelegateForRow because I need to set a custom delegate on a child row inside the QTreeWidget.
Does anyone know a solution for that?
You can't use QTreeWidgetItem in delegate directly (probably you can store list of this items inside delegates but I think that it is not efficient), because delegates works with QModelIndex and data inside different roles. You can set data to Qt::UserRole+1 and access it inside delegate. For example:
QTreeWidgetItem *cities = new QTreeWidgetItem(ui->treeWidget);
//...
cities->setData(0,Qt::UserRole+1,"chosen one");
QTreeWidgetItem *osloItem = new QTreeWidgetItem(cities);
//...
QTreeWidgetItem *berlinItem = new QTreeWidgetItem(cities);
//...
berlinItem->setData(0,Qt::UserRole+1,"chosen one");
Inside delegate (just example):
void ItemDelegatePaint::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QString txt = index.model()->data( index, Qt::DisplayRole ).toString();
if( option.state & QStyle::State_Selected )
{
if(index.data(Qt::UserRole+1).toString() == "chosen one")
painter->fillRect( option.rect,Qt::green );
else
painter->fillRect( option.rect, option.palette.highlight() );
}else
if(option.state & QStyle::State_MouseOver)
{
if(index.data(Qt::UserRole+1).toString() == "chosen one")
painter->fillRect( option.rect,Qt::yellow );
else
painter->fillRect( option.rect, Qt::transparent );
}
else
{
QStyledItemDelegate::paint(painter,option,index);
}
}
You can access the QTreeWidget from you delegate's paint routine to check if a condition for painting the background is met
void custom_delegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
const QTreeWidget* tree_widget = qobject_cast<const QTreeWidget*>(qstyleoption_cast<const QStyleOptionViewItemV3*>(&option)->widget);
....
}
or you store something in the QModelIndex UserData as Chernobyl suggested. In that case I would however create an enum for flags (if this is applicable in your case):
enum custom_painter_flags{
paint_default = 0,
paint_background = 1
};
void somewhere_creating_the_items()
{
QTreeWidgetItem* newitem = new QTreeWidgetItem(...);
newitem->setData(0, Qt::UserRole, QVariant::fromValue<int>(custom_painter_flags::paint_background));
}
void custom_delegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
custom_painter_flags painter_flags = static_cast<painter>(index.data(Qt::UserRole).value<int>());
if(painter_flags & paint_background){
....
}
}
Unfortunately I have not much time right now so this is thrown together pretty quick. Feel free to edit if you find any errors.
You can use qss on the QTreeWidgetItem to change color or background color.
I have done it for a QTableWidget, You must check the value of all your QTreeWidgetItem and set a background color / color.
For example, for my QTableWidget i have done something like this in a loop :
if(good item):
MyQTableItem.setBackground(QtGui.QColor(255,255,255))

Qt - Triggering an event when selection of abstract item delegate changes

I am trying to make a tableview with a row which has a separate dropdown for each column. The user can only select a combination of values. That is, if the user selects "A" from the first drop down, the values in the other drop downs should be updated to that which can match "A".
I have made my AbsractItemDelegate class and the values are being assigned fine. But I am stuck up at how I can trigger an event when a value changes in one of the drop downs.
Thanks.
The following is my delegate class implementation:
FillComboBox::FillComboBox(QStringList the_list) : QItemDelegate() {
//list = new QStringList();
list = the_list; }
QWidget* FillComboBox::createEditor(QWidget* parent,
const QStyleOptionViewItem& /* option */,
const QModelIndex& /* index */) const {
QComboBox* editor = new QComboBox(parent);
editor->addItems(list);
editor->setCurrentIndex(2);
return editor; }
void FillComboBox::setEditorData(QWidget* editor,
const QModelIndex &index) const {
QString text = index.model()->data(index, Qt::EditRole).toString();
QComboBox* combo_box = dynamic_cast<QComboBox*>(editor);
combo_box->setCurrentIndex(combo_box->findText(text)); }
void FillComboBox::setModelData(QWidget* editor, QAbstractItemModel* model,
const QModelIndex &index) const {
QComboBox* combo_box = dynamic_cast<QComboBox*>(editor);
QString text = combo_box->currentText();
model->setData(index, text, Qt::EditRole); }
void FillComboBox::updateEditorGeometry(QWidget* editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const {
editor->setGeometry(option.rect); }
You can update the data of the "other" item as soon as the current item's data is updating, i.e. in FillComboBox::setModelData(). Please find the pseudo code that implements desired behavior (see comments):
void FillComboBox::setModelData(QWidget* editor, QAbstractItemModel* model,
const QModelIndex &index) const
{
QComboBox* combo_box = dynamic_cast<QComboBox*>(editor);
QString text = combo_box->currentText();
model->setData(index, text, Qt::EditRole);
// Find the model index of the item that should be changed and its data too
int otherRow = ...; // find the row of the "other" item
int otherColumn = ...; // find the column of the "other" item
QModelIndex otherIndex = model->index(otherRow, otherColumn);
QString newText = text + "_new";
// Update other item too
model->setData(otherIndex, newText, Qt::EditRole);
}

Drawing a check mark in Qt

I am working with simple QTreeView. Each row of tree is a specific class inherited from one class EditorRow.
EditorRow has these functions:
virtual QVariant data(ColumnIndexEnum index, int role = Qt::DisplayRole) const = 0;
virtual void setData(const QVariant& data, ColumnIndexEnum index, int role = Qt::UserRole);
virtual QWidget* getEditor(QWidget* parent) const;
Each row has its specific widget, which is shown in the right column when selecting that row. When the row is not selected data function returns appropriate value for each row(f.e. the value which was chosen in the QComboBox).
But in case of row, which's widget is QCheckBox, I need to draw a checked(or unchecked) checkbox when the row is not selected.
I have tried to use Decoration role like this:
if(Qt::DecorationRole == role)
{
if(ValueColumn == index)
{
QStyle* style = QApplication::style();
QStyleOptionButton opt;
opt.state |= QStyle::State_Enabled;
if(isChecked())
opt.state = QStyle::State_On;
else
opt.state = QStyle::State_Off;
const int indicatorWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &opt);
const int indicatorHeight = style->pixelMetric(QStyle::PM_IndicatorHeight, &opt);
const int listViewIconSize = indicatorWidth;
const int pixmapWidth = indicatorWidth;
const int pixmapHeight = qMax(indicatorHeight, listViewIconSize);
opt.rect = QRect(0, 0, indicatorWidth, indicatorHeight);
QPixmap pixmap = QPixmap(pixmapWidth, pixmapHeight);
pixmap.fill(Qt::transparent);
{
QPainter painter(&pixmap);
QCheckBox cb;
cb.setLayoutDirection(Qt::RightToLeft);
style->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, &painter, &cb);
}
return QIcon(pixmap);
}
}
It actually works, but the icon is shown always, even when the row is selected.
I think it is because of DecorationRole.
Do You have any ideas how to handle this problem ?
Thank You.

How to show icons use QSqlRelationalTableModel and QTableView in every row

Now,I am try to use QSqlRelationalTableModel and QTableView to show my data in database,according to the properity "fileType" such as "doc,txt,exe,sln" to show a icon in the first column.
dirModel=new QSqlRelationalTableModel(this);
dirModel->setTable("ecm_doc");
dirModel->setFilter(QString("creatoruserid='%1' and parentid='%2'").arg(userid).arg(parentid));
dirModel->select();
dirView=new QTableView(this);
dirView->setItemDelegate(new DirDelegate(this));
dirView->setModel(dirModel);
dirView->setSelectionMode(QAbstractItemView::SingleSelection);
showIcon();
void DirTree::showIcon()
{
int rowCount = dirModel->rowCount();
for(int row = 0; row < rowCount; row++)
{
//here is a test.
QModelIndex index = dirModel->index(row, 1);
QIcon folderIcon(style()->standardPixmap(QStyle::SP_DirClosedIcon));
dirModel->setData(index, folderIcon, Qt::DecorationRole);
}
}
Help me,online wait:)
You should subclass from QSqlRelationalTableModel and reimplement the data() function in order to specify the icon:
QVariant MyModel::data(const QModelIndex &index, int role) const
{
// I assume that 1 is the db table column with the filetype property
if (index.column() == 1 && role == Qt::DecorationRole)
{
QSqlRecord r = modelRecord(index.row());
QString fileType = r.field(1).value().toString();
QIcon icon;
if (fileType == "exe")
icon = QIcon(":/PathToIcon/exe.png");
else if (fileType == "sln")
icon = QIcon(":/PathToIcon/sln.png");
...
return QVariant(icon);
}
return QSqlRelationalTableModel::data(index, role);
}

Resources