How to hide vaadin Table row with an empty cell? - row

I am using a vaadin Table to put some rows with two columns, so each row has a vaadin Tree (I am not using a TreeTable) in the first cell and a description (string) in the second cell. So when I click on a Tree item, it edits the description cell of the row.
Then I have added a filter on each Tree to filter on the nodes's caption.
So if a Tree doesn't have any captions passing the filter, the Tree isn't display.
But in this way, the table contains some row with nothing in the first cell and a description in the second and that is not ergonomic at all so what I want now is find a way to filter the Table row and hide the ones which are empty in the first cell.
I hope my question understandable.

I resolved my problem using the size() method of the Tree class.
Indeed, this method returns the number of visible nodes in the Tree. So if Tree has a filter and none of its nodes are displayed, then size() will return 0.
So all I had to do is updating my table style with
myTable.setCellStyleGenerator()
and in the getStyle() method, I get the Tree of my row and I get its size, if the size is 0, I hide the table row with css.
I think it could be a better way to hide these rows with a table filter but I'm still working on it.
thanks,
Tom

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.

Update of QTreeView without changing selection

I have a model that retrieves data from a table in a database from a certain SQL query, and shows the items in a QTreeView. The characteristics are:
the data comes from a table, but has an underlying tree structure (some rows are parents that have rows below them as children)
this tree structure is shown in the QTreeView
the children are selectable in the QTreeView (not so the parents)
the table in the database gets updated continuously
in the updates, a children can be added to any existing parent
periodically (with a QTimer) the QTreeView is updated with the contents of the table
Since the children are added at any time to any parent, the first silly approach when updating the QTreeView is clearing it all, and append all the rows again, in form of parent or children, to the QTreeView. This is a 0-order approximation, and it is indeed terrible inefficient. In particular, the following problems appear:
Any existing selection is gone
Any expanded parent showing its children is collapsed (unless ExpandAll is active)
The view is reset to show the very first row.
What is the best solution to this problem? I mean, the first solution I will try will be not to clear the QTreeView, but instead parse all the returned rows from the table, and check for each of them whether the corresponding item in the QTreeView exists, and add it if not. But I wonder if there is a trickiest solution to engage a given table in a database with a QTreeView (I know this exists for a QTableView, but then the tree structure is gone).
This thread mentions a general approach, but this might get tricky quickly, but I am not sure how this would work if the underlying model is changing constantly (i.e. the QModelIndex becoming invalid).
Worst case is that you will have to write your own mechanism to remember the selection before updating and then re-applying it.
I assume you use some model/view implementation? You could enhance your model with a safe selection handling, in case the example mentioned above does not work for you.
I guess this is the case for a self-answer.
As I presumed, after a careful analysis of what data is retrieved from the database, I had to do the following "upgrades" to the retrieval code:
I retrieve, along with the fields I want to show in the view, two identifiers, one for grouping rows and one for sorting items into groups
I also retrieve the internal record ID (an increasing integer number) from the table in the database, in order to ask only for new records in the next retrieval.
In the model population code, I added the following:
I first scan the initial records that may belong to existing groups in the model
When, in the scanning, I reach the last group in the model, this implies that the rest of retrieved records belong to new groups (remember the records are retrieved sorted such that items that belong to the same group are retrieved together)
Then start creating groups and adding items to each group, until we use all the records retrieved.
Finally, it is very important:
the use beginInsertRows() and endInsertRows() before and after inserting new items in the model
capture the sorting status of the view (with sortIndicatorSection() and sortIndicatorOrder()) and re-apply this sorting status after updating the model (with sortByColumn())
Doing that the current position and selection in the QTreeView receiving the model updates are preserved, and the items in the view are added and the view updated transparently for the user.

Sales list force change of column in lines

I'm using the page below a POS sales list. Here the user can use the barcode pistol and pass the article and the code is translated into the item no.
The problem is when they use the pistol and end to pick a item and want to pass to next one the line go automatically to the first column (Item type) and my goal was to force to go into the second column (Item no), because the Item type is by default the type "product".
Only change the order of columns of Item no to Item product is not enough in this case.
Since ACTIVATE is not supported for controls in RTC.
Not many good options here.
Try using QuickEntry Property. Set it to false for all controls on subpage except No..
Create custom page with as less fields as possible, use it as buffer to scan all items and create sales lines upon closing of this new page. You can implement desired behavior on this page and keep original page almost unmodified
Create add-in that will intercept scanner output somehow.

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

Returning objects that work with parent object's data and later invalidate them

I'm working on an implementation of tables in a Qt app, but having a bit of trouble getting the design right.
I have two classes, Table and Cell.
Cell has API for setting cell properties such as borders and paddings, and getting the row and column of the cell using int Cell::row() and int Cell::column(). It is an explicitly shared class, using QExplicitlySharedDataPointer for its data. It also has an isValid() API to query if the cell is valid or not.
Table has API for inserting/removing rows and columns and merging areas of cells. A Cell may be retrieved from a table using Table::cellAt(int row, int column). Rows of cells are kept as a QList<QList<Cell>>. When rows and columns are removed, the removed cells are marked as invalid by the table, which makes calls to Cell::isValid on any previously returned cells from the removed rows/columns return false.
Now to the tricky part: Since calculating the row and column number of a cell if you haven't already got them is an expensive operation, the Table::cellAt(int row, int column) methods sets the row/column explicitly on the Cell before returning it and the Cell keeps them as simple int members. This means a Cell can reply fast when queried for its row/column.
But here comes the problem; This also means that the values of Cell::row() and Cell::column will be incorrect if rows or columns are removed/inserted before the row/column that the cell is in.
I can't mark the affected cells as invalid in the same way I do when the actual row/column they are part of is removed. Since later on someone might again retrieve a cell with cellAt(int, int) in that row/column. And that cell should not be invalid.
Does anyone have some advise on a better design here?
You could do a lazy update. That is, instead of updating the cell's position information every time the table changes, only update it when Cell:row or Cell:column are called if the table has changed since the last time the cell's position was updated. That would require you to keep a version stamp or something in Table and Cell. Every time the table gets updated, bump the version. Cell::row and Cell:column would first check if the Cell's version is older than the Table's, and if so, recalculate the position.
Whether that extra work is worth it versus just always recalculating position or recalculating on every change, I can't say.
I discussed this problem with a friend because it seemed too much like a Programming Pearls exercise. This is what we came up with:
Create a new structure for counting indices. It could be something like struct Index { int n; };.
Store row and column indices in two QList<Index*>. Let's call these Dimension. Using a pointer is crucial, as you'll see later.
Cells do not store their row and column values anymore. They point to an element at each of the two Dimension. When queried for their row and column, there is now an extra pointer dereference which should not be too expensive.
When the table has rows and columns added or removed, you add items to or remove items from the corresponding Dimension and update the n value of the following items. Storing pointers is necessary because QList copies its values.
Instead of renumbering every Cell affected by a table manipulation, an operation that has a cost of O(rows x columns), you'll now update only the affected rows or columns, which has cost of O(rows + columns). The downside is added code complexity and two dereferenced accesses when the Cell is queried for its row or column.