×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

How to change caption color only for active page of a pageframe?

How to change caption color only for active page of a pageframe?

How to change caption color only for active page of a pageframe?

(OP)
Dear friends,
I want to change caption color of active page of a pageframe to blue and turn rest of the pages' captions to black.
I tried the following code in activate event of each page. It's working.
But rather than putting the code in each page's activate event, is there any centralized event that can be used for this purpose?
I tried ChatGPT. It suggested Pageframe1.PageChange event. But such an event/method is not there.

CODE -->

this.FontBold = .t. 
this.ForeColor = RGB(0,0,255)
FOR EACH pg IN this.Parent.Pages 
	IF pg.name#this.Name 
		pg.FontBold = .f. 
		pg.ForeColor = RGB(0,0,0)
	ENDIF
NEXT pg 	
this.Refresh 

RE: How to change caption color only for active page of a pageframe?

Put it in the PF's Refresh() method.

RE: How to change caption color only for active page of a pageframe?


Hi,

If you have not own pageframe class, create it.


DEFINE CLASS _pageframe AS pageframe

	Name = "_pageframe"

	*-- backup page fore color array
	DIMENSION _forecolor[1]


	*-- Convert Page Index to PageOrder
	PROCEDURE cotoro
		LPARAM liCOrder
		RETURN This.Pages(liCOrder).PageOrder
	ENDPROC


	*-- Convert PageOrder  to Page Index
	PROCEDURE rotoco
		LPARAM liPO 
		FOR liCO=1 TO This.PageCount  
		    IF This.Pages(liCO).PageOrder=liPO
		       RETURN liCO 
		    ENDIF        
		NEXT
		RETURN 0
	ENDPROC



	*-- Save pages' fore color
	PROCEDURE savepagescolor
		LOCAL lii
		DIME This._ForeColor(This.PageCount,4)
		FOR lii=1 TO This.PageCount 
		    WITH This.Pages(lii)
		    This._ForeColor(lii,1)=.ForeColor
		    This._ForeColor(lii,2)=.FontBold
		    This._ForeColor(lii,3)=.FontItalic
		    This._ForeColor(lii,4)=.FontUnderLine
		    ENDWITH
		NEXT
	ENDPROC

        *-- Set Active Page's fore color
	PROCEDURE setactivecolor
		LPARAM liPage
		WITH This.Pages(liPage)
		.ForeColor=RGB(0,0,255) && Application.PAGE_FC
		*.FontBold=Application.PAGE_FB=1
		*.FontItalic=Application.PAGE_FI=1
		*.FontUnderline=B_System.PAGE_FU=1
		ENDWITH
	ENDPROC


        * restore page's fore color
	PROCEDURE restorecolor
		LPARAM liPage
		WITH This.Pages(liPage)
		.ForeColor=This._ForeColor(liPage,1)
		.FontBold=This._ForeColor(liPage,2)
		.FontItalic=This._ForeColor(liPage,3)
		.FontUnderLine=This._ForeColor(liPage,4)
		ENDWITH
	ENDPROC


	PROCEDURE Click
		FOR lii=1 TO This.PageCount 
		    WITH This.Pages(lii)
		    .ForeColor=This._ForeColor(lii,1)
		    .FontBold=This._ForeColor(lii,2)
		    .FontItalic=This._ForeColor(lii,3)
		    .FontUnderLine=This._ForeColor(lii,4)
		    ENDWITH
		NEXT
		This.SetActiveColor(This.RoToCo(This.ActivePage))
	ENDPROC



	PROCEDURE Init
		IF This.PageCount>0
		   This.SavePagesColor()
		   This.SetActiveColor(This.RoToCo(1))
		ENDIF
	ENDPROC

ENDDEFINE
 

mJindrova

RE: How to change caption color only for active page of a pageframe?

Tore's idea is not bad, but doesn't work as Refresh() isn't an event happening. So you'd still need a call to This.Refresh() in every pages Activate event.

Using Eventtracking I see everytime you change pages there is one common event firing: the form.paint().
So you could do that in the Form.Paint event

CODE

With Thisform.pageframe1
   .SetAll("FontBold",.F.,"Page")
   .SetAll("ForeColor",Rgb(0,0,0),"Page")
   .Pages(.ActivePage).FontBold = .T. 
   .Pages(.ActivePage).ForeColor = RGB(0,0,255)
EndWith 

It's not great to handle something that only concerns one control on the much more general level of the form. So the idea of Tore could also be taken without even needing a call to This.Refresh, when you'd instead use Bindevent and bind the pages Activate() to the pageframe Refresh(), making it a pseudo event.

As I now see mJindrova's solution, I'm reminded when pageorders are changed, .Pages(.Activepage) could give the wrong page. You don't get directly to the activepage object without trickery with OBJTOCLIENT, so iterate all pagees to find the one with the right pageorder:

CODE

With Thisform.pageframe1
   .SetAll("FontBold",.F.,"Page")
   .SetAll("ForeColor",Rgb(0,0,0),"Page")
   
   For Each pg in .Pages
       If pg.Pageorder = .ActivePage
          pg.FontBold = .T. 
          pg.ForeColor = RGB(0,0,255)
       Endif
   EndFor
EndWith 
You could also extend the Pageframe class with a SelectedPage property storing the page object of the active page which you set by this For Each loop. When another page is activated the SelectPage would still be the previously selected page, that could be used to only reset that and not use Setall.

Chriss

RE: How to change caption color only for active page of a pageframe?

(OP)
Dear Tore Bleken,
Thank you.
Yes. PF.Refresh is centralized event.
But it is not invoked automatically when any page is activated.

RE: How to change caption color only for active page of a pageframe?

Have you considered creating an Assign method of the ActivePage property? That would be a central place to monitor page changes, with ActivePage containing the value of the page on which you are arriving.

Just a thought.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads

RE: How to change caption color only for active page of a pageframe?

Is it better to use MemberClass?

RE: How to change caption color only for active page of a pageframe?

xinjie,

it's clearly a solution to have a base class and thereby use the inheritance or simpler "write once, use many times" principle. But pages as memberclasses are a bit of a pain to use.
In an existing project with existing pageframes, when you first set the Memberclass you see this warning message:

What concretely hapens when you change the memberclass of a pageframe is all pages get deleted and replaced by new but empty pages of the pageclass you pick (well, or whatever you put into your pageclass).
So that makes it hardly practical to replace pages of existing pageframes in existing classes or forms of a project. And this also is true, if you'd switch from one memberclass to another.

At runtime you can set the memberclass and membeclasslibrary properties without them affecting existing pages, but that also means they stay whatever they are, the member propertis will only affect new members you create, for example by simply increasing the pagecount. That still doesn't make it easy to change from the usual page to a member pageclass.

If you plan it ahead of time for a new project, it can be very, just also plan ahead it is not simply modifying a property to change to another class, within the designer that triggers deletion and recreation of pages and all details you have in them are lost, all controls of pages, all code you put into them is not copied over into the empty new pageclass.

You could make it your default to not design pageframes at designtime, only add empty pageframes into forms. Give them a list of pageclasses they add one by one at initialization. Then edit/maintain the single pageclasses. It makes maintaining pages - let's say - different. You'd have the single page classes in one or more VCXes or PRGs and each page can be opened in parallel into the class designer (to surprise you with an advantage) to maintain them. This possible parallel editing is contrasted by not being able to navigate a pageframe of a form in design mode to have all your editing in the actual form or form class. It doesn't break encapsulation, as that's not about having all your code in one file, of course, but it becomes less practical when you want to use intellisense to address elements on other pages or on the form outside pageframes, you can still program a path like This.Parent.OtherPage.ControlX.property=value, but intellisense won't list you the controls of Otherpage as if it already was in the pageframe as a sibling page. So you do such programming "blindly". Well, in terms of encapsulation it is indeed bad style to reach outside of THIS, but making the pageframe the encapsulation scope, a page adressing another page is within this boundary, and that's taken away from you.

Anyway you do it in detail, it's not easy to fit memberclasses into already existing pageframes, so solving that page tab styling on the level of a pageframe class would be more practical than on the level of a base class for pages. No matter how nicely it would be to have a page base class that all further pages inherit from.

I can also understand the decision about that IDE step to delete all pages and recreate new ones. A pageclass can include controls and code, even if you would limit yourself to pageclasses that are empty and so could allow all the existing "furniture" of the old pages to move over. In the general case you could have overlap, the old page and the new member pageclass can have code in the same method, how do you merge that?

The different behavior of making a change to memberclass/memeberclasslibrary at design time and at runtime makes it a feature inconsistent to work with. On the other hand, if they'd use the runtime behavior at designtime, setting member classes would do nothing to the pages you already designed and I doubt many developers would then understand the meaning of them at all.

Chriss

RE: How to change caption color only for active page of a pageframe?

Hi, Chris

Thank you very much for your detailed discussion. And it's right.

I have an unproven idea that we should be able to programmatically change scx because it's DBF.

This should make it easier to replace the base class with a custom class if we have a "tool".

I will consider whether to make this tool after Chinese New Year. Normally, memberclass is already ready for me.

RE: How to change caption color only for active page of a pageframe?

Yes, I tested a bit and it seems to boil down to this: If you just add the memberclass and memberclasslibrary into the lines of the pagframe properties memo, that would be sufficient.

I think you wouldn't even need to change the page names from PageN to pageclassN. Names are names and only need to be unique, which they are already, they don't point out which class a page is, that's the job of the memberclass/memberclasslibrary only. Changing the page names as the IDE does would also require changing them and in the Methods memo of the pageframe and in all further records of page controls in their parent references to pages. So simply keep names and everything would be fine. The programmer would then perhaps need to add in DODEFAULT() calls into page methods to also run pageclass code, unless there is no page code that would override pageclass code anyway.

That pages have no extra record also is the fundamental flaw in the way a VCX or SCX stores pageframes: All pages of them must be the same memberclass. You can't change that with any tool. The only way to change that is designing a pageframe class that sets memberclass and memberclasslibrary to the class needed for each page before adding it, with all the pros and cons you'd need to deal with I already described.

Chriss

RE: How to change caption color only for active page of a pageframe?

Chriss,

Thank you very much for testing!

At least that validates my guess. This solves most problems with pages. As for using different page classes in a pageframe, at least we bought some more time to get the problem out of the way once and for all.

RE: How to change caption color only for active page of a pageframe?

Well, I didn't check out everything. I found out it's important how the order of the properties is in the properties memo, first the memberclasslibrary/memberclass have to be specified, then the pagecount. And the object names of the pages both in designer and at runtime will be pageclassname+number, so indeed you can't stick to Page1, Page2, etc. names, as I said before.

You need to cascade these name changes to all controls in pages and to the methods memo and compile the form. A tool for that will be helpful, it has more to do than just changing the properties memo.

I also found out its possible to use multiple page classes, just use the properties memo, as if it was a script setting the properties line by line

So this will work:

CODE

memberclass = "mypage"
pagecount=1
memberclss= "myotherpage"
pagecount=2
memberclass = "mypage"
pagecount=3 

You'll end up with page 1 being named mypage1, page 2 being named myotherpage1, page 3 being named mypage2. So the numbering will only increase, if you create multiple pages of the same pageclass, just as the numbering increases, if you put one after the other control on a page.

The caveat is you have to still have the property definition mypage1.name = 'mypage1', even though this is self referential. That's not introduced by memberclasses, that was always that way.

To set the caption that needs mypage1.caption = 'Page1', myotherpage1.caption='Page2', and mypage2.caption = 'Page3'. I haven't experimented in detail what happens if you get this all wrong, and remember to also cascade these changes into the methods memo, where the page names also have to match what's generated. One more thing to do as you change code in the methods memo is to compile the scx or vcx to get the objmemo to reflect that, that literally means COMPILE FORM or COMPILE CLASSLIB, not building the project.

If you do all this correctly you then can use multiple page classes. And on top of that the code already in the page is preserved and overrides the class code, just like it would be if the page originally had been that class, code you write into the pages at desig time inherits from the class and overrides it, if you write into the same methods you inherit, so the DODEFAULT() mechanism works for running both your code and the pageclass code.

Chriss

Edit: One more experience with this: If you change page names in the designer, because you'd like a simple naming of page1,2,3 again, you'll sabotage all this and VFP will remove all the details and remove the double definitions of memberlclass and only keep the higherst pagecount within the peroperties memo. So such usage of the properties memo is instable when then modified by the normal IDE designer, again.

Edit2: That last experience makes me think you should perhaps not support that multipageclass option, the step to enable a memberclass without needing to recreate the page contents is good enough for a first step.

RE: How to change caption color only for active page of a pageframe?

Going a step back to a pageframe solution, it's simple even to do for an already existing pageframe without redefining it.

You need this in the init:

CODE

BindEvent(thisform,'Paint',This,'Refresh') 

And this in the pageframe Refresh:

CODE

With This
   .SetAll("FontBold",.F.,"Page")
   .SetAll("ForeColor",Rgb(0,0,0),"Page")
   
   For Each pg in .Pages
       If pg.Pageorder = .ActivePage
          pg.FontBold = .T. 
          pg.ForeColor = RGB(0,0,255)
       Endif
   EndFor
EndWith 

Chriss

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login


Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close