Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to color row grid in alternate shade? 5

Status
Not open for further replies.

Mandy_crw

Programmer
Jul 23, 2020
578
0
16
PH
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)
POS_aatd9w.png
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...
 
Chris, you're right, of course, about SET DELETED ON. But the point is that Mandy is using RECNO() to control the shading of alternating rows, and that method only works if there are no deleted records (regardless of the setting of SET DELETED).

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Well, or using an extra field, Mike, as you suggested yourself and as my demo shows, too. I find it a little bit more disturbing to zap an alias and fill it with all minus one record that was in it before, than having an extra field you set for the alternating of the colors.

Chriss
 
Hi,

May I add my comments.
[ul]
[li]Why would you take this detour by filtering the data, ZAPping the underlying table and append the filtered data back to that table? What happens to the lost data? Isn't it more straightforward to filter the data into a cursor and use this cursor as RECORDSOURCE for the grid, since it is in natural order?[/li]
[/ul]
[ul]
[li]DYNAMICBACKCOLOR is a property of the column and not the grid - hence if you use SETALL at the grid level you have to add the COLUMN parameter[/li]
[/ul]
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))","[highlight #73D216]Column[/highlight]")

Finally please consider the warning about the ZAP command from the Hacker's Guide

ZAP

This may be the single most dangerous command in all of FoxPro, but it's incredibly handy when you're working interactively. ZAP permanently removes all records from a table. The name supposedly stands for "Zero And Pack." ZAPped records cannot be recalled.

Usage

ZAP [ IN cAlias | nWorkArea ]

Although you can ZAP in a work area other than the current one, we really don't recommend it. Using this command by itself is like striking matches; using it in another work area is like striking matches in a gas station.

ZAP is not a good database citizen. It doesn't call the Delete trigger for a table in a database. Instead, it neatly avoids all the work you've done to make sure the integrity of your database is maintained. This is a major flaw.

Due to the above and for lots of other reasons, never use ZAP in a program. It's just too risky. See PACK for suggestions on alternatives. Actually, the one case where ZAP is acceptable is when you're working on a temporary file in the first place, so no permanent data is at risk. In particular, it's a great way to re-create a cursor without losing the grid that's based on it. Simply ZAP and APPEND FROM your data instead of doing a SELECT.

So why do we think it's incredibly handy? When you're manipulating data manually—perhaps parsing older data to create a normalized database—it's clean and simple to ZAP the target table between tests. Outside this kind of situation, we strongly recommend you avoid ZAP.

hth

MarK
 
Mark,

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
 
I wonder if I once told you about using ZAP in grid cursors. They are part of a technique called "safe select".

Maybe you got it from 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:
*** Create the working cursor
SELECT * FROM account WHERE 0 = 1 INTO CURSOR curacct READWRITE
2. Whenever other data should be listed, query that into cursor junk, ZAP in curacct and APPEND FROM DBF('junk').

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
 
Hi Mike

... 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. ...

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.

With Mandy's solution, the cursor (or table) stays in existence throughout the process, so the problem does not arise.

Maybe, but the question remains: what about the lost data while filtering and then ZAPping the table?

MarK



 
Hi everyone... Thank you all for your discussions... it made me aware of a lot of things... i dont know guys but i have used DELETE and SET DELETED ON, but it gave me some problems... in my table even if i delete the item, when i add the same itemcode that has been deleted for edit, it shows two record with the same idnum, so what i tried to do is after deleting i issue PACK command... so i no longer use delete...

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...


 
Hi Mandy,

... in my table even if i delete the item, when i add the same itemcode that has been deleted for edit, it shows two record with the same idnum, so what i tried to do is after deleting i issue PACK command

This topic has already been discussed in thread184-1825134. Did you follow the advice given there?

hth

MarK
 
Mark said:
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.

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
 
Hi Mike,

It's more to do with the grid losing track of the columns to which the data is bound.

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
 
Mandy_crw said:
when i add the same itemcode that has been deleted for edit, it shows two record with the same idnum
That shouldn't happen. What is your code, have you used APPEND or INSERT and RECALL both? You could reactivate a deleted record with recall, replace the qty and have it back. Or you can disregard the deleted record and insert it again. Unless you created a primary key indexx or candidate inde, that doesn't allow duplicates.

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:
Set Deleted On
Create Cursor crsItems (Id I Autoinc, cItemName c(20) Default "item "+Transform(Id), lAlternate L)
Insert Into crsItems (cItemName) Values ('some item')
Delete
Insert Into crsItems (cItemName) Values ('some item')
Delete
Insert Into crsItems (cItemName) Values ('some item')
? reccount()
Browse

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
 
Hi Chriss… that was so comprehensive…! Im really learning with all of you… i appreciate so much… ill try to study my code and apply some refinement… thank you so much Chriss… God bless…
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top