I have a QTableView that represents a model made of rows and few columns, for example coordinates such as x,y,z. The rows are whole elements and I want to trigger a signal every time a user has chosen a selection. I envision some graphics object changing depending on the selected row.
My current attempt is to do something like
ui.tlbView->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
ui.tlbView->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows);
connect(ui.tlbView,&QTableView::clicked ,this,&FancyWidget::rowSelected);
This works sometimes, but fails other times. For example clicking on the vertical header does not register while the selection changes. This is bad because I want a signal that triggers every time the selection changes.
This makes me feel like catching the clicked signal is a hack and given that the widget correctly identifies that it is selected, even when my clicked signal is not called. I'm trying to figure out how to match 1:1 the selection state of the widget.
To get notified of selection changes, have a look at QItemSelectionModel.
The table view's selection model you can access via selectionModel(). In your case, QItemSelectionModel::selectionChanged() should be what you need.
connect(ui.tlbView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &FancyWidget::selectionChanged);
Related
I'm implementing show/hide column behaviour in a standard C++ Win32 application (no frameworks).
Say we've got 3 columns in a ListView control in Details view. The user has the option to show/hide the last two columns in order to see the extra detail if wanted or hide them to reduce clutter. All works well except that after the columns are deleted and then re-added, the data from the sub-items in those columns doesn't show up again, i.e. the columns are empty.
None of the items themselves have been altered in the meantime - do I lose the sub-item text when I delete the columns or I am missing something to force the columns to redraw the data?
Steps to reproduce:
1) Create a ListView32 control with 3 columns and add a bunch of items (and text to each of the items' sub-items). All good.
2) The user clicks "Hide Details", so I use LVM_DELETECOLUMN twice to remove the last two columns and they disappear. All good.
3) The user clicks "Show Details", so I use LVM_INSERTCOLUMN to add the last two columns and the headings appear, but the columns themselves are empty.
As an alternative, setting the column widths to zero is a hack and the user can still grab the re-size column splitter, so it's not a great option.
Many thanks for any suggestions.
Typically one does not store data in GUI. In case of plain listview32 you should add items specifying LPSTR_TEXTCALLBACK instead of real text and then handle LVN_GETDISPINFOW notification supplying (sub)item data. Windows will send this notification for all items. You can force Windows to retrieve data again by sending LVM_UPDATE message.
Setting the column widths is a viable solution. That is the way I do it in my UIs when columns can be shown and hidden dynamically. It works fine.
To prevent the user from resizing "hidden" columns, simply subclass the ListView using SetWindowLongPtr(GWL_WNDPROC) or SetWindowSubclass() to intercept HDN_BEGINTRACK notifications from the ListView's header control:
Notifies a header control's parent window that the user has begun dragging a divider in the control (that is, the user has pressed the left mouse button while the mouse cursor is on a divider in the header control). This notification code is sent in the form of a WM_NOTIFY message.
...
Returns FALSE to allow tracking of the divider, or TRUE to prevent tracking.
I'm using QDataWidgetMapper to display values in a model. I set its submit policy to be ManualSubmit so that users won't accidentally put in wrong values. But I also want to warn the user about unsubmitted change if he/she selects another row without saving. I have consulted the documentation and the Internet, but it seems that no signals are emitted prior to change in selection, nor is there any API querying the dirty status of the QDataWidgetMapper, which makes my task seemingly impossible. Is there any way to achieve this?
You can have a variable in the submit slot whose value you can monitor when the user selects another row.
Let value of that variable be x.
When user selects another row, fire a signal whose slot will check whether some text has changed or appeared in the text box of previous row && if that variable is still x.
If the variable is still x that would mean user didn't click the submit button.
When user clicks the submit button, let the variable be y.
I have a QTableView with 80+ columns displayed in it. The subclass i have created for QTableView allows has functionality for the standard table stuff i wanted e.g order by columns move columns and rows hide column and rows etc.
However the problem i have is the view's focus. lets say you have all the data in the table, you scroll all the way to the right so you are looking at columns 70-80 (assuming 10 columns fit on the screen at once) if i click the header of row 80 (to order by column 80) the table reorders (as expected) however it also jumps the view to the last focused cell (which as far as i can tell is the cell that was last clicked)
What i want to do is not necessarily refocus on the column that was clicked because this might still change the view what im looking for is to just keep the view's focus exactly as it is instead of having it jump back to where the last clicked cell was?
Is there some flag im missing for focus policy or will i need to get the current view and set the view back to that view after mouse clicks that reorder the table and if so how could this be done.
Im aware i have provided no code for this question but it doesnt seem there is any needed since its not a bug im looking to fix more of a feature im unaware of, if you want to see any just comment
EDIT:
Im using a QSortFilterPorxyModel, this seems to get set once (when i call this->setSortingEnabled(true); after the initial call to this on contruction my table model never calls sort again. I have a slot linked to the header clicked signal, and i set the scroll bars to scrollTo() to the index clicked, but i think the sort is happening after this so it does nothing, any idea of what signal are emitted after sorting so i can catch them and then set the view back maybe?
thanks
Before you do your sort, store the current values for where the scroll bars are with
int vPos = yourQTableView->verticalScrollBar()->sliderPosition();
int hPos = yourQTableView->horizontalScrollBar()->sliderPosition();
then after the sort, set it back
yourQTableView->verticalScrollBar()->setSliderPosition(vPos);
yourQTableView->horizontalScrollBar()->setSliderPosition(hPos);
The signals you are looking for are signals of QSortFilterProxyModel inherited from QAbstractItemModel:
layoutAboutToBeChanged()
layoutChanged()
I couldn't reproduce your symptoms by creating a QTableWidget, filling it up with random stuff, and then sorting a particular column. The selected cell stays selected, but does not become visible if it has scrolled off screen.
So the question is, what is causing the behavior you're seeing. It sounds as though scrollTo() is being called by some other function. Since that's a virtual function, I would override it with a pass-through function and see when it's getting called.
Aloha
I have a QTableWidget with two columns that are currently using a ComboboxDelegate (my subclass of QItemDelegate) to present options to the user. I'd like the choice in the first column to effect the options available in the second, for the current row only.
E.g have a list of cars in the first column, and in the second a list of colours which are available for that car. Other rows to have different cars selected and thus different colour choices available.
From what I can see, I can only set an item delegate per row or column, so I can't see how to change the options in the second column's delegate without affecting all the other rows.
Is this possible? I'd really like to avoid going to a full view/model separation as I have quite a bit of code looking at this QTableWidget already (and I'm under time pressure)
Well for those interested; I went back to my pre-delegate approach, which was to use QTableWidget::setItemWidget() to provide a combobox widget for each cell.
I subclassed qcombobox to take a reference to the table, and connected the combobox CurrentIndexChanged with a slot to update the table data.
(setting a widget in a cell does not affect the tablewidget data unless you do this).
Using a full combobox like this is more expensive than an itemdelegate, but my tables are very small so I can get away with it. The rendering of the combobox is not as nice as the delegate (the combobox is visible all the time instead of only during editing in the delegate's case), but with time I'm sure I can improve on this.
I have a question. I have a GtkListStore and a GtkTreeView, and I want to sort the GtkListStore and update the result to the GtkTreeView when the user clicks on a certain column of the GtkTreeView. I am assuming that the columns are clickable, and cannot be re-ordered, so the numerical order of the columns can be used to set the sorting column's index. But I cannot seem to find which signal gets emitted when the user clicks on the header of a particular column. I have gone through the GTKMM documentation time and again, but it does not seem to be mentioned!
Use Gtk::TreeView::get_column(<column-no>) to get a particular column and attach to its "clicked" signal using Gtk::TreeViewColumn::signal_clicked():
Gtk::TreeViewColumn* col = myview.get_column(SOME_COLUMN_NUMBER);
col->signal_clicked().connect(sigc::mem_fun(*this,&some_method));
That's not how you're supposed to do it.
There can be several views hooked up to the same model; sorting is not something you do to the model, it's something you do to the view.
See the GtkTreeSortable interface (and its GtkTreeModelSort implementation).