How to color row grid in alternate shade?
How to color row grid in alternate shade?
(OP)
Hi everyone.... I am designing a POS system currently... everything is almost working, but i wanted the row to change shade evertime an item is added...(as shown in the picture)
Would everyone teach me please and show me an example code for me to study and probably adapt to my system? Thanks in adavnce and God bless...

RE: How to color row grid in alternate shade?
Please have a look at DYNAMICBACKCOLOR()
Furthermore, there are quite a few code examples in this forum dealing with this subject, e.g.
CODE -->
hth
MarK
RE: How to color row grid in alternate shade?
RE: How to color row grid in alternate shade?
As the others have indicated, the secret is to use the DynamicBackColor property. (Note that this is a property of the column, not of the grid.)
If the underlying table or cursor has no index in force, and if it does not contain any deleted records, and if there is no filter in force, then the code is easy:
CODE -->
Put that code in the grid's Init. That's all you need.
But if the above conditions don't apply (and especially if the cursor is indexed), then it is slightly more complicated. In that case, you won't be able to rely on RECNO() in the above code, so you will need to add a field to the cursor that serves in its place. It should be a numeric field, and you will need to populate it with consecutive integers. Having done that, the code will be similar to the following:
CODE
where MyTable.CounterField is the field in question.
In both the above examples, the RGB() values determine the actual colours shown. You can experiment with these to find the combination of colours that you like best.
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
RE: How to color row grid in alternate shade?
In that case, an easier solution might be to create a cursor specifically for populating the grid. Create the cursor like this: SELECT * FROM MyTable INTO CURSOR csrGrid - adding any ORDER BY or WHERE clause that is relevant. Then use the cursor as the RecordSource of the grid. And, finally, put this code in the grid's Init:
CODE
That should work even if the original table has an index set, or has deleted records, or a filter in force.
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
RE: How to color row grid in alternate shade?
you pointed out a concern I also would point out.
You can only alternately color a grid based on recno(), if records are in record number order, otherwise this will look chaotic and randomly colored. As coloring is based on odd/even record numbers. but in other sort orders like ordered by product type, for example, odd and even record nummbers don't necessarily alternate anymore in that order.
Mandy,
If I assume you have a cursor of items feeding the grid in the form and starting empty and you add items, they will stay in record number order and all the advice given will work out fine. But things can become out of alternate order, if you delete items. Let's look at an example. Say you have 3 items with record numbers 1-3, then deleting the second item the remaining records don't get renumbered, they keep their record number 1 and 3, both odd and both have the same color. If you delete the last record and the remaining 1 and 2 are still alternating in even/oddness and so also in their color, that's fine at first, but when you add the 4th item it will mean recno 4 follows recno 2 and has the same color. So alternation of colors can easily break.
There are some ways to keep control, for example as Mike suggests: Using your own counterfield.
But I suggest a very simple neat trick that doesn't require working with dynamicbackcolor. Put an image control on top of the grid in grid size with alternating colors that allow the grid rows to show through by using transparency. Say you use a mid to dark blue but with 80%-90% transparency and a 100% transparent stripe the grid then can be kept at its default white color and you generate the light blue by the transparency.
There's a big bonus to this approach, too: It'll color the rows no matter if it starts with no items or not. The only thing that should be prevented is scrolling pixelwise, you should never show the grid scrollbars but add buttons that scroll the items b full rows only. That's the only thing that makes this approach a bit more complicated than using dynamicbackcolor. But it's easy enough, as you have the doscroll method of the grid.
Do you use the gdiplusx library for anything in your application, Mandy? Then this could also be used to generate such a PNG image file on the fly and with the dimensions necessary to fit the grids rowheight and number of rows visible. It's worth doing, as it unbinds you about any headaches about the row numbering. You just have to react to resizing of the grid and the rowheight, though. But that may not be enabled aside from adapting to screen size once at start of the POS system. That only points out that it would be best to create such a PNG with the help of the gdiplusx library whenever you know the dimensions of the grid and its rowheight.
Here's GDIPlusX:
https://github.com/VFPX/GDIPlusX
Chriss
RE: How to color row grid in alternate shade?
1. start gdiplusx by doing System.app, usually somewhere early in main.prg, for example:
CODE
2. code to create a png with 12 rows, each 24 pixels height in white (100% transparency) and blue (75% transparency):
CODE
Here's that PNG:
Chriss
RE: How to color row grid in alternate shade?
Thank you mjcmkrsr, Tore Bleken, Chris Miller... and Mike....
I really appreciate all your answers... and at the same time... i am learning... as i always do when you give answers... Ive gotten what Mike gave... my grid looks good and well pleasing to the eyes... Thanks again everyone.. God bless....
RE: How to color row grid in alternate shade?
fine. Just watch out what it looks like when you delete an item from the list and then add a new one. As said, the coloring based on recno() can easily break and become non-alternating. Mikes recommendation of using an extra field MyTable.CounterField could solve that, if you renumber it every time the number of items change, just loop all items and sequentially number them. It would also work to alternate between the values 1 and 2 or 0 and 1. Or you make that a logical field, say LogicalField, alternating between .T. and .F. like this routine does:
CODE
And change the dynamicbackcolor expression to
CODE
Chriss
RE: How to color row grid in alternate shade?
RE: How to color row grid in alternate shade?
RE: How to color row grid in alternate shade?
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
RE: How to color row grid in alternate shade?
Likely not my idea of using an image to color the grid rows. I can understand it's a bit overwhelming if you never used gdiplusx and also I just showed how to create the image file and only sketched how to use it in front of the grid. There are things you need to take into account like the offset of headers and recordmark and deletemark of the grid to position the image.
Here's an example derived from Marks using an Items cursor and the more usual dynamiccolor approach.
Remove the call to Thisform.AlternateColoring() in the PROCEDURE cmdDeleteItem.Click() code and you'll see how the alternate coloring breaks, if you don't refresh the lAlternate field of the items cursor.
CODE
Also notice, how the grid is all white without any items and is always white in rows with no data, which is because coloring is only applied to rows with data, there is no dynamicbackcolor commputed for rows without data, not only because the IIF expression depends on a field, empty rows are always drawn with default backcolor and only gridlines.
The advantage of dynamicbackcolor is, that this coloring obviously scrolls with the data, whereas an image in front of the grid stays in position and that's getting obvious when you scroll - only the data scrolls, not the coloring.
It's a matter of taste what you want to have, using empty records to populate all grid rows with colors can be a solution to that, but has its con, too, as scrolling up still makes the lower portion of the grid white.
Chriss
RE: How to color row grid in alternate shade?
Chriss… this is another approach… i will atudy it… thanks to you… as always…
RE: How to color row grid in alternate shade?
this is just a full example of the idea I suggested to use a logical field and a routine to refresh that whenever a record is added or removed, as otherwise, you risk breaking the alternate coloring.
There are some corner cases where deleting doesn't break the alternate coloring, if you delete the last or first item. And there's the even simpler corner case you always only add records and never delete them. Then just the new record needs the new logical opposite than the last or the next number in a numbering sequence as Mike suggested. But in the general case you simply at best repopulate the field that's responsible for the alternating colors, that's the easiest way to never let it break the look.
I asked you to test the case of deleting an item. Did you test that? Because unless it's just the last item you delete one row of a color between two rows of the same color and that means after the row is removed two rows with the same color remain. I thank you for always being thankful for all we post, but you rarely really react and give feedback to questions and recommendations, that's missing and I fear you only end up with something that somwhat works, but hasn't all the details necessary.
And in a POS system, if the item list is populated by scanning barcodes, the deletion of an item is a rarely used scenario, but you'll regret, if that happens and the alternating color look breaks. So in general, think about corner cases in your design and test whether they break even just the design you have in mind, not only by showing up errors. Otherwise you can live with that, it just will have quirks. In the long run, such things lead to the rejection of a system, if people find better designed systems. And POS and VFP is not a rare combination, others already did POS systems with VFP, too, so you have a big competition and a lot of contenders to replace your system, not only just the VFP based systems.
Chriss
RE: How to color row grid in alternate shade?
https://youtu.be/RGmrxxQNiDo?si=CWnzIjDYqte-DzJk
Spoiler:
RE: How to color row grid in alternate shade?
please don't post the same message multiple times.
RE: How to color row grid in alternate shade?
SELECT * from BINILI WHERE qty => 1 INTO CURSOR junk
SELECT BINILI
ZAP
APPEND FROM DBF("junk")
USE IN SELECT("junk")
thisform.Grid1.SetAll("DynamicBackColor", ;
"IIF(MOD(RECNO('Binili'), 2) = 0, ;
RGB(255, 255, 255), RGB(255, 255, 160))")
Thisform.grid1.refresh
this.Value = ""
thisform.text2.Value = 1
UNLOCK IN binili
RETURN 0
Thanks Chriss... God bless...
RE: How to color row grid in alternate shade?
The code you posted more or less matches what I had in mind. I'm pleased to see it was helpful.
Just one very minor point. Your code includes UNLOCK IN binili. Strictly speaking, that's unnecessary, because BINILI is, by necessity, opened exclusively. If it wasn't, you wouldn't be able to do the ZAP. This makes no difference to how your code works, but I thought I would point it out as it suggests a possible misunderstanding on your part.
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
RE: How to color row grid in alternate shade?
CODE
This part of your code ensures that you remove items from BINILI, if their qty was lowered to 0. The normal way to delete one record is just using the DELETE command.
I don't mind, it actually helps the coloring by recno to be stable and not break, so you "accidentally" have a solution that is stable for coloring. But lets think about extreme cases, if you work on data in a large table this way and remove items with qty<=0 by a Select of all items with qty=>1 and then a zap and append, you do a lot of moving data around, that could simply stay were it is.
Is it that you don't know how to suppress the display of deleted records? You simply SET DELETED ON. And then a delete makes a record invisible.
Chriss
RE: How to color row grid in alternate shade?
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
RE: How to color row grid in alternate shade?
Chriss
RE: How to color row grid in alternate shade?
May I add my comments.
CODE -->
SELECT * from BINILI WHERE qty => 1 INTO CURSOR csrBinili thisform.Grid1.SetAll("DynamicBackColor", "IIF(MOD(RECNO('csrBinili'), 2) = 0, RGB(255, 255, 255), RGB(255, 255, 160))","Column")
Finally please consider the warning about the ZAP command from the Hacker's Guide
hth
MarK
RE: How to color row grid in alternate shade?
The reason for the "detour" is as follows:
If you set the RecordSource to a specific cursor, and then regenerate the cursor (typically by issuing a SELECT with a WHERE clause), VFP first destroys the existing cursor, then builds a new one. So, for a brief moment, the cursor does not exist. Because the columns within the grid are bound to the cursor, destroying the cursor will rob the grid of the controls. The result is an empty rectangle: a grid with no columns.
With Mandy's solution, the cursor (or table) stays in existence throughout the process, so the problem does not arise.
At least, that's always been the approach I've taken. There may well be a simpler way of achieving the goal.
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
RE: How to color row grid in alternate shade?
Maybe you got it from https://andykramek.blogspot.com/2020/04/using-safe..., where Andy Kramek coined the term, perhaps, he's also using the alias name "junk" for a temporry cursor. This technique is meant to use, if your grid recordsource is an SQL query. And you repeatedly need to requery with different parameters or where clause. You always just zap a grid cursor, never a DBF, for the safety reasons and concerns MarK points out from Tamar Granors Hacker's Guide.
You artificially make up the situation by using a query to fill your BINILI alias from itself. Well, that's pointing out you actually don't need this. The safe select situation is doing these steps:
1. Create a grid cursor, Andy Kramek showcases this as creation of such a cursor
CODE
The aim here is to show a list of accounts, and the UI allows users to filter for account in different ways, which could be done with further queries in the same structure, just with other where clauses than 0=1, which is in short meaning .f., so the initial curacct cursor is empty. Every future list has other filter criteria and always stems from the same type of query from all data in account.dbf, but doing this directly again INTO CURSOR curacct would cause the grid to lose its structure. So you select into a temporary junk cursor, zap the grid cursor and append the new result to scrap it afterwards. But also you depend on a query, as one list miight be all "meyer" accounts and the next all with a certain minimum amount in their depot. The lists change arbitrarily, the source of data always is account.dbf and the previous list is not needed anymore.
In your situation, you also start with an empty list. But you don't query different lists of products with varying where clauses, do you? You know every barcode scan or every pick of a user in an online shop to put something into the items list will add one single record to the already existing list, or up the qty by one. So in your situation you don't change from say select * from products where barcodde=x to select * from products where barcodde=y, you just add the one record of the barcode to your already existing list. And the easiest way to do this is start with an empty grid cursor you createe by a CREATE CURSOR statement and then insert into it and delete from it as you go, but you never reselect it, you don't even initially select data into it. Heere you don't even need an SQL query like I gave with where barcode=x, you can just SEEK x to go to the product with a certain barcode and then insert into curitems from fields of the product table.
This situation doesn't require safe select, it's over the top for this and it's nonsensical as you use the grid cursor as the source of the data for the grid cursor, you already have the grid cursor and all its data, you just need to either change qty, if it drops to 0 delete the record and if a record with the scanned barcode doesn't exist yet (the regular case, indeed) insert it. You always only have operations on one record, you don't ever pick a completely different list of source data. That's where you are safe by never needing to recreate the grid cursor, once it is created, it is only modified and stays the same file, the same dbf file or the same tmp file. See the section in Andy Krameks blogpost where he demonstrates the tmp file name of the cursor with the same alias name changes, which is the core reason the grid misbehaves and you need this technique. Where that's not the case you also don't need safe select.
Chriss
RE: How to color row grid in alternate shade?
True, but this hardly noticeable and you could even add LOCKSCREEN to hide/show the updating process. And I guess it will take less time than filtering the data, ZAPing the table and appending the filtered data again to the table - with all the hick-ups that could arise during these procedures. When running my code snippet (see above), the grid is regenerated in less than 0,00 seconds.
Maybe, but the question remains: what about the lost data while filtering and then ZAPping the table?
MarK
RE: How to color row grid in alternate shade?
Chriss, ill try the snippet that you have given and try using the DELETE and SET DELETED ON.... Thank you always...
Thank you mjcmkrsr and Mike as always...
RE: How to color row grid in alternate shade?
This topic has already been discussed in thread184-1825134: How to use UPDATE properly…?. Did you follow the advice given there?
hth
MarK
RE: How to color row grid in alternate shade?
Mark,
It's not a question of how long it takes, nor of the visual effect. It's more to do with the grid losing track of the columns to which the data is bound.
I appreciate that I have not explained it very well. I'll try to rig up an example which shows what I mean.
Mike
__________________________________
Mike Lewis (Edinburgh, Scotland)
Visual FoxPro articles, tips and downloads
RE: How to color row grid in alternate shade?
I fully understand. But it is a matter of choice: I prefer rearranging the columns of the grid to filtering/zapping/appending, which imho is quite error prone.
Using my code as an example : what would you change when applying your approach?
MarK
RE: How to color row grid in alternate shade?
For a cursor you use in a form for temporary data, the accumulating list of sales items, you don't need to define standards like a primary key in them, it's just temporary list and its even a matter of taste whether an item is listed with qty=2 or just appears twice, I experience that daily with my groceries, it just depends on the clerks taste how they scan the items. And so actually a primary key is just hindering very normal use cases like that. Primary keys are important and I point that out often, but for a temporary list it' not yet permanent data in your dataabase, that's happeniing wwhen the items are actually sold, surely then you save the list of items and make your log also of the money or credit card transaction,, keep inventory, etc. But before that I wouldn't even make a barcode field a cnadidate to forrce unniqueness.
Well, and generally here's just a short code example showing that inserting and deleting the same record even multiple times doesnt cause an problms, conflictss or double listed records. Just have SET DDELETD ON and that means VFP takes the deletion mark into account and doesn't show records marked for deletion.
CODE
You can insert (or append, doesn't matter) and then delete as many times as you like. The cursor temp file will also actually grow in reccount, but all deleted records are not shown. To see, that this same item is 3 times in the cursor, you can SET DELETED OFF and convince yourself of it. But no, you don't have a problem even in case something like a customer changing his mind for 10 times would happen. VFP would be more patient than the clerk, for sure.
You have to do something to get into trouble with reinserting the same record. By itself no table or cursor is sensitive to that, that has to be limited by indexes, insert trigger code or rules, anything that's a "watchdog" in one or the other sense. But then your sales items list is not your product list with a unique barcode and idnum for every record. Something that's just temporary in a form and only becomes data you want to persist in your database. Up to the point the clerk actually sells the items that's not necessary is it? So you might have introduced something like an index that rejects a double idnum. Why? It's not a dbf of your database and outside the realm of its normalized data schema.
Chriss
RE: How to color row grid in alternate shade?
RE: How to color row grid in alternate shade?
https://youtu.be/WQG7o4G677g?si=upXkK5K1dy-o1_5K