I have a QListView pulling data from a QSQLTableModel.
Upon a user clicking an 'Add' button, I add a new item and open it for editing:
QSqlTableModel *tblModel= qobject_cast<QSqlTableModel *>(ui->listView->model());
if(tblModel->insertRow(tblModel->rowCount()))
ui->listView->edit(tblModel->index(tblModel->rowCount()-1, 1));
But once the user is done editing the new value, the selection of listView is lost. I can't find a signal on QListView or QSQLTableModel to handle when and edit has finished for me to 'restore' the selection.
Is there a way I can make sure the selection is kept?
An excerpt from edit() function documentation:
Note that this function does not change the current index. Since the
current index defines the next and previous items to edit, users may
find that keyboard navigation does not work as expected. To provide
consistent navigation behavior, call setCurrentIndex() before this
function with the same model index.
Related
I use Qt 5.6 and a QStandardItemModel filled with QStandardItem to display a data table.
Some items are enabled, some are not.
Only enabled items can be selected (this is the normal behavior).
But when the data are updated, some items enabled state can change, and this is the source of my problem. Consider the following scenario :
1 an item is enabled
2 the user select it
3 the item is selected
4 the data are updated, the item is now disabled
5 the item remain selected, despite it is disabled
And now, the user can interact with a disabled item : open context menu, edit it...
It there some "update" method in Qt model/view framework that I can call to update the selected state after a flag change ?
Or is there any simple (and generic) way to solve this problem, for all my item views ? (not all are tables, not all are based on QStandardItem)
Thanks
EDIT: This does not seem to work as the enabled property is no data but a flag and editing this should not trigger the named signal. Hang on!
What about connecting the signal
void QStandardItemModel:itemChanged(QStandardItem * item)
with some helper code like
void fixSelection(QStandardItem * item)
{
if (item.isEnabled()) {
// remove item from selection model of view...
}
}
See also here for some information about QItemSelectionModel.
You may also think about clearing the whole selection of the model if the data is modified. This will save you this extra amount of work. I do not know which action might disable some items under selection and which followup action which wants to work on the previously taken selection.
I'm making a small application that represents a to-do list.
The list is stored in a cusom model (derived from QAbstractItemModel) and is displayed in a QTableView.
I have also a custom widget (TaskDialog) that is used to browse and edit tasks from the list. The children of the TaskDialog are mapped to the model with a QDataWidgetMMapper.
On the task dialog I have also buttons that allow browsing through all the tasks in my to-do list (QDataWidgetMapper::toPrevious() ...).
The problem is that if I'm editing a task in the TaskDialog (e.g. the tasks name) and then browse to another task, the new edited enty isn't set in the model.
But if I edit something in the TaskDialog, then first change the focus to an other child widget of the TaskDialog and then press one of the browsing button, than the changes are written to the model.
How can I achive that widgets that are in a editing mode are accepted and written to the model.
I also tried the example of QDataWidgetMapper from Nokia. There it works perfectly. But they use a QStandardItemModel.
Best regards
Luke
I found a solution:
The submit policy of the QDataWidgetMapper has to be set to QDataWidgetMapper::ManualSubmit.
Then allways when I browse to a new item (i.e. one of the browse buttons is pressed) i submit the changes with QDataWidgetMapper::submit().
In my application, I have one tableview of items, and a side-panel "preview":ing the latest selected item.
I want clicking on an item to change the selection, and double-clicking to cause a "run"-action to be performed. More specifically, I want the "run"-action (including key-navigation and pressing enter) to be bound to the "activation" of the item in the table-row.
My problem is; single-clicks does not only change the selection, but fires the "activated" signal on the item. I would like to tweak it such that:
Navigation Keys, Single Mouse Click: Selection-change, update preview-panel
Enter Key, Double Mouse Click: Activate/run/open action triggered.
Is there a nice clean way to do it, or are overriding the onclick/doubleclick events my best option? Or is there some other tabular list-widget better suiting my needs?
I would connect the slot for the preview action to the currentChanged() signal of the table view's selectionModel(). This covers single clicks and key navigation.
Then there's two options for the double clicks and Enter key presses:
Subclass your tableview, override doubleClickEvent() and keyPressEvent() and fire your custom signal in there, with maybe the model index or something else as an argument. Then just connect your run method to your own signal as you have full control over when it is fired.
If you don't want to subclass, you can use the installEventFilter() mechanism.
Either I'm getting your approach wrong or I'm too tired, but if you want to trigger a run event you should avoid the activated signal completely. Set the signal slot mechanism so that your double click and Enter key press event trigger your run() function, and then the single click/nav buttons should trigger the 'activated' slot which will return your index in the tableview.
I'm pretty certain Qt wants you to be explicit about which signal points to which slot or it'll ignore it or point to a default.
I have a QTreeView with data that changes over time, with a dataChanged signal being emitted in the QAbstractItemModel every second. The items in the QTreeView can be edited as well, but when a editor is opened for a certain item the editor string is updated while I edit is, which is very annoying. Any way to prevent an editor to be updated with the new values?
Do you use your own model with QTreeView? In this case you overwrite it and not return any data for Qt::EditRole. If it is not convenient for you (you want to have the current data in the field when you begin to edit it), then you could create your own QItemDelegate/QStyledItemDelegate and implement some custom logic there: make it so the widget is not updated with new value, when it has focus, for example.
Althought I might be missing something, and there is an easier way to do this.
I'm showing a popup menu to select some values in a QTableWidget. The lowest item is a "Modify list" entry, when I select it a new window should automatically appear and the QComboBox should vanish and the cell return to a Qt::DisplayRole state.
Now Qt has all those nice API-calls like QTableWidget.edit() and QTableWidget.editItem(), what I'm really looking for is a QTableWidget.endEditing(), preferably without specifying the index of the cell, though I could get that using this call:
table.currentIndex()
… but I don't know if I can guarantee that the current cell is the cell being edited at all times.
Is there an API to close those kind of editors?
QTableWidget inherits 19 public slots from QWidget. One of those is setDisabled(), which should disable input events for that widget and all of its children.
I would try:
table.setDisabled( true );
table.setDisabled( false );
Although you said it does not work for you, there is an alternative method:
If you don't like that (the table loses focus, I believe), you can try using EditTriggers. For example:
table.setEditTriggers( QAbstractItemView::NoEditTriggers );
table.setCurrentItem(None) is what worked for me. (Don’t forget to block signals if you use some cellChanged/itemChanged slot function.)
This is with PyQt. For C++ I think replace None with NULL.
You may be able to use QTableWidget.closePersistentEditor() to close the editor. However, QAbstractItemView.closeEditor() may be closer to what you want, especially since you seem to be comfortable with the QModelIndex-based API and are already using a custom editor widget.
In my case, none of the options worked properly. So, I figured: I need to send the key press event to the line edit itself. The following works with QTreeView but probably does work with any other view or widget that opens a line edit to edit cells.
QWidget* editingWidget = treeView->findChild<QLineEdit*>();
if(editingWidget)
{
QKeyEvent keyPressEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QApplication::sendEvent(editingWidget, &keyPressEvent);
QApplication::processEvents(); // see note below
}
In my case, I wanted to start editing another field directly when having finished editing one item. That is why I put processEvents there, in most cases you can probably remove that line.
PS: yeah, it's C++, but should be easily adaptable to Python. I found this thread when I searched for the C++ solution, so maybe it helps anyone else, too.
I can't speak for list widgets. But, I got here trying to do something similar.
I was double-clicking a cell, and based on the column, bringing up a sub-form with a list, then when that was closed move to the next appropriate column based on the value selected.
My problem was I could get the value in the cell and "select" the next appropriate cell, but the original cell stayed selected in edit mode!
It finally dawned on me that my double-click was selecting the cell, ie. editing.
A single-click selects the cell but doesn't open an edit mode.
Side note: Never could get that sub-form to act truly modal, so I created a loop in the calling form: while the sub form was visible, with the only code being app.processEvents()