on the grid and virtualgrid
Posted: Fri Sep 30, 2011 11:42 am
In Qt there are two kinds of "grids": QTableView and QTableWidget. (1)
The difference is in how they handle the "cells".
Simplifying a bit, we may say that QTableView asks the program what and how to print each cell using a callback mechanism.
QTableWidget, instead, has to be loaded with data by the program and then handles everything itself.
This basic difference has quite big consequences.
QTableView is the basis of VIRTUALGRID and BROWSE (2), QTableWidget is the basis for GRID.
VIRTUALGRID handles both arrays and DBFs. For arrays, in the program you create the array, set grid to use it, and the grid will start to do the callbacks... how many rows ? which is the back/forecolor of cell at position 3,6 ? What text should I print at cell 2,1 ?
VIRTUALGRID answers all these queries in abstractGrid:onQuerydata(). For example the row count for arrays is quite easy:
(look in the source code, the forum program doesn't allow me to post the code....)
With VIRTUALGRID you work directly with the underlaying data. If you change a value in the array, the array is directly updated, the same for DBF fields. Of course, this is both good and bad. But for quick data entry it may be good.
As I said, QTableView asks the program for the data to display. For arrays it is quite simple, the grid rows matches the array row -1 (grid is 0-based, array is 1-based).
For DBFs with filters, index, ordscope, set deleted on the situation is a bit more complex. Infact if we can use with a simple dbGoto in case of none of the cited "filters" are set, it is a condition very rarely found in common use.
If we have index and optionally a ordscope, we may use ord* functions (not implemented now)
But if a filter is set, we must use "skip" to move between records.
Let's go with an example: we have to browse a DBF table with a controlling index on LastName. We have a VIRTUALGRID.
Qt QTableView asks for the number of rows in the data, and it gets back 200.
Then it starts to ask for the data for each row. Let's say there are 21 rows that can fit the screen, so it asks data for rows 0,1,2,3,4,5,6,7 up to 20. We move between records using skip n, with n calculated remembering the position we are and where we want to go.
Now click on first row: Qt asks again for data in row 0 (row 0 is a gotop()). Now row 0 is selected. Click on row 20. Qt asks for data for row 0 to draw the cells without the selection colors and then asks for data for row 20 to display it as selected. If we exit focus from the grid, row 20 is displayed with selected-disabled color, and data requested yet another time. (3)
As you may understand, everytime Qt needs to repaint the screen it asks the program the data... isn't it wonderful ?
Yes, it really is.
But in this DBF access we must consider SHARED dbf access. What happens if someone changed LastName of row 20 in another program instance and we click on row 20 ? If the change modified the order in the index of record 20, clicking on it would change what is shown on screen, since the skip would move to a different record!
But if I used a cache system to remember the recno() of row 20 and use dbGoto(), I may go to a record that is no more in the correct order, and since I may have some mixed cached and not cached records, it may become a mess.
QTableView in several occasions asks for a new record count, refreshes the rows shown on the screen asking for data, for example when it regains focus, when the grid is partially covered by other windows... at that moment the screen is refreshed and new rows and changed data are shown... (4)
and so we are at the crucial point: Qt needs info and ask for them, and it decides when to do... and it changes recno() pointer... it changes it several times... we may also try to reposition the pointer back at every request but it may be dangerous !
How can we trust the data in a shared DBF ? how can we be sure to not UPDATE the wrong record ?
Can Qt asks for data in the middle of an UPDATE ALL ? or a loop calculating some totals ???
(end of part 1.... is anybody interested in a part 2????)
(1) QTableWidget inherits from QTableView providing all the missing bits that the programmer must supply
(2) obsoleted
(3) it may be possible to add a cache layer to not use skip...
(4) I performed limitate testing and I don't know what happens when only some fields are changed
The difference is in how they handle the "cells".
Simplifying a bit, we may say that QTableView asks the program what and how to print each cell using a callback mechanism.
QTableWidget, instead, has to be loaded with data by the program and then handles everything itself.
This basic difference has quite big consequences.
QTableView is the basis of VIRTUALGRID and BROWSE (2), QTableWidget is the basis for GRID.
VIRTUALGRID handles both arrays and DBFs. For arrays, in the program you create the array, set grid to use it, and the grid will start to do the callbacks... how many rows ? which is the back/forecolor of cell at position 3,6 ? What text should I print at cell 2,1 ?
VIRTUALGRID answers all these queries in abstractGrid:onQuerydata(). For example the row count for arrays is quite easy:
(look in the source code, the forum program doesn't allow me to post the code....)
With VIRTUALGRID you work directly with the underlaying data. If you change a value in the array, the array is directly updated, the same for DBF fields. Of course, this is both good and bad. But for quick data entry it may be good.
As I said, QTableView asks the program for the data to display. For arrays it is quite simple, the grid rows matches the array row -1 (grid is 0-based, array is 1-based).
For DBFs with filters, index, ordscope, set deleted on the situation is a bit more complex. Infact if we can use with a simple dbGoto in case of none of the cited "filters" are set, it is a condition very rarely found in common use.
If we have index and optionally a ordscope, we may use ord* functions (not implemented now)
But if a filter is set, we must use "skip" to move between records.
Let's go with an example: we have to browse a DBF table with a controlling index on LastName. We have a VIRTUALGRID.
Qt QTableView asks for the number of rows in the data, and it gets back 200.
Then it starts to ask for the data for each row. Let's say there are 21 rows that can fit the screen, so it asks data for rows 0,1,2,3,4,5,6,7 up to 20. We move between records using skip n, with n calculated remembering the position we are and where we want to go.
Now click on first row: Qt asks again for data in row 0 (row 0 is a gotop()). Now row 0 is selected. Click on row 20. Qt asks for data for row 0 to draw the cells without the selection colors and then asks for data for row 20 to display it as selected. If we exit focus from the grid, row 20 is displayed with selected-disabled color, and data requested yet another time. (3)
As you may understand, everytime Qt needs to repaint the screen it asks the program the data... isn't it wonderful ?
Yes, it really is.
But in this DBF access we must consider SHARED dbf access. What happens if someone changed LastName of row 20 in another program instance and we click on row 20 ? If the change modified the order in the index of record 20, clicking on it would change what is shown on screen, since the skip would move to a different record!
But if I used a cache system to remember the recno() of row 20 and use dbGoto(), I may go to a record that is no more in the correct order, and since I may have some mixed cached and not cached records, it may become a mess.
QTableView in several occasions asks for a new record count, refreshes the rows shown on the screen asking for data, for example when it regains focus, when the grid is partially covered by other windows... at that moment the screen is refreshed and new rows and changed data are shown... (4)
and so we are at the crucial point: Qt needs info and ask for them, and it decides when to do... and it changes recno() pointer... it changes it several times... we may also try to reposition the pointer back at every request but it may be dangerous !
How can we trust the data in a shared DBF ? how can we be sure to not UPDATE the wrong record ?
Can Qt asks for data in the middle of an UPDATE ALL ? or a loop calculating some totals ???
(end of part 1.... is anybody interested in a part 2????)
(1) QTableWidget inherits from QTableView providing all the missing bits that the programmer must supply
(2) obsoleted
(3) it may be possible to add a cache layer to not use skip...
(4) I performed limitate testing and I don't know what happens when only some fields are changed