How to implement mixed selection model for QTableView - qt

I have custom table view that shows content of custom abstract model.
I need to implement mixed selection for these view.
When user clicks on the first column the whole row should be selected (AbstractItemView::SelectRow).
When user clicks on cell in other column just the particular cell should be selected (AbstractItemView::SelectItems).
What need to do to achieve such behaviour?

Just do this:
void MainWindow::on_tableView_clicked(const QModelIndex &index)
{
//if(!index.column()) more elegant
if(index.column() == 0)
ui->tableView->selectRow(index.row());
}
Catch clicked() signal and check is it first column. If so, then selectRow() with current row (index.row())
I use here QTableView but QAbstractItemView has clicked signal too.

Related

How to update values in QTableView

I have a QTableView which gets its data from QAbstractTableModel and is a 2d array. Below the TableView I have two comboboxes. User first selects the row in the TableView. Now I want that when the user selects an option from the combobox, I want the selected option to update the display in the TableView selection.
Shown below is the UI. For example if the User Selects REF DES in the class combo box I want the selected row to update its class name to REF DES.
I am using c++ qt5. How do I achieve this with signals and slots?
enter image description here
Currently I have a slot that updates the combobox values based on my selection in tableview. I use something like this.
void GetOptionsClass::slotSelectionChange(const QItemSelection&, const QItemSelection&)
{
int rowidx = ui->line_tableView->selectionModel()->currentIndex().row();
data = model->index(rowidx, 2).data().toString();
if (data == "BOARD GEOMETRY") {
ui->lineSubclass->clear();
ui->lineSubclass->addItems(board_geometry_opts);
ui->lineClass->setCurrentIndex(0);
}
However I want to reverse this. Meaning when I change combobox I want to update the qtableview.

QlistView setCurrentIndex() not working

I am facing a problem with a QListView component.
I created a simple form with a listview and a tableview.
Then I put this code, both widgets populate with the data model as I want:
QSqlQueryModel * modela = new QSqlQueryModel();
QSqlQueryModel * modelb = new QSqlQueryModel();
[...]
ui->listView->setModel(modela);
ui->tableView->setModel(modelb);
[...]
void MyWindow::on_listView_clicked(const QModelIndex &index)
{
ui->tableView->setCurrentIndex(ui->listView->currentIndex());
}
void MyWindow::on_tableView_clicked(const QModelIndex &index)
{
ui->listView->setCurrentIndex(ui->tableView->currentIndex());
// FAILS, does not react...
}
The first slot (when I click any item in the listview widget) works as expected, it automatically selects the corresponding item in the tableview widget, but the second case does not work, it just does not select any item in the listview...
What I want is that whatever item the user clicks in the tableview gets selected in the listview.
Is it possible?
I tried hard, looking for examples and the official qt documentation, but I don't find the right way to do (also tried to connect with signal/slots, but I don't know how to exactly connect both widgets).
Thanks in advance.
QModelIndex is an integral part of a certain QAbstractItemModel. It means that you can't use an index from model A to select an item in a view of model B.
QModelIndex is not just a couple of x,y. It also keeps a pointer to a model which created it.
So if you need to select the same row as selected in the first view, you need to extract a row from the first index, then get a right index in the second model and use it to select an item in the second view:
void selectTheSameRow(const QModelIndex& indexFromModelA)
{
int row = indexFromModelA.row();
QModelIndex indexFromModelB = modelB->index(row, 0);
viewB->setCurrentIndex(indexFromModelB);
}

QStandardItemModel within QTtableview

I am using QStandardItemModel inside QTtableview. Is it possible to add checkbox in on column cell & combobox in another column cell.
So that i can select predefined option from the combo box.
Please suggest how to achieve this.
For the first:
You can setFlags() on an QStandardItem to make it checkable:
Qt::ItemFlags QStandardItem::flags() const
void QStandardItem::setFlags ( Qt::ItemFlags flags )
Qt::ItemIsUserCheckable
( enum Qt::ItemFlag )
For the second:
You should create your own Custom Delegate class inheriting QStyledItemDelegate and reimplement the createEditor, setEditorData and setModelData methods. Check this link and, for a more complete example, the SpinBox Delegate example
Edit: Once you got your custom delegate class, you have to tell your view to use it in a given column with QAbstractItemView::setItemDelegateForColumn

Interact with editor widgets' data in QTableView

I'm using an editable QTableView + QStandardItemModel.
While editing a cell in a table view, I'd like to do something according to the new input data in this specific cell when committing the new data into the table view.
To do this, I need the new input data and the current model index (or column & row number).
I tried some slots such as
virtual void closeEditor (QWidget * editor,
QAbstractItemDelegate::EndEditHint hint)
and
virtual void commitData ( QWidget * editor ).
commitData seems to be what I need, however, the parameter is only the editor and I cannot figure out how to obtain the text in this editor widget.
I looked QTextEdit but it's not a inherited class of QWidget.
I wonder if there's any way to obtain the data (text) and axis (column, row) of an editor widget?
I suggest to implement your own item delegate, inheriting QStandardItemDelegate (or QAbstractItemDelegate). There you can override
void setModelData ( QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const
Simply do you your custom processing and then call QStandardItemDelegate::setModelData(...) to make sure that your model is updated with the newly edited data.
The itemChanged(QStandardItem*) signal is emitted by a QStandardItemModel whenever an item's data changes.
From the given QStandardItem, you can retrieve the row and column directly. To get the displayed text, pass Qt::DisplayRole to the item's data() method.

indexWidget() unexpectedly returns a NULL pointer

I am attempting to create a model/view application in Qt 4.7.1. I am a very new Qt developer.
Summary of what I am attempting to do:
I have a treeview that is organized as a rectangular table of rows and columns. One column of items contains a button. By default this button is to be transparent and disabled. A given button is to become visible and enabled when the mouse is hovering over its row.
The approach I am pursuing is to
find the model index for the cell that the mouse is hovering over, and
obtain a pointer to the widget associated with the widget, and
using this pointer manipulate the visibility of the button within said widget.
I cannot get a valid pointer to the widget.
my current code looks like this:
void HistoryTreeView::mouseMoveEvent(QMouseEvent *event)
{
QAbstractItemModel *m(model());
// Only do something when a model is set.
if (m)
{
QModelIndex index = indexAt(event->pos());
if (index.isValid())
{
// if the mouse has moved to another row
if (index.row() != m_currentRow)
{
m_currentRow = index.row();
QMessageBox::information( this, "HistoryTreeView", QString("index(%1)").arg(index.row()));
QWidget * item = indexWidget(index);
Q_ASSERT(item != NULL );
}
}
else // model is invalid
{
m_currentRow = -1;
}
}
QTreeView::mouseMoveEvent(event);
}
The symptoms:
I expected the call to indexWidget() to return a valid pointer to the widget the mouse is over. Instead it unexpectedly returns a NULL pointer.
Commentary:
The variable named 'index' is acting as I expected because the QMessageBox shows the correct row value. Consequently I do not think there is anything wrong with the value I am providing to indexWidget().
This is just debug code. It is missing things like code that selects the column that holds the buttons.
OK, Here is the nature of my error as I understand it.
I had incorrectly understood that every item in a view is its own widget. I now understand that the view itself is a widget, but that individual items within the view are not widgets, per se.
Because I had misunderstood that view items were widgets I believed that could:
obtain an index from a given element in a model,
use indexWidget() to obtain a Widget * to the view item associated with the model element
and then use this pointer to manipulate the view item as though it was a widget.
indexWidget() simply returned a NULL because view items are not widgets.

Resources