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

Assigning properties in ADD OBJECT clause

Status
Not open for further replies.

vfp4ever

Programmer
Oct 18, 2013
71
East Java
Hello,

I am not sure whether it is possible to intercept the assignment of a property in an ADD OBJECT clause within a class definition. As a matter of fact, the <Property>_ASSIGN method does not seem to be called at all. For instance, the BackColor_ASSIGN event is not triggered unless I make an explicit assignment in some class event (e.g. Init).

Code:
DEFINE CLASS MyPageClass AS Page
[indent]ADD OBJECT lblx AS MyLabelClass WITH BackColor = 0xD4D0C8[/indent]
ENDDEFINE

Is there a way to manipulate the value of BackColor using this syntax? I would like to be able to change BackColor values in case of a system theme/colour change (intercepting WM_SYSCOLORCHANGE).

Dario
 
Hi Dario,

First, forget about the Assign method. It is not relevant in this context. You use an assign method to intercept the assignment of a value to an existing property - not to manipulate the actual creation of the property.

The code that you have shown is syntactically correct. When you run a form containing a page based on your page class, it will contain a label whose BackColor is 0xD4D0C8. Is that you want?

If you want to be able to change the BackColor while the form is running (in response to some event), you just reference the property in the normal way, for example:

Code:
MyForm.MyPageFrame.MyPage.lblx.BackColor = .... whatever

Does that answer your question?

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thank you Mike,

forgive me if I did not explain clearly what I am trying to do.

When I assign a property such as BackColor in a derived class like MyPageClass, I set it to a system value named TApp.System.Colors[COLOR_BTNFACE], defined elsewhere as the result of Windows API GetSysColors( COLOR_BTNFACE - 1 ). (The -1 is because Windows defines are zero-based). If I change the Windows scheme on my computer (under Properties/Appearance), my application intercepts the WM_SYSCOLORCHANGE Windows message and I can update all TApp.System.Colors accordingly. Immediately afterwards I must update all BackColor properties of all objects in the application.

That would be easy if I created objects with .AddObject in the Init event of their containers, I might simply intercept the BackColor_ASSIGN event or call a dedicated routine to reassign the new values. But... with the ADD OBJECT clause I am not able to tell the object to update its BackColor value. I think I would need to intercept the "internal" assignment of the property triggered with the ADD OBJECT command, but unfortunately BackColor_ASSIGN only works with explicit assignments.

I am afraid this could be a major difference between the two ways of adding objects. Any idea or workaround?

Dario
 
I never would have guessed this diagnostic info from your initial post. Thanks for the background!

So you want a hard-coded color value to adjust based on Windows messages? Not gonna happen.

You might find success using BindEvent() binding to Windows events but then it's up to you to cascade the external change throughout your interface. (And you'll probably forever be plagued with visual artifacts.) Access/assign methods respond to access/assign events from a Foxpro program. Not Windows.
 
If you want your app to have theme colors, just do nothing at backcolors or other colors, forms will get theme colors.

In general you'll not be able to do what you plan to do, you'll need to do that on the level of the class you add, ie MyLabelClass would be a label class with a backcolor set to =GetSysColors( COLOR_BTNFACE - 1 ) at design time.

Bye, Olaf.

 
you'll need to do that on the level of the class you add, ie MyLabelClass would be a label class with a backcolor set to =GetSysColors( COLOR_BTNFACE - 1 ) at design time

Thanks Olaf,
I do that already. That's fine as long as system colours (e.g. Windows Standard, Brick, Desert, Eggplant, ...) do not change during the application run.
 
Well, that's your problem, yes.
Once a class is loaded in memory such default values are kept. Eg try a property you set via = DATETIME(), it'll have the datetime of the first instance.

See CLEAR CLASS, but it's not possible while instances run, so put that into init.

Bye, Olaf.
 
Thank you, Tamar

I have read your interesting article about BindEvent( ). I have followed a similar approach, intercepting the Windows WM_SYSCOLORCHANGE message first and calling an "UpdateThoseProperties( )" method in the base class of each control (MyLabelClass, MyTextBoxClass, ...) from either its Init event and the procedure responding to the system change.

Code:
FUNCTION Init( ) AS Boolean
	This.UpdateThoseProperties( )
	RETURN .T.
ENDFUNC

Code:
PROCEDURE ChangeSystemColorsAndFonts( toObject AS Object )
	IF PEMSTATUS( toObject, "Objects", 5 )
		LOCAL loObject AS Object
		FOR EACH loObject IN toObject.Objects
			IF PEMSTATUS( loObject, "UpdateThoseProperties", 5 )
				loObject.UpdateThoseProperties( )
			ENDIF

			ChangeSystemColorsAndFonts( loObject )
		ENDFOR
	ENDIF
ENDPROC

But now, how can I assign the correct value to a property (e.g. BackColor) in "UpdateThoseProperties( )"?

Code:
PROCEDURE UpdateThoseProperties( )
	WITH This
		.BackColor = ???
	ENDWITH
ENDPROC

as I may have to deal with one of the following assignments:

Code:
ADD OBJECT lblx AS MyLabelClass ;
	&& default TApp.System.Colors[COLOR_BTNFACE], must change
or
Code:
ADD OBJECT lbly AS MyLabelClass WITH BackColor = 0x800000 ;
	&& fixed custom colour, no change
or
Code:
ADD OBJECT lblz AS MyLabelClass WITH BackColor = TApp.System.Colors[COLOR_HOTLIGHT] ;
	&& system colour, must change


Dario
 
If you have some colors needing to change with themes and oter, needing to stay as application specific, then you have to manage that eg with meta data, a local property or a colormanger.

Actually there is a nice method you could use: object.ResetToDefault("property"), which would redo the expression stored in the class definition (not in the ADD OBJECT property clauses, those are not useful at all), but again this won't work nice with PRG classes, you should rather go the route of using VCX classes, they don't have that problem with ResetToDefault().

See thread184-1743330
myself said:
In VCX classes this works correctly, in classes defined in PRG code not.

Anyway, in VCX classes this also works only for the default assignment expressions you set in the properties, not in something you set via ADD OBJECTs sub clauses.
You're breaking your own neck here, if you want to enforce it, make use of visual classes and everything is easier in that respect.

Bye, Olaf.
 
OlafDoschke said:
... then you have to manage that eg with meta data, a local property or a colormanger.

Thanks, Olaf

That's absolutely true. I had tried with .ResetToDefault already but it does not re-evaluate (I wasn't aware of the bug and the difference between PRG code and VCX), so it is of no help. The only thing, as you say, is to add an extra property (initialized as 0 in the class definition):

Code:
PROCEDURE UpdateThoseProperties( )
	WITH This
		.scBackColor = IIF( BETWEEN( .BackColor, 1, COLOR_MAX ), .BackColor, .scBackColor )
		.BackColor   = IIF( BETWEEN( .BackColor, 1, COLOR_MAX ) .OR. ;
				!EMPTY( .scBackColor ), TApp.System.Colors[.scBackColor, 1], ;
				.BackColor )
	ENDWITH
ENDPROC

This way, I can use ADD OBJECT with either BackColor = 0x800000 (fixed) or BackColor = COLOR_HOTLIGHT (scheme-dependant). Of course, I am not going to use any shade of black interfering with values next to zero.

And now... facing the problem when the property is logical, e.g. FontBold. I guess an extra property is not enough to handle this case.

Dario
 
In my code, the control subclasses handle the initial set-up, and it doesn't matter how the controls get added (I think).

Tamar
 
Just to stress one thing again: If you leave all layout properties at default your forms get themed by windows.

If you want to mix theme with own setttings, then it gets hard and I wouldn't do that. Anyway, if:

I would rather add a property to control what to do, instead of just an initial backup value. What you need to know is, whether the control or its single properties should be theme controlled or not, that needs a bool property. An initial value or expression might be useful besides that and an expression you might want to reevaluate, as ResetToDefault doesn't do it, but reverting to VCX classes can also solve that. Anyway, if you want that expression to be individually different in all instances of the classes, an expression property might be useful. You can decide, if one set of these three preoprties is enough per control, or you even need this for each single property.

You can use another overall bool property to cascade changes, eg a bool ThemeRefresh. If you define a ThemeRefresh_Assign method, that will be done for each control, if you later simply do Thisform.SETALL("ThemeRefresh",.t.).

I wonder, why you favor PRG classes, they have their pros and cons, but in my eyes more cons than pros. Even though they are easier to maintain in regard of source code control, that comes with a too expensive price of not being able to visually design things. Christof Wollenhaupt offers twofox to convert the VCX libs to XML and back at his foxoert site, in it's XML representation the classlibs go into SCC and that's it. Actually I couldn't get it to work without further documentation, but the idea is simple, you may do that on your own and use CURSORTOXML and XMLTOCURSOR on the vcx, you also need meta data about indexes, but what helps here very easily is a zapped vcx as general template to append the vcx data into. That works without scctext or scctextx, but because of the xml structure doesn't mean easy merges of changes of several developers. The XML structure is convoluted with the source code and it get's messy with XML inside source code, even if that's in CDATA sections.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top