MFC CListCtrl updating text of any cell - mfc

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

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.

Problems with selection and highlighting in ClistCtrl

I found some problem.
I have class extended from CListCtrl. When I make double click on row I selected it. Everything good, but if I sort some column I have problem!
For example:
I have some row in second position. I selected it and sort column, highlighting is left on second position but my item has moved to 4th row (and selection moved to 4th row)
I have bad feeling that it could be some bug:(
Did somebody see problem like this?
PS: I'm not sure that I have to provide some code, because guess it's ok, but if needs it I will post it
Thank you very much and sorry for my English)
I've only seen this problem with owner data list views (LVS_OWNERDATA) so I'm guessing this is the case here. AFIK there are two possible solutions. The first is to store the selection state yourself and then use LVM_SETCALLBACKMASK to let the control know that you will provide the selection state. You will also have to respond to mouse clicks and update your data array. The other solution is to store a list of selected items before sorting, deselect all items, do the sorting and then finally restore the selection using the stored list.

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

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.

Qt Delete selected row in QTableView

I want to delete a selected row from the table when I click on the delete button.
But I can't find anything regarding deleting rows in the Qt documentation. Any ideas?
You can use the bool QAbstractItemModel::removeRow(int row, const QModelIndex & parent = QModelIndex()) functionality for this.
Here you can find an example for all this.
Also, here is an inline quote from that documentation:
removeRows()
Used to remove rows and the items of data they contain
from all types of model. Implementations must call beginRemoveRows()
before inserting new columns into any underlying data structures, and
call endRemoveRows() immediately afterwards.
The second part of the task would be to connect the button's clicked signal to the slot executing the removal for you.
If you are removing multiple rows you can run into some complications using the removeRow() call. This operates on the row index, so you need to remove rows from the bottom up to keep the row indices from shifting as you remove them. This is how I did it in PyQt, don't know C++ but I imagine it is quite similar:
rows = set()
for index in self.table.selectedIndexes():
rows.add(index.row())
for row in sorted(rows, reverse=True):
self.table.removeRow(row)
Works perfectly for me! However one thing to know, in my case this function gets called when a user clicks on a specific cell (which has a pushbutton with an 'X'). Unfortunately when they click on that pushbutton it deselects the row, which then prevents it from getting removed. To fix this I just captured the row of the sender and appended it to the "remove_list" at the very beginning, before the "for loops". That looks like this:
rows.add(self.table.indexAt(self.sender().pos()).row())
You can use another way by deleting the row from database, then clear the model and fill it again, this solution is also safe when you are removing multiple rows.