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

Set Grid Header Click Method 2

Status
Not open for further replies.

JRB-Bldr

Programmer
May 17, 2001
3,281
US
OK, I got the help I needed for my previous questions, now the next one.

I am dynamically building the Grid in the Init Method of my Form. I am using the SELECT table and AFIELDS() to get its field count and field names.

I am using the field count and field names to dynamically set the Grid.Column.Count and then with a FOR ENDFOR loop I am setting up each Column.

SELECT MyTable
=AFIELDS(aryFlds)
mnFldCnt = ALEN(aryFlds,1)

ThisForm.Grid.ColumnCount = mnFldCnt

FOR i = 1 TO mnFldCnt
mcFldName = aryFlds(i,1)

* --- Set Column Control Source ---
mcControlSource = ALIAS() + "." + mcFldName
mcObject = "ThisForm.Grid.Column" + ALLTRIM(STR(i)) + ".ControlSource"
&mcObject = mcControlSource

* --- Set Column Header Properties ---
mcObjBase = "ThisForm.Grid.Column" + ALLTRIM(STR(i)) + ".Header1."
mcObject = mcObjBase + "FontBold"
&mcObject = .T.
mcObject = mcObjBase + "Alignment"
&mcObject = 2
mcObject = mcObjBase + "Caption"
&mcObject = mcFldName
ENDFOR

Now I want to put code (the same code) into the HEADER's Click Method.

Into each Header Click Method I want to put code to call the Form's SetOrder method:
ThisForm.SetOrder

How do I programatically get this code into each one?

Thanks,
JRB-Bldr
 
Which version of VFP are you using? The easiest answer is drastically different depending on whether or not you're using VFP 8.


-BP (Barbara Peisch)
 
In that case, you'll have to define your own header class in a PRG. It would look something like this:
Code:
DEFINE CLASS MyHeaderClass as Header
   FUNCTION Click
      * Put your click code here
   ENDFUNC
ENDDEFINE
When you're dynamically building your grid, before you set the header properties, use &mcObjBase..RemoveObject("Header1") to remove the existing header (note the two dots between mcObjBase and RemoveObject) and &mcObjBase..AddObject("Header1","MyHeaderClass") to add your header class. (You'll need to change "MyHeaderClass" to whatever you've named your class.)


-BP (Barbara Peisch)
 
Barbara - Thanks for the reply.

As you can see in my top posting, the Grid already exists in a 'basic' form on the FORM. I am merely modifying it dynamically to represent the table chosen by the user. I am doing this within the FORM's INIT Method.

"define your own header class in a PRG"

Can this Class definition approach work if the basic Grid already exists on the FORM?

Can this Class definition be done within one of the FORM's methods instead of in a PRG?

Can this Class definintion be done in a PROCEDURE PRG?

Thanks,
JRB-Bldr
 
BPeisch -- and how would you do that in VFP8???

Thanks,
Jim Nelson
 
I attempted to put this into my Form INIT Method prior to my building the Grid but got an error

DEFINE CLASS GridDblClick as Header
FUNCTION DblClick
ThisForm.ReOrder
RETURN .T.
ENDDEFINE

SELECT Leads && <<--- Error Generated Here


Error Message: "Statement is not in a Procedure"

I then attempted to put this into my PROCEDURE PRG file as:

FUNCTION DefClass
DEFINE CLASS GridDblClick as Header
FUNCTION DblClick
ThisForm.ReOrder
RETURN .T.
ENDDEFINE
RETURN .T. && <<--- Error Generated Here


Error Message: "Statement is not in a Procedure"

Am I missing some syntax or what is the problem?

Thanks,
JRB-Bldr
 
jrbbldr,

Don't put DEFINE CLASS inside function/method. Just put it directly in you PROCEDURE.PRG
Code:
DEFINE CLASS GridDblClick as Header
   FUNCTION DblClick
      ThisForm.ReOrder
   ENDFUNC
ENDDEFINE

That should work

-- AirCon --
 
You can have a method of your form or grid called replaceheaders and then run something like code below (this is merely an example and you would need to modify it to suit your needs class name is 'MyNewHeader' and the prf file that the header class definition is in is 'MyPrg.prg'). I use code similar to this to set up my grids so I can make them during design time just like i want and then at runtime all of the headers get replaced with a special sorting header.

Code:
LOCAL liColIndex
WITH THIS && thisform.grid1
	* replace default column header with custom header class
	FOR liColIndex=1 TO .COLUMNCOUNT && loop through all grid columns
		WITH .COLUMNS(liColIndex)
			IF UPPER(.Header1.CLASS) == 'HEADER' && replace only columns that have default header class
				m.lcOldCaption = .Header1.CAPTION && store the caption properties to forward it to new header
				m.lnOldBackColor = .Header1.BACKCOLOR && store the caption properties to forward it to new header
				m.llOldwordwrap = .Header1.WORDWRAP && store the wordwrap boolean property
				m.lnAlignment = .Header1.ALIGNMENT && store the alignment property
				m.lnOldForeColor = .Header1.FORECOLOR
				.NEWOBJECT('Header2','MyNewHeader', "MyPrg.prg") && this will remove old header automatically
				.Header2.NAME = 'Header1'
				.Header1.CAPTION = m.lcOldCaption
				.Header1.BACKCOLOR = m.lnOldBackColor
				.Header1.WORDWRAP = m.llOldwordwrap
				.Header1.ALIGNMENT = m.lnAlignment
				.Header1.FORECOLOR = m.lnOldForeColor
			ENDIF
		ENDWITH
	ENDFOR
ENDWITH

boyd.gif

[sub]craig1442@mchsi.com[/sub][sup]
&quot;Whom computers would destroy, they must first drive mad.&quot; - Anon​
[/sup]
 
OK, now with AirCon's suggestion I can now get the code to no longer generate an error message.

But it is not working as expected.

I wanted to insert the code into the Header's DblClick Method (originally the Click Method, but I changed my mind).
I do not see where/how this Class Definition and the AddObject() get the code into where it is needed.

Now when I double click on the Header my SetOrder method 'bombs out' telling me that there is no Parent object defined for whatever it thinks "This" is within my This.Parent.ControlSource statement.

Thanks,
JRB-Bldr
 
jrbbldr,

Have you tried using the replace method that I proposed above? It will replace the headers on the grid with the new class you have created...you will have to modify it a bit since the names of stuff are different in what you are doing, but it will give you what you want. Just call the replaceheader method (or whatever you decide to call it) from within the Grid's init event and whenever you add columns after that since new headers get the VFP base header class. The dbl-click code gets there because the headers in the grid will now be your class and not the VFP base header class and you have written your code into the class.

boyd.gif

[sub]craig1442@mchsi.com[/sub][sup]
&quot;Whom computers would destroy, they must first drive mad.&quot; - Anon​
[/sup]
 
I think Craig's example should work for you. Perhaps this can makes you clearer.

I'm assuming your grid object is named "GRID", is that right ?
If so then put this code in your FORM INIT.

Code:
[COLOR=green]** Change PROCEDURE.PRG with
**    your Procedure name[/color]
Set procedure to PROCEDURE.PRG

FOR i = 1 TO mnFldCnt
  [COLOR=green]** aryFlds(i,1) is your array field[/color]
  mcFldName = aryFlds(i,1)

  With ThisForm.Grid.Columns[i]
   .RemoveObject('Header1')
   .AddObject('Header1', 'GridDblClick')
   .Header1.Caption = mcFldName
  EndWith
Next


-- AirCon --
 
Oops..sorry Craig. I didn't see your posted earlier :)

-- AirCon --
 
It seems like I have descended into what a friend of mine refers to as:
"Grid Inferno"
-- actually he words it more strongly, but for Forum Political Correctness I will tone it down.

I seem to have gone from limited/moderate understanding to total confusion.

OK, here is what I understand (and what I am totally mis-understanding)...

Note - I apologize in advance for the following ranting out of confusion/frustration.

A VFP7 (remember I am using VFP7 - not VFP8 as some other users side-tracked us) Header is a Class and, as such, it has pre-defined Properties and Events/Methods.
The Events/Methods of this pre-defined class contain no code, but rather a 'container' for developers to "hard code" insert their own code.

The above suggestions seem imply that I should get rid of my VFP7 Default Header Class for this Grid with .RemoveObject("Header1")
And then replace it with a new Header Class that I define myself with .AddObject("Header1","MyHeaderClass")

The new Header Class could be defined to contain my own Events/Methods with my own code to execute when the DblClick event was executed.

BUT where is it that my new DblClick Event that I am relying on for execution is defined or even referenced?

Perhaps it is obvious to others, but I cannot see where that Event is ever referenced in the examples of code provided.
If the user performs the physical action of Clicking or Double Clicking on the Grid Column's Header "cell" something should happen, but if I don't define it and/or differentiate it from another event, I don't see how it can.

My new code needs to execute on the DblClick Event.
If I never say something to the effect of "USE THIS CODE ON THE PHYSICAL ACTION OF DblClick" then how will it ever work. Something needs to 'tie' the code to a user's physical operation (e.g. clicking the mouse on the grid). The original VFP7 Header Class has a clearly identifiable Event, but I cannot see the same clearly identifiable thing in the suggestions around this new Class approach.

Also if I am creating a new Custom Header Class don't I need to define ALL of the properties of this new Header Class so that it will work right? How about ALL of the other 20 or 30 properites and events/methods? Hopefully I don't have to define each and every one of them also.

Help!

Thanks,
JRB-Bldr
 
JRB-bldr,

First of all I'm also using VFP7, so all the code/sample I posted is works for VFP7.

Perhaps it is obvious to others, but I cannot see where that Event is ever referenced in the examples of code provided

If I understand it correctly, when you create a class by code all the EVENT is define by FUNCTION. So DblClick event is inside the DEFINE CLASS.
Code:
DEFINE CLASS GridDblClick as Header
   FUNCTION DblClick  [COLOR=green]&& DblClick EVENT[/color]
      ThisForm.ReOrder
   ENDFUNC
ENDDEFINE

So all header events that you can see visually can be code inside the CLASS by using FUNCTION EventName

Hopefully I don't have to define each and every one of them also

No you don't have to as long as you want to leave the event run as default. But if you need to add code for the event than you need to define it. For example
Code:
DEFINE CLASS GridDblClick as Header
   FUNCTION Click  [COLOR=green]&& Click EVENT[/color]
      Wait 'Header Click event' window nowait
   ENDFUNC

   FUNCTION RightClick  [COLOR=green]&& RightClick EVENT[/color]
      Wait 'Header RightClick event' window nowait
   ENDFUNC

   FUNCTION DblClick  [COLOR=green]&& DblClick EVENT[/color]
      ThisForm.ReOrder
   ENDFUNC
ENDDEFINE

Sorry for my English, hope you can undestand what I say. :)
Regards

-- AirCon --
 
jrbbldr,

Just to add a bit to Aircon's excellent explanation. Notice in your class definition...

DEFINE CLASS GridDblClick as Header
FUNCTION DblClick
ThisForm.ReOrder
RETURN .T.
ENDDEFINE

...that you are defining your new class as a HEADER, this gives you all of the defaults of the base header class so you don't have to define all of the properties and events yourself, just the ones you want changed. The DblClick() function you are defining in it is because you want to put your own code in that event to run when the user double-clicks on the header in your grid(s).

boyd.gif

[sub]craig1442@mchsi.com[/sub][sup]
&quot;Whom computers would destroy, they must first drive mad.&quot; - Anon​
[/sup]
 
I created an example awhile back for someone else that needed the columns to resize when the user double-clicked on the headers...it is an example that you can run in VFP to see how it works replacing the headers and such in the grid...will show you some other things like how to define your own columns and such which you don't appear to need right now, but still maybe a running example will get rid of some of your confusion (hopefully it won't add to it).

Columns autofit
thread184-770613


boyd.gif

[sub]craig1442@mchsi.com[/sub][sup]
&quot;Whom computers would destroy, they must first drive mad.&quot; - Anon​
[/sup]
 
OK, a good night's sleep has diminished my frustration level and I was willing to learn from what you guys have been patiently trying to tell me.

By using the excellent advice provided, I now have the grid being built and it is including the code in the Header DblClick Method as intended.

HOWEVER, a few more 'challenges' are now being encountered.

Issue #1:
The code for my ThisForm.ReOrder is as follows:
mcAlias = ALIAS()
mcString = This.Parent.ControlSource
mcField = EVALUATE(mcString)
mcField = UPPER(mcField)
mcField = STRTRAN(mcField, mcAlias + ".", "")

mcSafety = SET('SAFETY')
SET SAFETY OFF
INDEX ON &mcField TAG key
GO TOP
SET SAFETY &mcSafety

ThisForm.Grid.Refresh


When I Double Click on the Header cell, causing this code to execute, I get an error message:
Parent is not an Object
and then 'cascading' error messages related to it.

If I Suspend the program and Activate Window Trace, I can see the object "This" and it is not named as expected - "Header1". Instead it's name is the over-all Form's name.

Issue #2:
I am setting a Filter on the ControlSource Table which the Grid displays.

I have used SET STEP ON to ensure that there are displayable records after the SET FILTER TO is executed.

However upon then issuing the RESUME the Grid does not show ANY records.

Any suggestions?

Thanks,
JRB-Bldr
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top