How to interact with checkbox actions ? (QTableView with QStandardItemModel) - c++

I'm using QTableView and QStandardItemModel to show some data.
For each row, there is a column which has a check Box, this check box is inserted by setItem, the code is as follows:
int rowNum;
QStandardItemModel *tableModel;
QStandardItem* __tmpItem = new QStandardItem();
__tmpItem->setCheckable(true);
__tmpItem->setCheckState(Qt::Unchecked);
tableModel->setItem(rowNum,0,__tmpItem);
Now I want to interact with the check box. If a check box changes its state by user (from checked to unchecked or vice versa), I want to do something on the corresponding data row.
I know I can use signal-slot to catch the change of checkbox, but since there are lots of data row, I don't want to connect each row one by one.
Is there anyway to interact with the check action more effectively? Thanks :)

I don't deal with QTableView+QStandardItemModel, but may be example below will help you:
1). table.h file:
#ifndef TABLE__H
#define TABLE__H
#include <QtGui>
class ItemDelegate : public QItemDelegate
{
public:
ItemDelegate(QObject *parent = 0)
: QItemDelegate(parent)
{
}
virtual void drawCheck(QPainter *painter, const QStyleOptionViewItem &option,
const QRect &, Qt::CheckState state) const
{
const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter,
check(option, option.rect, Qt::Checked).size(),
QRect(option.rect.x() + textMargin, option.rect.y(),
option.rect.width() - (textMargin * 2), option.rect.height()));
QItemDelegate::drawCheck(painter, option, checkRect, state);
}
virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
const QModelIndex &index)
{
Q_ASSERT(event);
Q_ASSERT(model);
// make sure that the item is checkable
Qt::ItemFlags flags = model->flags(index);
if (!(flags & Qt::ItemIsUserCheckable) || !(flags & Qt::ItemIsEnabled))
return false;
// make sure that we have a check state
QVariant value = index.data(Qt::CheckStateRole);
if (!value.isValid())
return false;
// make sure that we have the right event type
if (event->type() == QEvent::MouseButtonRelease) {
const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter,
check(option, option.rect, Qt::Checked).size(),
QRect(option.rect.x() + textMargin, option.rect.y(),
option.rect.width() - (2 * textMargin), option.rect.height()));
if (!checkRect.contains(static_cast<QMouseEvent*>(event)->pos()))
return false;
} else if (event->type() == QEvent::KeyPress) {
if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
&& static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
return false;
} else {
return false;
}
Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
? Qt::Unchecked : Qt::Checked);
QMessageBox::information(0,
QString((state == Qt::Checked) ? "Qt::Checked" : "Qt::Unchecked"),
QString("[%1/%2]").arg(index.row()).arg(index.column()));
return model->setData(index, state, Qt::CheckStateRole);
}
virtual void drawFocus(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect) const
{
QItemDelegate::drawFocus(painter, option, option.rect);
}
};
static int ROWS = 3;
static int COLS = 1;
class Table : public QTableWidget
{
Q_OBJECT
public:
Table(QWidget *parent = 0)
: QTableWidget(ROWS, COLS, parent)
{
setItemDelegate(new ItemDelegate(this));
QTableWidgetItem *item = 0;
for (int i=0; i<rowCount(); ++i) {
for (int j=0; j<columnCount(); ++j) {
setItem(i, j, item = new QTableWidgetItem);
item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable);
item->setCheckState((i+j) % 2 == 0 ? Qt::Checked : Qt::Unchecked);
}
}
}
};
#endif
2). main.cpp file:
#include <QApplication>
#include "table.h"
int main(int argc, char **argv)
{
QApplication a(argc, argv);
Table w;
w.show();
return a.exec();
}
Good luck.
PS: here is the original text.

handle the click event, there you will get the modelindex, get the data and modify the same
if you are going to insert more than one text or icon, then you need to set the delegate for your listview

Here is another similar idea of the example suggested by mosg using a QStyleItemDelegate instead. http://developer.qt.nokia.com/faq/answer/how_can_i_align_the_checkboxes_in_a_view

Use on clicked slot and index.data(Qt::CheckStateRole) :
void MainWindow::on_tableView_clicked(const QModelIndex &index)
{
if(index.column() == 2){
if(index.data(Qt::CheckStateRole) == Qt::Checked){
//your code
}else if(index.data(Qt::CheckStateRole) == Qt::Unchecked){
//your code
}
}
//get other infos
QVariant value = index.sibling(index.row(),0).data();
QString selectedMessageName = value.toString();
}

Related

image with 3 possibility of value

I would like to personalize the 3rd columns to contain QCheckBox widgets. I would like those QCheckBox widgets to be customized with three icons: 1.png (Default state) | 2.png (Selected state) | 3.png (Disabled state). So I could do this using a custom delegate with the following implementation:
#include "mydelegate.h"
#include <QCheckBox>
#include <QPainter>
#include <QKeyEvent>
#include <QtDebug>
#include <QApplication>
#include <QStyleOptionViewItem>
MyDelegate::MyDelegate(QObject* parent) :
QStyledItemDelegate(parent)
{
// 1.png
_icon.addPixmap(QPixmap("1.png"), QIcon::Active, QIcon::On);
// 2.png
_icon.addPixmap(QPixmap("2.png"), QIcon::Selected, QIcon::On);
// 3.png
_icon.addPixmap(QPixmap("3.png"), QIcon::Disabled, QIcon::On);
}
void MyDelegate::paint(QPainter* painter, const QStyleOptionViewItem&
option, const QModelIndex& index) const
{
if (index.column() != 2)
QStyledItemDelegate::paint(painter, option, index);
else
{
bool value = index.model()->data(index,
Qt::UserRole).toBool();
QStyleOptionButton buttonVis;
buttonVis.rect = option.rect;
buttonVis.iconSize = QSize(50, 50);
buttonVis.icon = _icon;
buttonVis.features |= QStyleOptionButton::Flat;
buttonVis.state |= value ? QStyle::State_Enabled : QStyle::State_None;
QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonVis, painter);
}
}
bool MyDelegate::editorEvent(QEvent* event, QAbstractItemModel* model,
const QStyleOptionViewItem& option, const QModelIndex& index)
{
if (event->type() == QEvent::MouseButtonRelease)
{
bool value = model->data(index, Qt::UserRole).toBool();
model->setData(index, !value, Qt::UserRole);
}
return true;
}
The problem that it's work for 1.png and 3.png and not for the 2.png. i want that it will work for the three icons
It is not necessary to implement the paint(...) or use editorEvent(...) methods, it is only necessary to override the initStyleOption(...) method by enabling the option of the icon.
In the following example the item (2, 2) is selected, the item (4, 2) is disabled and the other items are enabled but not selected showing 3 types of icons:
#include <QtWidgets>
class MyDelegate: public QStyledItemDelegate
{
public:
MyDelegate(QObject *parent=nullptr):
QStyledItemDelegate(parent)
{
m_icon.addPixmap(QPixmap("1.png"), QIcon::Active, QIcon::On);
m_icon.addPixmap(QPixmap("2.png"), QIcon::Selected, QIcon::On);
m_icon.addPixmap(QPixmap("3.png"), QIcon::Disabled, QIcon::On);
}
void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override{
QStyledItemDelegate::initStyleOption(option, index);
if (index.column() == 2){
option->features |= QStyleOptionViewItem::HasDecoration;
option->icon = m_icon;
option->decorationSize = QSize(50, 50);
}
}
private:
QIcon m_icon;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTableWidget w(10, 4);
MyDelegate *delegate = new MyDelegate(&w);
w.setItemDelegate(delegate);
QTableWidgetItem *item = new QTableWidgetItem;
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
w.setItem(4, 2, item);
w.show();
return app.exec();
}
Update: The OP is using an inadequate terminology since it refers to the status of a widget (normal, selected, disabled), instead it must indicate the states unchecked, partially checked and checked.
#include <QtWidgets>
class MyDelegate: public QStyledItemDelegate
{
public:
MyDelegate(QObject *parent=nullptr):
QStyledItemDelegate(parent)
{
uncheckedIcon = QIcon("1.png");
partiallyCheckedIcon = QIcon("2.png");
checkedIcon = QIcon("3.png");
}
void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override{
QStyledItemDelegate::initStyleOption(option, index);
if (index.column() == 2){
QIcon m_icon;
QVariant value = index.data(Qt::UserRole);
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
if(state == Qt::Unchecked)
option->icon = uncheckedIcon;
else if (state == Qt::PartiallyChecked)
option->icon = partiallyCheckedIcon;
else
option->icon = checkedIcon;
option->features |= QStyleOptionViewItem::HasDecoration;
option->decorationSize = QSize(50, 50);
}
}
bool editorEvent(QEvent* event, QAbstractItemModel* model,
const QStyleOptionViewItem& option, const QModelIndex& index) override
{
bool r = QStyledItemDelegate::editorEvent(event, model, option, index);
if(index.column() != 2)
return r;
if ((event->type() == QEvent::MouseButtonRelease)
|| (event->type() == QEvent::MouseButtonDblClick)
|| (event->type() == QEvent::MouseButtonPress)) {
if ((event->type() == QEvent::MouseButtonPress)
|| (event->type() == QEvent::MouseButtonDblClick))
return true;
QVariant value = index.data(Qt::UserRole);
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
state = static_cast<Qt::CheckState>((state + 1) % 3);
return model->setData(index, state, Qt::UserRole);
}
return r;
}
private:
QIcon uncheckedIcon;
QIcon partiallyCheckedIcon;
QIcon checkedIcon;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTableWidget w(10, 4);
MyDelegate *delegate = new MyDelegate(&w);
w.setItemDelegate(delegate);
w.resize(640, 480);
w.show();
return app.exec();
}

Customizing QTableView grid style

I'm wondering several things. I have subclassed QTableView to make a custom table. I'd like to be able to do several things.
First of all, I wanted the selected cells not to all have the "selected" color (blue by default) but instead have a frame around the selected cells (just like in Excel). To do this, I've used the following (in my custom QItemDelegate):
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QModelIndex upIndex = index.sibling(index.row() - 1, index.column());
QModelIndex downIndex = index.sibling(index.row() + 1, index.column());
QModelIndex rightIndex = index.sibling(index.row(), index.column() + 1);
QModelIndex leftIndex = index.sibling(index.row(), index.column() - 1);
auto newOption = option;
if (option.state.testFlag(QStyle::State_Selected))
{
painter->save();
auto selIndexes = selM->selectedIndexes().toSet();
painter->setPen(QPen(Qt::red, 5));
if (!selIndexes.contains(rightIndex))
painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
if (!selIndexes.contains(upIndex))
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
if (!selIndexes.contains(downIndex))
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
if (!selIndexes.contains(leftIndex))
painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
painter->restore();
// newOption.palette.setBrush(QPalette::Normal, QPalette::Highlight, index.data(Qt::BackgroundRole).value<QColor>());
newOption.palette.setBrush(QPalette::Normal, QPalette::Highlight, Qt::gray);
}
QStyledItemDelegate::paint(painter, newOption, index);
}
This is probably not optimal, but I'd like to have something that works, before anything else.
Now it seems to be working, but it unfortunately isn't automatically repainted. What happens when I select cells is the following:
Which is not what I'm looking for at all. I guess it's not being repainted because (1) The points inside the zone are still red and (2) If I resize my window, I get the following:
Which is way closer to what I'm trying to achieve.
I've already tried to do this in my QTableView:
// selModel is my selection model
connect(selModel, &QItemSelectionModel::selectionChanged, [this]() {
for(const auto & selected : selModel->selectedIndexes())
{
update(visualRect(selected));
repaint(visualRect(selected));
}
}
(Before, I actually used setDirtyRegion but it didn't work either, so I figured I'd do something more... brutal.)
Finally, I have another question: why do I get those weird red "small lines" in my cell corners? Even on the "kind of" correct screenshot I get these lines that I can't explain:
Please suggest if you have any ideas for any of the issues.
The problem can be easily explained as follows.
Assume that the cell (0,0) is selected. Now the user selects the additional
cells (0,1), (1,0) and (1,1). Qt correctly repaints the additional 3 cells, that
became selected. But, it doesn't repaint the cell (0,0), as it was neither
selected nor deselected. Of course for your desired behavior you still need to redraw this cell.
This can easily be achieved by just redrawing all indices of your current selection.
MyDelegate.h
#pragma once
#include <QStyledItemDelegate>
#include <QItemSelectionModel>
class MyDelegate : public QStyledItemDelegate {
public:
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setSelectionModel(QItemSelectionModel* selectionModel);
private:
QItemSelectionModel* mSelectionModel{ nullptr };
};
MyDelegate.cpp
#include "MyDelegate.h"
#include <QPainter>
#include <QDebug>
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (!mSelectionModel) return;
auto newOption = option;
auto normalText = newOption.palette.brush(QPalette::ColorGroup::Normal, QPalette::ColorRole::Text);
newOption.palette.setBrush(QPalette::ColorGroup::Normal, QPalette::ColorRole::Highlight, QBrush(Qt::GlobalColor::blue, Qt::BrushStyle::NoBrush));
newOption.palette.setBrush(QPalette::ColorGroup::Normal, QPalette::ColorRole::HighlightedText, normalText);
QStyledItemDelegate::paint(painter, newOption, index);
QModelIndex upIndex = index.sibling(index.row() - 1, index.column());
QModelIndex downIndex = index.sibling(index.row() + 1, index.column());
QModelIndex rightIndex = index.sibling(index.row(), index.column() + 1);
QModelIndex leftIndex = index.sibling(index.row(), index.column() - 1);
//auto newOption = option;
//newOption.palette.setBrush(QPalette::Normal, QPalette::Highlight, Qt::transparent);
if (option.state.testFlag(QStyle::State_Selected))
{
painter->save();
painter->setClipRect(option.rect);
auto selIndexes = mSelectionModel->selectedIndexes().toSet();
painter->setPen(QPen(Qt::red, 5));
if (!selIndexes.contains(rightIndex))
painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
if (!selIndexes.contains(upIndex))
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
if (!selIndexes.contains(downIndex))
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
if (!selIndexes.contains(leftIndex))
painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
painter->restore();
}
}
void MyDelegate::setSelectionModel(QItemSelectionModel* selectionModel)
{
mSelectionModel=selectionModel;
}
main.cpp
#include <QApplication>
#include <QDebug>
#include <QStandardItemModel>
#include <QTableWidget>
#include "MyDelegate.h"
int main(int argc, char** args) {
QApplication app(argc, args);
auto widget = new QTableView;
QStandardItemModel model;
model.setRowCount(10);
model.setColumnCount(10);
for (auto i = 0; i < 10; i++) {
for (auto j = 0; j < 10; j++) {
model.setItem(i, j, new QStandardItem("Test"));
}
}
auto selModel = new QItemSelectionModel;
selModel->setModel(&model);
widget->setModel(&model);
widget->setSelectionModel(selModel);
auto delegate = new MyDelegate;
delegate->setSelectionModel(selModel);
widget->setItemDelegate(delegate);
// Ensures that also items are repainted, that where neither selected nor deselect, but will stay selected
// This solutions eventually paints elements twice
QObject::connect(selModel, &QItemSelectionModel::selectionChanged, [widget,selModel](auto &selected, auto& deselected) {
for (auto item : selModel->selectedIndexes()) {
widget->update(item);
}
});
widget->show();
app.exec();
}
As for the strange red line artifacts, you should paint the red line inside the allowed rectangle I guess. This is easily achieved by clipping to the item boundaries.

Qt tablView with model containg pointer to custom class

I created my custom class (CustomObject), that inherit from QGraphicsItem. I use those object to draw on scene (rectangles, polygons and stuff) and I store pointers to them in QList. Now I need to display all my CustomOBjects in tableView, but there are 2 conditions:
When I select and interact with object in tableview - I must be able to interact with "real" CustomObject represented by it (example: I selected obj1 in tableview and click button "delete" or "edit" - and I want to be able to interact with acctaul object (delet or edit it).
When I add new or change it - i wish to see change in tableView.
I'm not sure if i can achieve that with jsut table view and soem custom mdoel - or shoud I make my own QAbstractItemModel class, but if i do - how do i do it? Shoud i make class inherit from QAbstractItemModel and add pointer to my CustomObject, or just force my CustomObjects into soem specific model?
Little bits of my code:
Here is my CustomObject.h
//I removed some code that was stricly related to "personal" functions related with specific features of my app
class CustomObject : public QGraphicsItem
{
public:
CustomObject();
CustomObject(int _x, int _y, int _w, int _h);
virtual QRectF boundingRect() const;
void set_Name(QString name);
QString get_Name();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
private:
QString Name;
I store them in list, in my "Overseer" class:
class ObjOverseer
public:
void drawingCustomObject_Do(int x, int y); //This function creates new "CustomObject" and adds it to the list (below)
QList<CustomObject*> ObjectsList_CustomObjects;
In my mainwindow - I simply create that ObjOverseer and keep its pointer.
EDIT 1
I used this example:
https://doc.qt.io/archives/4.6/itemviews-addressbook.html
and created this class:
CustomModelOfCustomObject::CustomModelOfCustomObject()
{
}
CustomModelOfCustomObject::CustomModelOfCustomObject(QObject *parent)
: QAbstractTableModel(parent)
{
}
CustomModelOfCustomObject::CustomModelOfCustomObject(QList<CustomObject*> objects, QObject *parent)
: QAbstractTableModel(parent)
{
ListOfObjects=objects;
}
int CustomModelOfCustomObject::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return ListOfObjects.size();
}
int CustomModelOfCustomObject::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 2;//TODO - ZMIENIC ILOSC KOLUMN
}
QVariant CustomModelOfCustomObject::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= ListOfObjects.size() || index.row() < 0)
return QVariant();
if (role == Qt::DisplayRole) {
CustomObject* obj = ListOfObjects.at(index.row());
if (index.column() == 0)
return obj->get_Name();
else if (index.column() == 1)
return obj->get_Address();
}
return QVariant();
}
QVariant CustomModelOfCustomObject::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return tr("Name");
case 1:
return tr("Address");
default:
return QVariant();
}
}
return QVariant();
}
bool CustomModelOfCustomObject::insertRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginInsertRows(QModelIndex(), position, position+rows-1);
for (int row=0; row < rows; row++) {
CustomObject* obj;
ListOfObjects.insert(position, obj);
}
endInsertRows();
return true;
}
bool CustomModelOfCustomObject::removeRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position+rows-1);
for (int row=0; row < rows; ++row) {
ListOfObjects.removeAt(position);
}
endRemoveRows();
return true;
}
bool CustomModelOfCustomObject::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {
int row = index.row();
CustomObject* p = ListOfObjects.value(row);
if (index.column() == 0)
p->set_Name(value.toString());
else if (index.column() == 1)
p->set_Address(value.toString());
else
return false;
ListOfObjects.replace(row, p);
emit(dataChanged(index, index));
return true;
}
return false;
}
Qt::ItemFlags CustomModelOfCustomObject::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}
QList<CustomObject*> CustomModelOfCustomObject::getList()
{
return ListOfObjects;
}
But still, when i reach point in my function where i shoud use this model- i dont know hwo i shoud add it or even if i will be able to use it as intended.
EDIT 2
When i chaned ListOfObject to public and tried:
MyModel->ListOfObjects.append(newObj);
all crashed
First thing to note is, you list in ObjOverseer and CustomModelOfCustomObject are not connected, you need to save the pointer of ObjOverseer list instead of copy it to CustomModelOfCustomObject. This one :
CustomModelOfCustomObject::CustomModelOfCustomObject(QList<CustomObject*> objects, QObject *parent)
: QAbstractTableModel(parent)
{
ListOfObjects=objects;
}
You need to add function to your CustomModel that will handle adding new customobject :
bool CustomModelOfCustomObject::insertNewData(CustomObject *obj, int rowposition = -1)
{
int row = rowposition < 0 ? ListOfObjects.size : row;
beginInserRows(QModelIndex(), row, row);
ListOfObjects.insert(row, obj);
endInsertRow();
}
And when you want to add new object, simply call those function. If you list on model is connected to ObjOverseer (pointer type), you does not need to add new object to your ObjOverseer.
Solved it. Now i only add "representation" of object to model and whenever i need to update any object (ew. change name or color) i just do it via my overseer, passing soem kind of guid/identifier/id/anything that woudl let me tell objects apart form eachother.

Qt: Space between individual cells in QTableWidget

(Using Qt 5.5.1 on Windows 8.1)
I have a table displaying images selected by the user.
I know their are many other ways to display multiple images on a GUI, but I'm new to Qt, so I didn't understand how to use QGraphicsView and found the following to be the easiest way.
But this forms a table in which images are not separated. I want some space b/w them. See how the next images starts right where the first ends.
How can I do it so that next image starts after leaving some space?
I need those checkboxes too (they came bu default by using QTableWidget) because after adding images, I want user to select them too for further processing.
main.cpp
QFileDialog dialog(this);
dialog.setNameFilter(tr("Images (*.jpg)"));
dialog.setFileMode(QFileDialog::ExistingFiles);
QStringList all_filenames = dialog.selectedFiles();
int maxCol = 3;
int maxRows = all_filenames.size() / maxCol;
ui->tableWidget->setColumnCount(maxCol);
ui->tableWidget->setRowCount(maxRows);
int remainder = all_filenames.size() % maxCol;
if (remainder != 0)
{
maxRows +=1;
}
ui->tableWidget->horizontalHeader()->setDefaultSectionSize(200);
ui->tableWidget->verticalHeader()->setDefaultSectionSize(200);
if(all_filenames.isEmpty() == 0)
{
for( int i = 0; i < all_filenames.size() ; ++i)
{
QPixmap map(all_filenames.at(i));
map = map.scaled(200,200,Qt::IgnoreAspectRatio,Q::FastTransformation);
QBrush brush(map);
QTableWidgetItem* item = new QTableWidgetItem();
item->setCheckState(Qt::CheckState());
item->setBackground(brush);
ui->tableWidget->setItem(j,k,item);
k++;
if ( k == maxCol )
{
j++;
k = 0;
}
}
}
EDIT
cmargindelegate.cpp
#ifndef CMARGINDELEGATE_H
#define CMARGINDELEGATE_H
#include <QItemDelegate>
class CMarginDelegate : public QItemDelegate
{
public:
explicit CMarginDelegate(int margin, QObject* parent);
~CMarginDelegate();
private:
int m_margin;
public slots:
void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index);
};
#endif // CMARGINDELEGATE_H
cmargindelegate.cpp
#include "cmargindelegate.h"
#include <QItemDelegate>
CMarginDelegate::CMarginDelegate(int margin, QObject*parent):QItemDelegate(parent),m_margin(margin)
{}
CMarginDelegate ::~CMarginDelegate()
{}
void CMarginDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)
{
QStyleOptionViewItem itemOption(option);
// Make the 'drawing rectangle' smaller.
itemOption.rect.adjust(m_margin, m_margin, -m_margin, -m_margin);
QItemDelegate::paint(painter, itemOption, index);
}
Implement a custom delegate to draw your table cells. You can start with this one:
class CMarginDelegate : public QItemDelegate
{
public:
CMarginDelegate(int margin, QObject* parent)
: QItemDelegate(parent),
m_margin(margin)
{}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
QStyleOptionViewItem itemOption(option);
// Make the 'drawing rectangle' smaller.
itemOption.rect.adjust(m_margin, m_margin, -m_margin, -m_margin);
QItemDelegate::paint(painter, itemOption, index);
}
private:
int m_margin;
};
And this is how to use it:
ui->tableWidget->setItemDelegate(new CMarginDelegate(5, ui->tableWidget));

How to make some column non-editable and some column editable in QTableView?

I have the model MyModel : public QSqlTableModel.
I want to forbid editing certain columns of the table. I did this using the method flags(), but faced with a new problem. I need to insert a row in the database, and when I cause methods insertRow () and setData (), the method setData () returns 0 for not editable columns. Therefore, I can not fill data to inserted row.
I want to forbid editing certain columns for view, but not for the model.
Some code:
Qt::ItemFlags ApplicantTableModel::flags(const QModelIndex &index) const
{
if(index.column() == 9 || index.column() == 10)
if(index.column() == 9 && index.data() == 0)
return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
else
return Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable;
else return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
}
I fix it in next way. I created delegate.
QWidget *StatusDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() == 9){
QComboBox* editor = new QComboBox(parent);
editor->addItem(tr("Відраховано"));
editor->addItem(tr("Допущено"));
editor->addItem(tr("Бюджет"));
editor->addItem(tr("Контракт"));
editor->setAutoFillBackground(true);
return editor;
}
else return 0;
}
Given the information you left, I created an example widget, which shows that setData() even works on non editable indexes.
Model
class MyModel : public QStandardItemModel
{
public:
MyModel(QObject* parent = 0)
: QStandardItemModel(parent)
{}
Qt::ItemFlags flags(const QModelIndex &index) const {
if(index.column() < 5)
return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
else
return Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable;
}
};
Table Widget
// .h
class MyTableWidget : public QWidget
{
Q_OBJECT
public:
MyTableWidget(QWidget* parent = 0);
private slots:
void onEditTextChanged(QString const&);
private:
void initWidgets();
void initLayout();
QTableView* table_view_;
MyModel* table_model_;
QLineEdit* table_edit_;
};
// .cc
MyTableWidget::MyTableWidget(QWidget* parent)
: QWidget(parent)
, table_view_(0)
, table_model_(0)
, table_edit_(0)
{
initWidgets();
initLayout();
}
void MyTableWidget::onEditTextChanged(QString const& text)
{
foreach(QModelIndex index, table_view_->selectionModel()->selectedIndexes())
table_model_->setData(index, text);
}
void MyTableWidget::initWidgets()
{
table_view_ = new QTableView(this);
table_edit_ = new QLineEdit(this);
table_model_ = new MyModel;
table_model_->setColumnCount(10);
table_model_->setRowCount(10);
for(int c = 0; c < table_model_->columnCount(); ++c) {
for(int r = 0; r < table_model_->rowCount(); ++r) {
table_model_->setData(table_model_->index(r,c), QString("foo"));
}
}
table_view_->setModel(table_model_);
connect(table_edit_, SIGNAL(textChanged(QString const&)),
this, SLOT(onEditTextChanged(QString)));
}
void MyTableWidget::initLayout()
{
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(table_view_);
layout->addWidget(table_edit_);
setLayout(layout);
}
Leaving out the Qt::ItemIsEditable flag will only prevent editing by any caller that handles this flag. For instance, Qt delegates check flags() before they create the editor for modifying cell values. This prevents from ever calling setData(). If you call setData() yourself there should be no problem in editing the data.
I am assuming your error lies somewhere else. Did you overwrite setData() to handle flags()? Did you check if the ModelIndex you are handing in is correct?