qt5 view different roles of model data - qt

I want to use a QTableView to show different roles of an item, e.g. column 1 shows the DisplayRole data, column 2 shows UserRole, column 3 shows UserRole+1, etc
I've created this by making my own item delegate and assigning it to the appropriate column. However, to get access to the same item the delegates have to access their siblings. For example, here's my setEditorData function:
void UserRoleDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QModelIndex baseIndex = index.sibling(index.row(),0);
QVariant v = baseIndex.data(Qt::UserRole);
if(v.isValid())
static_cast<QLineEdit*>(editor)->setText(v.toString());
}
Right now, it's hardcoded that column 0 contains the real object and other columns just access that via the sibling function. I'm worried, though, that it's fragile in that changing the column order will break it.
There are obvious ways to manage that, but I'm just wondering if I'm taking the right approach. Is there a better option to display different aspects of the same item?

To avoid possible code rewrite you simple could use the enumeration for your column numbers. For example:
enum ColumnNumber {
Base,
Sub1,
Sub2
}
And in your delegate's code:
[..]
QModelIndex baseIndex = index.sibling(index.row(), Base);
Thus, if you need to change the column order, you simply need to change the order of your enum values. The rest of code will work correctly as it is.
WRT to item delgate usage - it looks rather strange. Such things used to made in the model class, especially in QAbstractItemModel::data(...) function, using it with Qt::EditRole role. For example:
QVariant Model::data(const QModelIndex &index, int role) const
{
if (role == Qt::EditRole) {
// Get the data that stored in the first column
// ..
return data;
}
[..]
}

Related

QT Model/View Project doesnt show Strings from QList

My QTableView doesn't show strings from a QStringList.
In QTableWidget I have QTableWidgetItems. Must I set the strings manually or will the view show them automatically? In all the tutorials I don't see a "->setItem", they appear automatically.
I have 2 QLineEdits that give the QStrings to my Model :
void View::pushButtonClicked() {
meinModel->setData(txtname->text(), txtvalue->text());
}
In setData I push the Strings in two QLists.
names.push_back(name);
values.push_back(value);
I emit a dataChanged signal with the index from topleft and bottomright.
QModelIndex topLeft = createIndex(names.size()+1,0);
QModelIndex bottomRights = createIndex(names.size()-1,1);
emit dataChanged(topLeft, bottomRights);
I have a QAbstractTableModel and so i override the columnCount, rowCount and data Method.
In my data() Method I return my value and name:
QString returnValue;
if(0 == index.column()) { returnValue = names.at(index.row()); }
All of this compiles without warnings, but doesn't work correctly :( Is there something I'm doing obviously wrong?
One obvious problem is that you didn't get the semantics of dataChanged correctly. dataChanged means that an existing item has changed its value. When you change the structure of the model by adding/removing rows or columns, you have to enclose the modification in beginXxx and endXxx calls - see this answer for details.
For example:
void MyModel::setData(const QString & name, const QString & value) {
beginInsertRows(QModelIndex(), names.size(), names.size());
names.push_back(name);
values.push_back(value);
endInsertRows();
}

Qt5 Is it possible to retrieve an item's checkstate from a combobox without having a pointer to the model?

I know you can do it when you have access to the QStandardItemModel but using combobox->model() returns a QAbstractItemModel which doesn't have the item(int row, int col) accessor. I've tried working with QAbstractItemModel::itemData(QModelIndex) but can't get it to work as I require.
I just need to get the CheckState of the items, if(item.checkState() == Qt::Checked) etc...
Edit: I have this code, can I cast it to a QStandardItem?
QModelIndex index(1, 0);
QVariant item = ui->SearchAssessmentCombo->model()->data(index, Qt::CheckStateRole);
You can't declare an index yourself, all indices are tied to a model. Internally, the data() function will determine that the index you gave in the parameter does not belong to the model and will return null values for everything.
You need to ask your model to give you a valid index before you can use it.
QModelIndex index = ui->SearchAssessmentCombo->model()->index(1,0);

Displaying a tooltip for QTreeWidgetItem when it's hovered without calling setTooltip() for every item

I want to display a tooltip for QTreeWidgetItem that's hovered. However, getting a tooltip is not a very fast process in my case, so I don't want to call setTooltip() for every single item. I want to do it on demand, on some event or signal. What's the easiest way to do it?
The best solution I've found is to subclass QTreeWidgetItem, override virtual QVariant data(int column, int role) const; and return a tooltip for this item when data is called for Qt::ToolTipRole.
I think that it should be easier to achieve what you want if you migrate to a QTreeView/Model pattern.
QAbstractItemModel has a role for tooltips: Qt::ToolTipRole
You could subclass a Model to reimplement the
QVariant QAbstractItemModel::data ( const QModelIndex & index, int role = Qt::DisplayRole ) const [pure virtual
method.
So, when receives a Qt::TooltipRole, it calculates/recovers from an internal cache.

Adding a 'None' option to a QComboBox linked to a model

I have a QComboBox so the user can a network name from from a model column. I'm using code like this:
self.networkSelectionCombo = QtGui.QComboBox()
self.networkSelectionCombo.setModel(self.model.worldLinks)
self.networkSelectionCombo.setModelColumn(WLM.NET_NAME)
I'm using PySide, but this is realy a Qt question. Answers using C++ are fine.
I need to give the user the option of not selecting any network. What I'd like to do is add an extra item to the combo box called 'None'. However this will just get overridden by the model contents.
The only way I can think of is to create an intermediate custom view on this model column and use that to update the combo, then the view can handle adding in the extra 'magic' item. Does anyone know a more elegant way of doing this?
One possible solution is to subclass the model you are using in order to add there the extra item. The implementation is straight forward. If you call your model MyModel then the subclass would look like this (C++ used):
class MyModelWithNoneEntry : public MyModel
{
public:
int rowCount() {return MyModel::rowCount()+1;}
int columnCount() {return MyModel::columnCOunt();}
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const
{
if (index.row() == 0)
{
// if we are at the desired column return the None item
if (index.column() == NET_NAME && role == Qt::DisplayRole)
return QVariant("None");
// otherwise a non valid QVariant
else
return QVariant();
}
// Return the parent's data
else
return MyModel::data(createIndex(index.row()-1,index.col()), role);
}
// parent and index should be defined as well but their implementation is straight
// forward
}
Now you can set this model to the combo box.

How to select a row in a QListView

I'm still struggling with using QListView, I'm trying to select one particular row in the view and I cannot figure out how to do this.
I found a similar question on StackOverflow which recommends using the createIndex() method of the model, however this method is protected (perhaps it used to be public but is not anymore) so that doesn't work for me. Any suggestion?
You can get the index of anything by just calling
QModelIndex indexOfTheCellIWant = model->index(row, column, parentIndex);
Then you can call setCurrentIndex(indexOfTheCellIWant) as bruno said in his answer.
If model contains just a standard list of items as opposed to a tree structure, then it's even easier. Because we can assume that the item is a root item - no parent.
QModelIndex indexOfTheCellIWant = model->index(row, column);
With a tree structure it is a little trickier, because we can't just specify a row and a column, we need to specify these with respect to a parent. If you need to know about this part let me know and I'll explain more.
Only one more thing to note. Selection is based on cells, not really rows. So if you want to ensure that when the user selects a cell (or you do through code) that the whole row is selected you can do that by setting the "selectionBehavior" on the itself.
list->setSelectionBehavior(QAbstractItemView::SelectRows);
You can use QAbstractItemView::setCurrentIndex ( const QModelIndex & index )
Fetch an instance of QModelIndex from the QListView's model and select it:
void selectRowInQListView(int row, QListView *listView) {
QModelIndex index = listView->model()->index(row, 0);
if (index.isValid()) {
//listView->selectionModel()->select(index, QItemSelectionModel::Select);
//listView->selectionModel()->select(index, QItemSelectionModel::Current);
listView->setCurrentIndex(index);
}
}

Resources