# VBForums UtilityBank > UtilityBank - Tutorials >  VB6 Cairo-Widgets Tutorial

## Schmidt

This is the "logical second step", after one got more familiar with Cairo-Drawing -
in the preceding Tutorial here: https://www.vbforums.com/showthread....cs-using-Cairo

This Widget-Tutorial will show, how you can put your gathered knowledge with the Drawing-Methods 
(behind the usually named CC As cCairoContext) - to good use, when writing your own Cairo-based Controls.

A self-implemented "UserControl" (with the helper-classes from RC6, using cairo-drawing) - is called "a Widget".

A Widget is like a WindowLess-UserControl in VB6 - but not implemented in a *.ctl - but a normal *.cls.

Due to that (everything sitting in a "normal Class"), I recommend to use the same ClassName-prefixing as you find in the Demos:
- cSomeNormalClass (a normal Class is prefixed with a small c)
- cfSomeRC6Form (an RC6-Form-Class is prefixed with cf)
- cwSomeWidget (an RC6-Widget-Class is prefixed with cw)

This will allow one, to keep the different type of Classes apart (the cf-prefixed ones are like *.frm, and the cw-ones like *.ctl).

Ok, on the inside of a cwSomeWidget-Class, you will see basically the same principle, as when implementing something in a MyCtl.ctl:
- an internal Helper-Variable, which provides you with all kind of Events inside of this "Control-Class"
- in VB6 this Helper-Variable is named UserControl (automatically provided by the IDE, you don't have to define it)
- and for RC6-WidgetClasses the same thing is usually named W, but you have to define it yourself:
Private WithEvents W As cWidgetBase

Other than that, the implementation is similar to what you do in a VB6-UserControl-Module:
- you get Resize, Focus, Keyboard, Mouse- and Paint-Events from your internal UserControl-Variable
- and in the same way, you get the same Events (plus a few more) in your Widget-Class from the W-Variable

The largest difference to VB6-Usercontrols is this:
- We now have a fully Alpha-Capable Vector-engine behind it (which supports even nested Alpha)
- And the Widget is "by default" always "fully transparent"

The latter part meaning:
If you don't render anything in the W_Paint()-Event via explicite Cairo-methods, you will "not see anything" 
(the Container-Background of the Parent-Widget or Parent-Form will "remain as it is" below the area, your Widget occupies).

Please note, that the only way to "render a given Widget properly", is via the W_Paint()-Event.
If you change state on a given Widget (e.g. a Caption-Prop or an ImageKey-Property), you will have to ensure:
- either a W.Refresh (if you are on the inside of your own implementing WidgetClass)
- or a MyCtl.Widget.Refresh call on the outside of your WidgetClass-implementation
to finally trigger the W_Paint-Event on the given Widget, which then dutifully re-renders its contents, according to the new "state".

Ok, the Tutorial here has the same "Folder-structured approach" (from simple to more difficult),
as the Cairo-Drawing-Tutorial which came before it...

*Folder-Contents:*
- 0 Hello World in VBScript
- 1 Hello Widgets (simple)
- 2 Widgets (Moveable-Prop and Zooming)
- 3 Widgets (Events and Nesting)
- 4 Widgets (MouseCursors and ImageKeys)
- 5 SliderWidget (demonstrating visual inheritance)

Here a ScreenShot of the "Folder #4 Demo" (Drag-Drop + MouseCursor-Handling)


Here a ScreenShot of "Folder #5" (a Slider Widget + Visual Inheritance)


Here the Demo-Zip:
RC6WidgetTutorial.zip

Happy "Widgeting"...

Olaf

----------


## yokesee

Never, I have been given the visual aspect.
But this tutorial is very good.
I will study it later


very good work

----------


## JT870

Dear Olaf,
     The RC5/6 Widget is so powerful that  I'm able to use it to  simulate a little graph canvas  to create a group of objects  as a desired mixed object, my question is how to save the single object and whole canvas  , especially  like microsoft excel's insert shapes  and grouping them and save them.  Thanks.

----------


## Schmidt

RC5/6 Widgets are based on a "State-Machine"...
 (based on a bunch of Widget-Props, which hold that State,... 
and "all that State" is finally influencing the rendering in the internal W_Paint-Event, when triggered by the .Refresh-Method).

So, if you want to save Widgets (a Widget-Hierarchy, starting from some "Root-, or Parent-Widget"), you will have to:
- Enumerate all Widgets recursively (starting from a Root-Widget) 
- build (serialize) "a XML- or JSON-Node"-string out of the "internal State" of the currently enumerated Widget 
adding that "String-Result-Node", to a StringBuilder-Object, you pass along in that recursive Enumeration

And as for the serialization itself, you basically have to do that (in a single, given Widget) -
for all the Private Vars within that Widget, starting with the one which is "always there" -> W As cWidgetBase.

1) serialize all "Default-Props" of 'W' (Left, Top, Width, Height, FontName, FontSize, ForeColor,BackColor etc.)
2) and finally serialize all "selfdefined Private Vars" which you used, to hold additional state

-----------------------------------------

That said... the RC5/6 already contains an "Auto-Serializer", based on XML - 
which can be triggered behind any .Widget*s*-Prop via e.g.: strXML = MyRC6Form.Widget*s*.SerializeToXML(..., ...)

The only requirement for that to work properly, is that all of your own Widget-Classes are contained Public in an AX-Dll
(and not as Private Classes in your Main-Project).

If that requirement is a problem for you, then you can always "roll your own" serialization, 
as outlined at the beginning of this post.

Olaf

----------


## JT870

Desr Olaf, Thank you very much， As per your guide above,  I define sth my self in every obj class, so far the object  can  be moved, zoomimg ,  coped  and saved as png ,also with the help of imagemagicK command line it can be copy as tranparent bg object  similar to MS excel insert graph. It works fine。

My another3 questions are:
1)how to lock any one object but allow other objects to move and zoom in the  same panel?
2) Is it possible to group some objects together like excel insert graph?
3) when I make one object  rotate  as your post example in vbforums, it can work at first time, then  memory problem occured ,how can I do ?

thanks .

----------


## JT870

Attachment 183516

----------


## Schmidt

Cannot see (or download) your attachment.

As for your other questions:
1) Move-Locks could be done by simply setting MyShape.Widget.Moveable = False
2) Grouping (using the Widget-Engine) one can do, by placing the grouped Widgets within their own (transparent) Parent-Widget
3) A link to some code (or your own uploaded Zip-File) would be good

Olaf

----------


## -Corso->

Hi all, I can't believe I missed this tutorial(?) somehow. As I'm reading it currently, just wondering, since Olaf has updated Cairo so much, it appears that some of the programing is no longer requires a lot of the setouts of the old stuff. Is this same situtation for Widgets too? Like for example, one doesn't need to type this in anymore to make Cairo work. (Great) 
_"Public New_c As New cConstructor, Cairo As cCairo"_
I'd like learn more if possible, but I feel like I'm reading something that seems out of date. Does anyone have any updated Widget samples/examples they could share with us plebs?
Have a Cairo-Random-Auto-Generated Facemaker Maiden for your trouble.

----------

