Re-implement sorting for QTableWidget? - c++

Is there a way to re-implement the sorting function for QTableWidget? I use QComboBox (multicheck) in the first row of my table to filter the data. I also want be able to sort the data in the table, but I want my widget to stay in the first row no matter how I sort the data.
I know that I can re-implement the < operator and set a value as well as a widget in a cell, but that does of course not help me.

Related

How to force sorting a QTableWidget prior to displaying

I'm using Qt 5.21.3. I have a QTableWidget that, when initially displayed, shows the rows in the order they were populated. I've set setSortingEnabled(true) and all rows are sorted properly when I click the column headers, but I'd like the table sorted on a specific column, in this case column 0, before showing the table but I can't for the life of me figure out how to accomplish it.
I've tried setting setSortingEnabled(false) prior to populating the table then to true before showing the table, but that appears to do nothing.
The way I'm getting around this now is to use std::sort to sort QList before populating the table, but this just seems like kludge to me and I'm not sure I can sort on an item other than the first if I need to.
You have to invoke the sort() method of the model:
tableWidget->model()->sort(0, Qt::AscendingOrder);
or sortItems() method:
tableWidget->sortItems(0, Qt::AscendingOrder);
after filling the table.

Qt QTreeWidget - disabling interaction for a single column

is there a way to disable interaction or just sorting for a specific row in a QTreeWidget? I have a table where if you click the header, it sorts the items. I have a custom "CTreeWidgetItem" where I have overloaded the < operator to perform a custom sort on my data. The problem is, it sorts on every header I click, not just the first column. I need it to only work for the first column. Is there something I can do?
Simply connect to the sectionClicked() signal of the header (QTreeView::header()). Then force the sort indicator back to the first section QHeaderView::setSortIndicator().

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.

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