QTableWidget - combobox delegate how do I allow different options per cell - c++

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.

Related

How to hide the first column of a wxListCtrl in wxWidgets?

The context
In a wxWidgets (version 3.0.2) C++ application, I am trying to hide the first column of a wxListCtrl.
I did not find a member function to do this so I tried to set the width of the column to 0:
myListCtrl->SetColumnWidth(0, 0);
first argument being the column ID and second one the width in pixels (wxListCtrl documentation).
After running the program, the header of the first column is hidden as I wanted but the data of each row of the first column overlaps the data of each row of the second column (which is not hidden). It is obviously not what I want. The header and the data of the first column should be hidden.
The question
In wxWidgets 3.0.2, is there a way to hide the first column (header and data of each rows) of a wxListCtrl?
I don't believe you can. You have a few options.
Delete the column using DeleteColumn(int columnIndex). You aren't losing any data, just the display of it, so you can always re-insert the column and repopulate it if you need to re-add it. Obviously this could be time consuming if your data is excessively large.
Depending on your application, just don't create the column in the first place. You don't say why you want to hide it, so if you just don't want it, don't add it.
Implement your control as a virtual control which gives your application control over what to display where. The burden of data display management falls to you to do manually but you have a great deal more flexibility. Inherit the class with wxLC_VIRTUAL style and implement OnGetItemText http://docs.wxwidgets.org/3.0/classwx_list_ctrl.html#a92370967f97215e6068326645ee76624
Edit:
To expand on the comment question, how to get the selected item index:
The wxListCtrl is a little weird when it comes to selected items. I'm sure it has to do with needing to support report, icon, etc. different views. When dealing with a multi-column report mode, you might find that you can only select items in the first column. If you are on Windows, it should automatically be set to "Full Row Select" but I don't know about other OSs.
Anyway, here is a utility method that returns the first selected item (note that you can support multi-selection if you want to).
//Get the item currently selected
int ListView::GetItemSelected() const
{
for(int i=0; i<GetItemCount(); ++i)
if (GetItemState(i, wxLIST_STATE_SELECTED) == wxLIST_STATE_SELECTED)
return i;
return -1;
}
If you want (and it makes sense), you can connect the list item selected event.
this->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxCommandEventHandler(ListView::selected_Changed), NULL, this);
and within that event handler, get the selected item and do what needs doing (depending entirely on your application).
You will note that I'm using a derived class here which just makes things a lot easier but you don't have to. You can connect to something like MyMainForm::sqlResults_selectedChanged or whatever.
There is more than one way to accomplish all this and you can also find some good suggestions and help here: https://wiki.wxwidgets.org/WxListCtrl

QTableView re-focus the view to specific column

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.

Paradimatic signal for when a user selects a row

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);

MFC CListCtrl updating text of any cell

This question is to understand how to update any row programatically.
Details.
I have a listcrtl, that accepts the data from either from a file or from the edit controls in the dialog. When the items are added I will know its position, that I added, so I can change its subitem texts. I have even implemented the sort functionality in the list, so now the position keeps changing. I have an identifier column for each row, so that I can recognize the row.
Now, from an out side event, if I have to change an other columns value of an ID that I know , I have to first find the position of the item by comparing the id column, then with that position, I have set the subitemtext.
This works fine except that it takes time to find the row first then it need to update the column.
Now, in order to get the row directly, I need some help.
I have gone through
http://msdn.microsoft.com/en-us/library/windows/desktop/hh298346(v=vs.85).aspx
But this does not use MFC. Please help me achieving this.
If you have many items you should consider switching to Virtual Lists. It is the fastest way to access the data. If you do not want to invest time to this, then the easiest way for you will be the following:
When you populate the CListCtrl store the ID of each item in the item data using the SetItemData() method. The ID will always be associated with the item, even after re-sorting.
When you need to locate the required item, just scan all items, but do not use GetItemText(). Use GetItemData() instead. This will be faster

GtkTreeView Column Header Click Event

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).