How to programmatically change the Index of QComboBox using QStandardItemModel? - c++

How to use the QStandardItemModel::setData function to set the current value for a QComboBox that is found in a certain cell for example at index (0,0) that works as a delegate such that the QStandardItemModel::setData function calls the ComboBoxItemDelegate::setModelData function.
I know that ComboBoxItemDelegate::setModelData function is called when an item is selected from the comboBox but my problem is that ComboBoxItemDelegate::setModelData function is not called by calling the comboBox::setData.
So I want to call comboBox::setData or (any other function that) programatically that will call ComboBoxItemDelegate::setModelData
What I have tried:
Here is the setModelData function that is called when an item from the comboBox is selected from the UI:
void ComboBoxItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (QComboBox* cb = qobject_cast<QComboBox*>(editor)){
qDebug()<<"hello, i have been called from the setModelData";
}
else
QStyledItemDelegate::setModelData(editor, model, index);
}
But when I tried to set the data of the comboBox (that is found in index (0,0)) to "Item A" by the following:
ui->tableView->model()->setData ( ui->tableView->model()->index(0,0), "Item A, Qt::EditRole);
the comboBox's value was set successfully, but the ComboBoxItemDelegate::setModelData function was not called, and this is my problem

Related

Disable QAction if the QTreeView item has no children

I have QTreeView populated from database.
I have contextmenu configured as:
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
I have the method to look for a right click to open contextMenu on the item.
void MainWindow::on_treeView_customContextMenuRequested(const QPoint &pos)
{
QModelIndex idx = ui->treeView->indexAt(pos);
if (!idx.isValid())
{return;}
else{
QPoint globalPos = ui->treeView->mapToGlobal(pos);
QAction* selectedItem = contextMenu->exec(globalPos);
if (selectedItem){
qDebug () << selectedItem;
}
}
h.file
QMenu *contextMenu;
How do I check if the selected item from QTreeView is not a parent of any item & it has a parent.
Should I include QTreeView and QStandardItem code here to see or that's irrelevant?
The Qt doc. has a dedicated chapter for this topic:
Model/View Programming
which I recommend to get an overview.
Concerning the actual question of OP:
How do I check if the selected item from QTreeView is not a parent of any item & it has a parent.
The QTreeView inherits QAbstractItemView::model() which provides a pointer to the QAbstractItemModel which in turn provides the underlying model data for the rendered tree view items.
Any provided QModelIndex in a view should refer to this model.
The QAbstractItemModel provides a variety of methods to retrieve data concerning visualization and relations of model items. The QTreeView uses this but it should be used as well for any added function.
So, selected item is not parent of any item is turned around into "selected item has no children" for which QAbstractItemModel::hasChildren() is good for:
bool QAbstractItemModel::hasChildren(const QModelIndex &parent = QModelIndex()) const
Returns true if parent has any children; otherwise returns false.
Use rowCount() on the parent to find out the number of children.
Note that it is undefined behavior to report that a particular index hasChildren with this method if the same index has the flag Qt::ItemNeverHasChildren set.
Note: This function can be invoked via the meta-object system and from QML. See Q_INVOKABLE.
See also parent() and index().
and it has a parent can be retrieved using QAbstractItemModel::parent():
QModelIndex QAbstractItemModel::parent(const QModelIndex &index) const
Returns the parent of the model item with the given index. If the item has no parent, an invalid QModelIndex is returned.
A common convention used in models that expose tree data structures is that only items in the first column have children. For that case, when reimplementing this function in a subclass the column of the returned QModelIndex would be 0.
When reimplementing this function in a subclass, be careful to avoid calling QModelIndex member functions, such as QModelIndex::parent(), since indexes belonging to your model will simply call your implementation, leading to infinite recursion.
Note: This function can be invoked via the meta-object system and from QML. See Q_INVOKABLE.
See also createIndex().
Putting this together, OPs function should look like this:
void MainWindow::on_treeView_customContextMenuRequested(const QPoint &pos)
{
QModelIndex idx = ui->treeView->indexAt(pos);
if (!idx.isValid()
|| !ui->treeView->model()->hasChildren(idx)
&& !ui->treeView->model()->parent(idx).isValid()) {
return;
// bail out -> no context menu for leaf nodes or toplevel nodes
} else {
QPoint globalPos = ui->treeView->mapToGlobal(pos);
QAction* selectedItem = contextMenu->exec(globalPos);
if (selectedItem) {
qDebug () << selectedItem;
}
}
}
I'm not quite sure whether this matches exactly OPs required behavior. It might be necessary to fix the condition but this should be not that hard.

Delegate erasing text in QTreeView using QStandardItemModel

I'm having some difficulty adding a delegate to my QTreeView.
I have added some QStandardItems through a model which works fine, but when I add the delegate, the text is erased and only the icons are visible.
This is the code i'm using for my delegate:
void SeqNavDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.column() == 0 && option.state & QStyle::State_Enabled)
{
const QIcon icon(QLatin1String(":/SeqNavMenu/images/green.png"));
QRect iconRect(option.rect.right() - option.rect.height(),
option.rect.top(),
option.rect.height(),
option.rect.height());
icon.paint(painter, iconRect, Qt::AlignRight);
}
}
What i would like to do is combine the two, which is to say, have the text and checkboxes, and to the right have the icons that i have put in the delegate.
Maybe someone can point me in the right direction here ?
Cheers.
When you assign a delegate to a view, the view stops rendering items by itself (actually it does it with another delegate which is replaced by yours). So it delegates the rendering to you. And you programed the delegate to draw icons only. Thats why you see only icons.
If you need to draw a check-box and a text as well you need to draw it by yourself or call the ancestors method paint somewhere in your implementation. So if you inherited SeqNavDelegate from QStyledItemDelegate call :
QStyledItemDelegate::paint(painter, option, index);

QListView & QStandardItemModel check text before editing row

I want to check the text of a row in QListView before the user is editing it. If it doesn't fit a pattern, I don't want to accept it.
Currently I have a QListView and QStandardItemModel. I can easily add and remove items via the QStandardItemModel. I also set the model of the list view.
Are there some delegates or event function(s) on the list or the model for editing?
you can overload data() and setData() functions from QStandardItemModel, then when user tries to edit item your setData will be called with Qt::EditRole and there you can do your processing.
http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#setData
If I understand you correctly, you want to check the value of an item at the time the user attempts to enter the edit mode?
Using a delegate should work for this fairly well:
class MyItemDelegate : public QItemDelegate {
public:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
if(index.data() == /* do whatever check you want here */) {
return NULL; // Prevent editing
}
return QItemDelegate::createEditor(parent, option, index);
}
};
listView->setItemDelegate(new MyItemDelegate());

How to set a delegate for a single cell in Qt item view?

Rather perplexed by this omission--but in Qt's QAbstractItemView class, it's possible to set a QAbstractItemDelegate (i.e., QItemDelegate or QStyledItemDelegate) to the entire view, a single row, or a single column, using the setItemDelegate* methods. In addition the item delegate for an individual cell can be queried, with QAbstractItemView::itemDelegate(const QModelIndex&), along with the delegate for rows, columns. and the entire view. But there appears to be no way to set an item delegate to an individual cell. Am I missing something? Any reason this should be?
No you can't set item delegate only for one cell or one column but you can easly set item delegate for whole widget and choose in which cell, column or row you want to use your custom painting or something.
For e.g.
void WidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.column() == 1)
{
// ohh it's my column
// better do something creative
}
else // it's just a common column. Live it in default way
QItemDelegate::paint(painter, option, index);
}
You can find some more information here
I'd recommend reimplementing createEditor function instead:
QWidget * WidgetDelegate::createEditor(
QWidget *parent,
const QStyleOptionViewItem &,
const QModelIndex &index) const
{
QWidget *widget = 0;
if (index.isValid() && index.column() < factories.size())
{
widget = factories[index.column()]->createEditor(index.data(Qt::EditRole).userType(), parent);
if (widget)
widget->setFocusPolicy(Qt::WheelFocus);
}
return widget;
}
Sinc Qt 4.2, QAbstractItemView provides setItemDelegateForColumn() and setItemDelegateForRow().

QComboBox Get The Varient When "currentIndexChanged(int)" Emitted

I am having difficulty finding documentation on this or an example.
Could someone concretely show me how to access the QVariant of the currently selected index in a QComboBox
QComboBox * combo = new QComboBox();
combo->addItem("Bla1", QVariant(1));
combo->addItem("Bla2", QVariant(2));
combo->addItem("Bla3", QVariant(3));
combo->addItem("Bla4", QVariant(4));
connect(combo, SIGNAL(currentIndexChanged(int)), this, slot(HANDLEITMAN(int))
And of course else where in the source
void TheCooler::HANDLEITMAN(int index)
{
//What do I do with index?
//sender()?
}
First, make combo a member of TheCooler, or otherwise put HANDLEITMAN in a class which has combo as a member. Unless it's available to TheCooler::HANDLEITMAN somehow you can't get the data, and this is the logical way to do it. Then it's just
void TheCooler::HANDLEITMAN(int index)
{
QVariant data = combo->itemData(index);
}
If you don't want to make combo a member of the class TheCooler, you can use the sender() function that returns a pointer to the QObject that sent the triggering signal (in this case, currentIndexChanged(int)).
void TheCooler::HANDLEITMAN(int index)
{
QComboBox * combo = qobject_cast< QComboBox * >(sender());
if (combo == 0)
return; // something wrong happened
QVariant data = combo->itemData(index);
}
If combo is null, then you probably tried to call the slot by yourself, or you have connected it with a signal emitted by a class that is not a QComboBox.