Using custom delegate with the class derived from QTableView - qt

I have derived a class from QTableView. and I have Promoted the Widget QTableViewto the derived class in Qt creator. and try to implement the Custom delegate in the derived class, which does not seem to work. But when I demote the QTableView Widget to QTableView. Custom delegate works.
I tried to go through a documentation but could not find any solution. Am I missing anything?
Update:
I have checked the Paint() method is called but not createEditor method.
You can find the code below.
Geometry.cpp (constructor of the class derived from QTableView)
Geometry::Geometry(QWidget *parent) :
QTableView(parent)
{
this->setAcceptDrops(true);
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
this->setContextMenuPolicy(Qt::CustomContextMenu);
this->setEditTriggers(QAbstractItemView::NoEditTriggers);
grpModel = new QStandardItemModel();
grpModel->setHorizontalHeaderItem(0,new QStandardItem ("Geometry part"));
grpModel->setHorizontalHeaderItem(0,new QStandardItem ("Surface property"));
this->setModel(grpModel);
}
MyDelegate.cpp (Definition of custom delegate)
QWidget* MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
//Definition
this method is not called
}
void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
//definition
}
void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
//definition
}
void MyDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter,option,index); // This method is called
}
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableGeometry->setModel(grpModel); //tabelGeometry is promoted to Geometry
comboDelegate = new MyDelegate();
ui->tableGeometry->setItemDelegate(comboDelegate);
}

The solution was that
I have removed this->setEditTriggers(QAbstractItemView::NoEditTriggers); from the constructor of the class Geometry.cpp. What i have understood that delegate was attached but not called because Items must be editable for the delegate to be called.

Related

Remove CellWidget from QTableWidget when focus out

I have a QTableWidget in which some cells have QComboBox as cellWidget. I want to create the comboBox only when the user clicks in the cell. For this, I have caught itemClicked signal and created the comboBox and set it as cellWidget.
Now, I want to delete this comboBox in two scenarios - if the user selects some value from the comboBox, or the user simply focusses out (click anywhere in the dialog).
For the first case, I have use the signal QComboBox::activated which is invoked when something is selected in the drop-down. There I delete the comboBox and it works fine.
However, I am not sure how to proceed for the second case (delete the comboBox when the user focusses out of the drop-down without selecting anything).
I tried capturing eventFilter for focusOut for the tablewidget as well as the comboBox, but it didn't help.
You can use QItemDelegate for this purpose:
comboboxdelegate.h
class ComboBoxDelegate : public QItemDelegate
{
Q_OBJECT
public:
ComboBoxDelegate(QObject *parent = nullptr) :
QItemDelegate(parent)
{
}
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItems(QStringList() << "1" << "2" << "3" << "4"); // fill it with your own values
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QComboBox *cb = static_cast<QComboBox*>(editor);
cb->setCurrentText(text);
}
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *cb = static_cast<QComboBox*>(editor);
QString text = cb->currentText();
model->setData(index, text, Qt::EditRole);
}
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
};
mainwindow.cpp
...
ui->tableWidget->setItemDelegate(new ComboBoxDelegate);
...

Access pointer to QWidget(Combobox) of the customdelegate

I have derived a class from QStyledItemDelegate. I am using a QComboBox in this delegate. This delegate is used in QTableView.
My question is, how can i change the index of the Combobox in the delegate programatically i.e how to access the pointer to that widget outside the delegate class ?
I have checked that CreateEditor, SetEditorData, SetModelData functions (of QStyledItemDelegate) are called automatically when we click on the combobox and we cannot call them manually to maniplate the data in the model.
afaik any time you start editing and the combobox is shown, it will allocate a new one. if you want to have a permanent combobox, you should look at
QTableView::setIndexWidget(const QModelIndex&, QWidget*)
so you could access the combobox with the following code:
const QMoodelIndex idx = model->index(row, column);
QWidget* wid = view->indexWidget(idx);
QComboBox* box = qobject_cast<QComboBox*>(wid);
if (box)
// do your thing
You can have the contents of your combobox as a class member of your delegate in a QStringList. Your item delegate can be like :
#include <QStyledItemDelegate>
#include <QComboBox>
class ComboBoxDelegate: public QStyledItemDelegate
{
Q_OBJECT
public:
ComboBoxDelegate(QObject *parent = 0);
QWidget *createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
void setEditorData( QWidget *editor,
const QModelIndex &index ) const;
void setModelData( QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index ) const;
void updateEditorGeometry( QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
QStringList comboItems;
mutable QComboBox *combo;
private slots:
void setData(int val);
};
ComboBoxDelegate::ComboBoxDelegate(QObject *parent ):QStyledItemDelegate(parent)
{
}
QWidget *ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
combo = new QComboBox( parent );
QObject::connect(combo,SIGNAL(currentIndexChanged(int)),this,SLOT(setData(int)));
combo->addItems(comboItems);
combo->setMaxVisibleItems(comboItems.count());
return combo;
}
void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString text = index.model()->data( index, Qt::DisplayRole ).toString();
int comboIndex = comboItems.indexOf(QRegExp(text));
if(comboIndex>=0)
(static_cast<QComboBox*>( editor ))->setCurrentIndex(comboIndex);
}
void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
model->setData( index, static_cast<QComboBox*>( editor )->currentText() );
}
void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry( option.rect );
}
void ComboBoxDelegate::setData(int val)
{
emit commitData(combo);
//emit closeEditor(combo);
}
When you want to update the items in combobox somewhere in your code just get a pointer to the item delegate by calling itemDelegateForColumn and access the comboItems member :
ComboBoxDelegate * itemDelegate = qobject_cast<ComboBoxDelegate *>(ui->tableView->itemDelegateForColumn(columnIndex));
//Updating combobox items
itemDelegate->comboItems.append("newItem");
...

Correctly implementing QStyledItemDelegate

I have a class (EditorTagManager) that contains a QTreeWidget. During runtime, the tree can contain any number of tag items, all of which are checkable. I'm trying to add horizontal lines between the QTreeWidgetItems in order to make it clear that these tags are unrelated and are meant to be separate from one another (each item is a root-level node).
From my research on the subject, I've figured out the only way to control the appearance of QtreeWidgetItems to any meaningful extent is to subclass QStyledItemDelegate and bind the delegate to the QTreeWidget. It's kind of an abstract concept so I don't fully understand it. Since I’ve never had to subclass a Qt object before, I'm not sure if I’m doing it correctly.
Since the Qt Documentation didn't really explain how to do this, I used the settingsdialog.cpp/.h files from the Clementine 1.0.1 source code as my guide/reference because Clementine's preferences window uses similar separators on its QTreeWidget. I'm trying to reverse-engineer my own solution from Clementine's code, the only problem is Clementine's implementation of this does things I don't need (so I have to figure out what's relevant to my code and what's not). That's what got me up to this point; my code is very similar to the Clementine code (I just changed the delegate class name):
Here is my current delegate header declaration in editortreemanager.h:
class TagListDelegate : public QWidget
{
public:
TagListDelegate(QObject* parent);
void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
};
Here is my current delegate source in editortreemanager.cpp:
TagListDelegate::TagListDelegate(QObject *parent) :
TagListDelegate(parent){
}
void TagListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const{
}
Even though TagListDelegate::paint() doesn't actually do anything yet, I just want to get this code working correctly before I try to change the appearance of the QTreeWidgetItems. My goal is to keep this as simple as possible for now.
Everything compiled fine until I told the QTreeWidget (ui->AvailableTags) to use the delegate:
ui->AvailableTags->setItemDelegate(new TagListDelegate(this));
The compiler error reads:
/home/will/qt_projects/robojournal/ui/editortagmanager.cpp:211: error:
no matching function for call to
'QTreeWidget::setItemDelegate(TagListDelegate*)'
I’m in a bit over my head here so I would definitely appreciate some help in figuring this out.
UPDATE (7/30/13):
My Delegate class now looks like this:
Source:
TagListDelegate::TagListDelegate(QStyledItemDelegate *parent) :
TagListDelegate(parent){
}
void TagListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const{
QStyledItemDelegate::paint(painter, option, index);
}
Header declaration:
class TagListDelegate : public QStyledItemDelegate
{
public:
TagListDelegate(QStyledItemDelegate* parent);
void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
};
UPDATE (7/31/13)
Here is what my classes look like now:
header:
class TagListDelegate : public QStyledItemDelegate
{
public:
TagListDelegate(QObject* parent);
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
};
source:
TagListDelegate::TagListDelegate(QObject *parent)
: TagListDelegate(parent){
}
QSize TagListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize ret = QStyledItemDelegate::sizeHint(option, index);
return ret;
}
void TagListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const{
QStyledItemDelegate::paint(painter, option, index);
}
You're not subclassing QStyledItemDelegate in your code. You're subclassing QWidget.
Change
class TagListDelegate : public QWidget
to:
class TagListDelegate : public QStyledItemDelegate
And don't forget to include the header:
#include <QStyledItemDelegate>

How to create Symbian style list views in Qt

I've never done any item delegates in Qt before, and I think the documentation doesn't explain well about more complex delegates.
I need to create 2 styles of Symbian(^3) style lists
Type 1:
This is for common navigation lists, the icon and the lower label are optional.
Type 2:
This is for settings lists, where the pushbutton can be a toggle(on/off)-button or execute a context menu, etc.
How would I go on creating these sort of item delegates?
Best Regards,
Rat
I had to make something similar once. This is how I did it.
My delegate class declaration. As you can see it has a member: QLabel *label. You can add another label or a pushbutton, depending on your needs.
class MyItemDelegate : public QStyledItemDelegate
{
public:
explicit MyItemDelegate(QObject *parent = 0);
~MyItemDelegate();
protected:
void paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const;
private:
QLabel *label;
};
My paint() and sizeHint() methods.
QSize MyItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(!index.isValid())
return QSize();
QVariant data = index.data(Qt::DisplayRole);
label->setText(data.toString());
label->resize(label->sizeHint());
QSize size(option.rect.width(), label->height());
return size;
}
void MyItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(!index.isValid())
return;
QVariant data = index.data(Qt::DisplayRole);
// Not necessary to do it here, as it's been already done in sizeHint(), but anyway.
label->setText(data.toString());
painter->save();
QRect rect = option.rect;
// This will draw a label for you. You can draw a pushbutton the same way.
label->render(painter, QPoint(rect.topLeft().x(), rect.center().y() - label->height() / 2),
QRegion(label->rect()), QWidget::RenderFlags());
painter->restore();
}
Hope this is what you've been looking for. Good luck!
You have 2 options ,
1) QML - This in my opinion is the best way to go and easier to achieve what you are trying to do.
Link to Example
This shows you how to use a Delegate for a listview.
2)QItemDelegate - Subclass QItemDelegate then Assign a this delegate to a listview ,
Link to QItemDelegate

QStandardItem + QComboBox

I am trying to put a QComboBox into a QStandardItem to be used in a QStandardItemModel. I have been looking around and I cannot find an answer, any ideas?
You don't store a QComboBox in a QStandardItemModel. Let's say you have the following choices:
A
B
C
D
and you have a list with two items in a QListView, the first value being A the second being D:
QListView* pView = new QListView();
QStandardItemModel* pModel = new QStandardItemModel();
pView->setModel(pModel);
pModel->appendRow(new QStandardItem("A"));
pModel->appendRow(new QStandardItem("D"));
What we created above is a list widget which will display the values of "A" and "D". Now, to the QComboBox. I assume you want that to edit the values of "A" and "D" in the list. For this, you need to create a QItemDelegate.
See http://doc.qt.io/qt-4.8/qitemdelegate.html
An attempt:
class ComboBoxDelegate : public QItemDelegate
{
Q_OBJECT
public:
ComboBoxDelegate(QObject *parent = 0);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
ComboBoxDelegate::ComboBoxDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *ComboBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItem("A");
editor->addItem("B");
editor->addItem("C");
editor->addItem("D");
return editor;
}
void ComboBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QString value = index.model()->data(index, Qt::EditRole).toString();
QComboBox *cBox = static_cast<QComboBox*>(editor);
cBox->setCurrentIndex(cBox->findText(value));
}
void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QComboBox *cBox = static_cast<QComboBox*>(editor);
QString value = cBox->currentText();
model->setData(index, value, Qt::EditRole);
}
void ComboBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
And then you need to set the delegate on the QListView to make it work, see:
pView->setItemDelegate(new ComboBoxDelegate(pView));

Resources