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 Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to distinguish in a grid by different grid-lines via their backcolor 4

Status
Not open for further replies.

german12

Programmer
Nov 12, 2001
563
DE
I have a grid on a form like this

Gridsample_x8ovya.jpg


the backcolor of the grid is yellow as you can see.
In the column Daysleft there are some negative values (which means the time has passed.
My question:
Is it possibel that for lines with negative values (they can differ in their number)- that the backcolor of that lines gets another backcolor than yellow - just to distinguish immediately, what had been in past, and what is still coming up?

Thanks
Klaus




Peace worldwide - it starts here...
 
Yes Klaus, you can.

In the properties of the column or columns you can set the DynamicBackColor.
I always do that with a function like "mycolor()" . Enter mycolor() in the DynamicBackColor property without the " ".

Then in the main prg make a procedure (or function) to determine this backcolor. Two or more different colors to return. You can make it as complicated as necessary.

Code:
PROCEDUE MYCOLOR
if AAAAAAA             && Example: if Daysleft < 0
    return rgb(x,y,z)  && your values
else
    return rgb(x,y,z)  && your values
endif

Or a more complicated example:

PROCEDUE MYCOLOR
Do case
   case XXXXXXX and AAAAAA   && 2 conditions must be true
     return rgb(x,y,z) && your values
   case XXXXXXX              && AAAAAA is false
     return rgb(x,y,z) && your values
   case YYYYYY
     return rgb(x,y,z) && your values
   case ZZZZZZZ
     return rgb(x,y,z) && your values
   otherwise
     return rgb(x,y,z) && 5th color
endcase

If you want to set all columns to the same function for the DynamicBackColor you can set this in the Grids Init event:
Code:
THIS.setall("Dynamicbackcolor", "mycolor()","Column")
 
Klaus,

JackTheC mentioned the DynamicBackColor property. This is definitely the way to go. In fact, it would be worth your time to study all the Dynamicxxxx properties as they open the door to a lot of useful formatting options for grids. (Note that these are properties of the Column object, not of the grid itself.)

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 

JackTheC

Thank you very much for your help.
At first I had difficulties to test your program, because I could not find the columns and their properties of the grid.

That was because the column-count in the grid had been set to -1 here.
In this case only a grid is shown, but not other child-objects.
I still have to learn a lot, but it is real fun when something finally works.
Now it is good to see immediately what event has gone (turquoise), and what is still coming soon (yellow)

grid_with_to_colors_de8phm.jpg
grid_with_to_colors_de8phm.jpg


Klaus

Peace worldwide - it starts here...
 
Mike
- thank you also ...for pointing out to me the other dynamic properties of a grid.
I'll deal (or play) with that more.

JackC and Mike
This night I tried to "expand" the code for the main.prg

Code said:
*Program main.prg
*Changing properties in a grid.

DO FORM ereignisse
DO mycolor


PROCEDURE Mycolor
IF daysleft < 0
dynamicfontbold = .t. *I added this line
RETURN RGB(125,255,255)
*blue
ELSE
dynamicfontbold = .f. * I added this line
RETURN RGB(255,255,0)
*yellow
endif
ENDPRO
I wanted to have additionally fontbold = .t. in that column, however
there is no effect.
The RGB change remains to work well.

Where is my fault?


Klaus





Peace worldwide - it starts here...
 
Hi Klaus,

You have to add a procedure yam may want to call MyFontBold() (see code below)

Code:
*!*	grid_calculatedcolumn.prg
PUBLIC goForm

goForm = NEWOBJECT("form1")
goForm.Show
Read Events

Close all
Clear All

RETURN


**************************************************
DEFINE CLASS form1 AS form
	AutoCenter = .T.
	Caption = "Grid with running total"
	Width = 522
	MinHeight = This.Height
	MinWidth = This.Width
	MaxWidth = This.Width
 
	ADD OBJECT grid1 AS grid WITH ;
		ColumnCount = -1, ;
		Left = 12, ;
		Top = 36, ;
		Width = ThisForm.Width - 24, ;
		Height = ThisForm.Height - 72, ;
		RecordSource = "curTemp", ;
		Anchor = 15
 
		PROCEDURE grid1.Init
		
[highlight #FCE94F]                        This.SetAll("Dynamicbackcolor", "ThisForm.myColor()","Column")
			This.SetAll("DynamicFontBold", "ThisForm.myFontBold()","Column")
[/highlight]
			WITH This.Column1
				.Width = 90
				.Header1.Caption = "Name"
			ENDWITH

			WITH This.Column2
				.Width = 90
				.Header1.Caption = "Street"
			ENDWITH

			WITH This.Column3
				.Width = 90
				.Header1.Caption = "Area Code"
			ENDWITH			
			
			WITH This.Column4
				.Width = 90
				.Header1.Caption = "Town"
			ENDWITH			
			
			WITH This.Column5
				.Width = 90
				.Header1.Caption = "Phone"
			ENDWITH
		 ENDPROC 

	ADD OBJECT cmdPrint AS CommandButton WITH ;
		Left = 12, Top = 6, Height = 24, Caption = "Print Report"
		
		PROCEDURE cmdPrint.Click()
			SELECT * FROM curTemp ORDER BY 1 INTO CURSOR curPrint
			MODIFY REPORT rptNames
			REPORT FORM rptNames NOCONSOLE PREVIEW 
		
		ENDPROC

PROCEDURE Mycolor()
	IF UPPER(cTown) = "BASEL" OR UPPER(cTown) = "BERLIN"
	
		RETURN RGB(125,255,255)

	ELSE
		RETURN RGB(255,255,0)

	ENDIF 
ENDPRO

[highlight #73D216]PROCEDURE MyFontBold()
	IF UPPER(cTown) = "BASEL" OR UPPER(cTown) = "BERLIN"
	
		RETURN .T.

	ELSE
		RETURN .F.

	ENDIF 
ENDPRO[/highlight]

PROCEDURE Destroy
	Thisform.Release()
	CLOSE ALL
	Clear Events
ENDPROC

PROCEDURE Load
	CREATE CURSOR curTemp (cName C(20), cStreet C(29), iAereaCode I , cTown C(20), cPhone C(10))
	
	INSERT INTO curTemp VALUES ("Allan", "Hoogen", 23452, "Amsterdam", "2532-56325")
	INSERT INTO curTemp VALUES ("Kim", "Hoogard", 23452, "Rotterdam", "2532-56325")
	INSERT INTO curTemp VALUES ("Jane", "Hoovenmod", 23452, "Brussles", "2532-56325")
	INSERT INTO curTemp VALUES ("Chris", "Hieveport", 23452, "Berlin", "2532-56325")
	INSERT INTO curTemp VALUES ("Mark", "Hagen", 23452, "Zürich", "2532-56325")
	INSERT INTO curTemp VALUES ("Mike", "Drben", 23452, "Basel", "2532-56325")
	INSERT INTO curTemp VALUES ("Amanda", "Ogenogen", 23452, "Paris", "2532-56325")
	
	LOCATE 
	
ENDPROC

ENDDEFINE
*********************************************

hrh MarK
 
Klaus, try to write a separate procedure "MyFontBold" similar to PROCEDURE Mycolor, but RETURN .T. or RETURN .F. instead of "RETURN RGB(...)".

Then add to the grid's init event: THIS.setall("DynamicFontBold", "myFontBold()","Column")

 
Mark & ManniB
Bingo
Both of your help were successful as you can see on the screenshot below.

It is obviously a mistake if 2 different properties are addressed at the same time in a procedure.
(Program maintenance is also easier with separate procedures).
I keep learning new things here.
I am very thankful for that

Regards
Klaus

grid_with_to_colors_ufpoz5.jpg
grid_with_to_colors_ufpoz5.jpg


Peace worldwide - it starts here...
 
Mark, what means "yarn" in your sentence below?
The translation of "yarn" into German is "garn" and this is material for sewing....


Mark: You have to add a procedure [b said:
yam[/b] may want to call MyFontBold() (see code below)]

Peace worldwide - it starts here...
 
Hi Klaus

It is just a typo it should read

You have to add a procedure [highlight #73D216]you[/highlight] may want to call MyFontBold() (see code below)


hth

MarK
 
Thanks Mark -
I had first thought of an English abbreviation.
There are sometimes difficulties because they often do not appear in the dictionary.
e.g. your "hth" - but I think it is "hope that helps".
(or " humor totally heartbreaking"?)

Klaus







Peace worldwide - it starts here...
 
Hi Klaus and Mark,

so, clearly, HTH means heavy transport helicopter.

Klaus, remember I suggested you compute daysleft from startdate and DATE() in an older thread? In the same manner, you could also make the row color a computed field and set it to one color for negative values (past events), the other color for positive values (future events) and maybe also a special color for todays events.

This would make DynamicBackColor the simplest expression it can be, just that color field name. And it would allow changing color independently from the first computation, too. Or you just create an integer field in the query of the data with CAST(0 as I) as color and then populate that. That would help if the computation is more complex than it's for checking daysleft being negative or positive.

In your simple case it could be done like this as a two staged query, even if the eventstable only has the startdate:
Code:
Select startdate, daysleft, ICase(eventdata.daysleft<0,Rgb(255,0,0),eventdata.daysleft>0,Rgb(0,255,0),RGB(255,255,0)) as eventstatuscolor from ;
(Select startdate-Date() as daysleft,* from eventstable) eventdata into cursor eventgridcursor

Chriss
 
Hi Chris,

Interesting approach. But why would you take this detour (creating an additional cursor, deleting the EventStatusColor column) since in any case you have to set DynamicBackColor?

See Code below

Code:
*!*	grid_dynamicbackcolor
PUBLIC oform1

oform1=NEWOBJECT("form1")
oform1.Show
Read Events

Close all
Clear All

RETURN


**************************************************
DEFINE CLASS form1 AS form
	AutoCenter = .T.
	Caption = "Grid with dynamic backcolor"
	Width = 450
	MinHeight = This.Height
	MinWidth = This.Width
 
	ADD OBJECT grid1 AS grid WITH ;
		ColumnCount = -1, ;
		Left = 12, ;
		Top = 42, ;
		Width = ThisForm.Width - 24, ;
		Height = ThisForm.Height - 54, ;
		RecordSource = "csrEvents", ;
		Anchor = 15
		
		PROCEDURE Grid1.Init()
			This.SetAll("DynamicBackColor", "EventStatusColor", "Column")
			This.DeleteColumn(3)
			
		ENDPROC 
			
 
PROCEDURE Destroy
	Thisform.Release()
	CLOSE ALL
	Clear Events
ENDPROC

PROCEDURE Load
	LOCAL i

	CREATE CURSOR csrTemp (dDateStart d )

	FOR i = 1 TO 50
		INSERT INTO csrTemp VALUES ( DATE() + 5 - INT((7.5 * RAND())))
	ENDFOR
	
	Select dDateStart, csrEventData.iDaysLeft, ICase(csrEventData.iDaysLeft < 0,Rgb(255,0,0), csrEventData.iDaysLeft > 0, Rgb(0,255,0), RGB(255,255,0)) as eventstatuscolor ;
		from (Select dDateStart - DATE() as iDaysLeft, * from csrTemp ) csrEventData into cursor csrEvents 

	LOCATE 
ENDPROC

ENDDEFINE
*********************************************

MarK
 
I was mainly demonstrating the color calculation, you can add as many columns to the cursor as you want from the events dbf.

And about creating a cursor: I explained why you would never store a computed value in a table and the norm of normalized data in an older thread of Klaus (quite recent, anyway, see my last 2 posts in thread184-1821686). And with that principle, almost all displays of data will be by cursors as you usually need to join normalized data anyway, and in that step make the computations.

I see people disregard this best practice exactly for the reasons your question points out. Why not use a DBF for grid display and do anything needed so you don't need to query data and have less code? Well, it's a bad compromise in my eye, as it just invites errors in the data. And yes, this or more generally speaking 3 tier design of an application means you rarely will ever just design a table as you want to display it, as I said there, that's also a reason views are called views, to store the queries needed to get to data for viewing. The best part of that is that a normalized database of a shop system, for example, allows having views combining all data of an order for one view of forms like the shopping cart for the customer or the order items for order fulfillment and shipping, but also views looking on the data from the products as their main table, counting orders of a product, allowing enterprise resource planning, in very short.

You still need to set dynamicbackcolor, yes. But that's no disadvantage, is it? Why should you not have to set dynamicbackcolor to make that a plausible solution? With a field for the color you don't call code for that that's also repeatedly called every time the grid scrolls. You just specify a field of the workarea the grid displays and accesses anyway. It's a norm, Mark, and I just want to point it out at least, even if in general it means more work in terms of queries. As it looks like no advantage to moving the code into a query instead of a grid or form method to color the grid, people will always tend to not do it, but that leads to all that bad database design out there, that finally makes things less maintainable. Refusing any data redundancy that invites data discrepancies is even taken as a trivial offense and also argued for performance reasons.

Chriss
 
Also, an interesting approach:

Code:
This.DeleteColumn(3)
I also said earlier I would always design grids visually in the form designer, maybe using the approach to drag&drop from data environment or with a builder assigning columns.

When relying on the automatic creation of columns you also have other disadvantages with any table, even with the simpler approach to just USE a table or put it in the data environment and display that in a grid. You also need to remove the column of the ID of the table as that's not data you want to display to the user, usually.

Visual design makes it eas to have the columns you want already at design time and removes the need to programmatically correct generated columns, as you always use the "handcrafted" grid. And the drag&drop option does make that simple, not a tedious handcrafting task. Manually and visually changing column widths etc. makes it easy to have the ideal grid design.

Klaus already asked about the grid not so long ago and to use it for any query. With the automatically created columns you always live with the field names as captions. The drag&drop takes in the captions you could define in the table designer (for DBC tables only). Did you know this can even be an expression?



Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top