Author Topic: Components  (Read 1001 times)

Chris Boss

  • Administrator
  • Newbie
  • *****
  • Posts: 49
    • View Profile
Components
« on: March 21, 2023, 10:47:08 am »
The EZGUI docs don't go into detail about creating and using components. This post is where I will try to explain it better. I will give an brief overview and then over time add more to this discussion.

What is a component ?

A component is like a page form (which can be put on a normal form) which acts like a single control. You can put any child controls on the component and make it do some repeatable task, but to your app it will act like a single control.

You can create a component once and use it over and over again on different forms. 

You do not create a component like you do a normal form, even though technically it is a form with child controls. There are special commands for defining a component and even processing its events and also sending events from the component to your app (remember it appears to your app as a single complex custom control).

The designer needs a component to be compiled to a DLL so you can use it there when visually designing your app. But a component in your app can be accessed either in its compiled form (DLL) or as source code (designer will generate the path to the source code if you desire rather than load a DLL when it generates your source code).

Components are a bit complex at first glance and is an advanced feature. But once you start learning how to use them it really is not that difficult.

Let's look at some source code for a component that comes with EZGUI (Canvas Scroller):

Code: [Select]
' ======================================
' [PROTECTED CODE]         Do NOT Edit !
' ======================================

DECLARE SUB EZ_CSCROLLER_InitComponent(BYVAL CMPPrefix$)
DECLARE SUB EZ_CSCROLLER_Design()
DECLARE SUB EZ_CSCROLLER_ParseEvents(CID&, CMsg&, CVal&, Cancel&)
DECLARE SUB CSCROLLER_Events(CID&, CMsg&, CVal&, Cancel&)
' ------------------------------------------------

%CSCROLLER_MYPICTURE          = 100

'<<BEGINFORM>> "CSCROLLER"

' ======================================
' [PROTECTED CODE]         Do NOT Edit !
' ======================================

SUB EZ_CSCROLLER_InitComponent(BYVAL CMPPrefix$)     ' (PROTECTED)
     EZ_DefComponent CMPPrefix$+"CSCROLLER", "SVBK||CSCROLLER.bas", CODEPTR(EZ_CSCROLLER_Design), CODEPTR(EZ_CSCROLLER_ParseEvents)
END SUB

SUB EZ_CSCROLLER_Design()     ' (PROTECTED)
     LOCAL CText$
     EZ_Color-1,-1
     EZ_UseFont 4
     EZ_UseAutoSize "CT"
     EZ_Picture %CSCROLLER_MYPICTURE, 0, 0, 6, 3, "SAMPLEBMP", ""
     ' -----------------------------------------------
END SUB


SUB EZ_CSCROLLER_ParseEvents(CID&, CMsg&, CVal&, Cancel&)     ' (PROTECTED)
     SELECT CASE CID&
          CASE %EZ_Window
               CSCROLLER_Events CID&, CMsg&, CVal&, Cancel&
          CASE ELSE
               CSCROLLER_Events CID&, CMsg&, CVal&, Cancel&
     END SELECT
END SUB

' ======================================
' [USER ACCESSABLE CODE]  You may Edit !
' ======================================
'<<SAVE>>
SUB CS_ShowPicture(BYVAL P$)
     LOCAL W&, H&, CW&, CH&, FW!, FH!, SW&, SH&, SF$, X&, Y&, XDif&, YDif&, VScroll&, HScroll&, EW&, EH&
     EZ_HideC "{ME}",%CSCROLLER_MYPICTURE,%CSCROLLER_MYPICTURE
     IF P$="" THEN
          EZ_HideFormScrollBars "{ME}", "B"
          EXIT SUB
     END IF
     IF EZ_ImageHandle(P$)<>0 THEN
          EZ_GetPictureSize P$, W&, H&
          EZ_HideFormScrollBars "{ME}", "B"
          EZ_GetSize "{ME}",FW!, FH!, 2
          VScroll&=0
          HScroll&=0
          CW&=FW!
          CH&=FH!
          SW&=EZ_WO("SW")
          SH&=EZ_WO("SH")
          SF$=""

          IF W&<=CW& AND H&<=CH& THEN
               ' no scrollbars
               X&=(CW&-W&)\2
               Y&=(CH&-H&)\2
          ELSE
               EW&=0
               EH&=0
               IF W&>CW& THEN EH&=SH&
               IF H&>CH& THEN EW&=SW&
               IF W&>(CW&-EW&) THEN
                    X&=0
                    SF$=SF$+"H"
                    HScroll&=W&-(CW&-EW&)
               ELSE
                    X&=((CW&-EW&)-W&)/2
               END IF
               IF H&>(CH&-EH&) THEN
                    Y&=0
                    SF$=SF$+"V"
                    VScroll&=H&-(CH&-EH&)
               ELSE
                    Y&=((CH&-EH&)-H&)/2
               END IF
          END IF
          IF X&<0 THEN X&=0
          IF Y&<0 THEN Y&=0
          EZ_ResizeC "{ME}",%CSCROLLER_MYPICTURE, EZ_CX(X&),EZ_CY(Y&), EZ_CX(W&),EZ_CY(H&)
          EZ_SetImage "{ME}",%CSCROLLER_MYPICTURE, P$
          EZ_ShowFormScrollBars "{ME}", SF$
          EZ_ShowC "{ME}",%CSCROLLER_MYPICTURE,%CSCROLLER_MYPICTURE
          IF INSTR(SF$,"H") THEN
'               EZ_SetHScroll "{ME}",0, 0, HScroll&, 0,(HScroll&\10)+1
               EZ_SetHScroll "{ME}",0, 0, HScroll&, 0,1
          END IF
          IF INSTR(SF$,"V") THEN
'               EZ_SetVScroll "{ME}",0, 0, VScroll&, 0,(VScroll&\10)+1
               EZ_SetVScroll "{ME}",0, 0, VScroll&, 0,1
          END IF
     END IF
END SUB

SUB ScrollMe(BYVAL SMode&, BYVAL CVal&)
     LOCAL C!, R!, W!, H!
     EZ_GetSizeC "{ME}",%CSCROLLER_MYPICTURE,C!, R!, W!, H!
     IF SMode&=-1 THEN
          R!=0-EZ_CY(CVal&)
     ELSE
          C!=0-EZ_CX(CVal&)
     END IF
     EZ_ResizeC "{ME}",%CSCROLLER_MYPICTURE,C!, R!, W!, H!
END SUB

SUB FreeMyStartBitmap()
     LOCAL P$
     P$=EZ_GetCmpText("{ME}",0,1)
     IF P$<>"" THEN
          EZ_FreeImage P$
          EZ_SetCmpText "{ME}",0,"", 1
     END IF
END SUB
'<<END>>

SUB CSCROLLER_Events(CID&, CMsg&, CVal&, Cancel&)
     LOCAL P$
     SELECT CASE CID&
          CASE %EZ_Window
               SELECT CASE CMsg&
                    CASE %EZ_Loading
                    CASE %EZ_Loaded
                         EZ_HideFormScrollBars "{ME}", "B"
                         EZ_HideC "{ME}", %CSCROLLER_MYPICTURE, %CSCROLLER_MYPICTURE
                         P$=EZ_GetText("{ME}",0)
                         EZ_SetText "{ME}",0,""
                         IF P$<>"" THEN
                              IF UCASE$(RIGHT$(P$,4))=".BMP" THEN
                                   P$=EZ_LoadPicture(P$)
                                   IF P$<>"" THEN
                                        CS_ShowPicture P$
                                        EZ_SetCmpText "{ME}",0,P$,1
                                   END IF
                              ELSE ' assume it is a Picture string
                                   CS_ShowPicture P$
                              END IF
                         END IF
                    CASE %EZ_TextUpdated
                         SELECT CASE CVal&
                              CASE 1
                              CASE ELSE
                         END SELECT
                    CASE %EZ_BitmapUpdated
                         FreeMyStartBitmap
                         P$=EZ_GetBitmapName(CVal&)
                         CS_ShowPicture P$
                    CASE %EZ_ColorUpdated
                         LOCAL FG&, BG&
                         FG&=EZ_GetCmpAttr("{ME}",0,1)
                         BG&=CVal&
                         EZ_SetColor "{ME}",0, FG&, BG&
                    CASE %EZ_FontUpdated
                    CASE %EZ_SelUpdated
                    CASE %EZ_ClearUpdated
                         CS_ShowPicture ""
                    CASE %EZ_FreeNow
                         FreeMyStartBitmap
                    CASE %EZ_Started
                    CASE %EZ_Close
                    CASE ELSE
               END SELECT
          CASE -1        ' Vertical scrollbar
               IF CMsg&=%EZ_Change THEN
                    ScrollMe -1, CVal&
               END IF
          CASE -2        ' Horizontal scrollbar
               IF CMsg&=%EZ_Change THEN
                    ScrollMe -2, CVal&
               END IF
          CASE ELSE
     END SELECT
END SUB


The designer generates a subroutine for adding the component to one of your forms:

SUB EZ_CSCROLLER_InitComponent(BYVAL CMPPrefix$)


In this routine is a call to EZ_DefComponent:

     EZ_DefComponent CMPPrefix$+"CSCROLLER", "SVBK||CSCROLLER.bas", CODEPTR(EZ_CSCROLLER_Design), CODEPTR(EZ_CSCROLLER_ParseEvents)

What is not provided is a example of how to put your components into a DLL.  You can put more than one component in a DLL to create a library of compoments. Once compiled to a DLL the DLL and the source code for the components should be put in the EZGUI Designers component folder.

Here is an example of a component DLL:

Code: [Select]
#COMPILE DLL "cmplib1.dll"
#INCLUDE "C:\ezgui45beta\includes\ezgui50.inc"

FUNCTION LIBMAIN (BYVAL hInst&, BYVAL FReason&, BYVAL lpR&) AS LONG
     SELECT CASE FReason&
          CASE 0      ' %DLL_PROCESS_DETACH
          CASE 1      ' %DLL_PROCESS_ATTACH
          CASE 2      ' %DLL_THREAD_ATTACH
          CASE 3      ' %DLL_THREAD_DETACH
          CASE ELSE
     END SELECT
     FUNCTION=1
END FUNCTION

#INCLUDE "C:\ezgui45beta\projects\real components\Form_pgscroller\pgscroller.bas"    ' Component include file!
#INCLUDE "C:\ezgui45beta\projects\real components\Form_cscroller\cscroller.bas"    ' Component include file!

SUB EZ_InitComponent(BYVAL CMPPrefix$) EXPORT
     EZ_PGSCROLLER_InitComponent CMPPrefix$
     EZ_CSCROLLER_InitComponent CMPPrefix$
END SUB

The two components that come with EZGUI are in separate files and must be included in this DLL code file and this is how I created the component DLL that comes with EZGUI.

A component needs an entrance function and that is predefined by EZGUI and always is:

SUB EZ_InitComponent(BYVAL CMPPrefix$) EXPORT

The function must be exported to EZGUI (and the designer) can find it the function. The function is found by polling the DLL for it by name and then it is called dnyamically (no Declare required).


Chris Boss

  • Administrator
  • Newbie
  • *****
  • Posts: 49
    • View Profile
Re: Components
« Reply #1 on: March 21, 2023, 11:07:51 am »
Now let's look at all the commands EZGUI provides for working with components:

To define a component use:

EZ_DefComponent

In your app you can either use a source code version of a component or you can load a precompiled component DLL. To load a component from a DLL use:

EZ_LoadComponent

To add a component to a form use:

EZ_AddComponent

Component specific commands available:

EZ_GetCmpAttr
EZ_SetCmpAttr
EZ_GetComponentData
EZ_CmpName
EZ_SendMeEvent
EZ_GetCmp
EZ_GetCmpText
EZ_E
EZ_SetCmp
EZ_SetCmpText
EZ_GetCmpData
EZ_CmpFG
EZ_CmpBG
EZ_CmpFont
EZ_CmpSetData



Component Specific Events (inside components own event code):

%EZ_AttrUpdated
%EZ_TextUpdated
%EZ_BitmapUpdated
%EZ_ClearUpdated
%EZ_ColorUpdated
%EZ_IconUpdated
%EZ_FontUpdated
%EZ_SelUpdated
%EZ_CmpSet
%EZ_CmpGet

Normal EZGUI commands that support components:

EZ_ResetAutoSize
EZ_GetCListClass
EZ_GetClass
EZ_GetGUIStats
EZ_Clear
EZ_SetImage
EZ_SetFont
EZ_SetColor
EZ_SelectItem
EZ_SetText
EZ_UseAutoSize
EZ_SwapImage

Two commands which can NOT be used with a component (the component itself, not the child controls of a component in the component code):

EZ_SetUserString
EZ_GetUserString





Chris Boss

  • Administrator
  • Newbie
  • *****
  • Posts: 49
    • View Profile
Re: Components
« Reply #2 on: March 21, 2023, 02:35:11 pm »
The key to understanding what a component does is this:

If you design a form you can only use one instance of this form at a time. Each form has its own name and no two can have the same name.

A Component uses a single form design, but can create multiple instances of itself and it creates a unique name for each instance which it tracks internally.

You don't talk directly to the controls on the component. Instead it is treated as if if was a control and it is given its own unique control ID at creation.

When you talk to the component, instead of talking to its controls directly, you talk to the form itself using the available component supporting commands such as:


EZ_Clear
EZ_SetImage
EZ_SetFont
EZ_SetColor
EZ_SelectItem
EZ_SetText
EZ_SwapImage

A component tracks its own colors, font, text and bitmap/icon.

If I have a component which has an ID of 100 on a Form1 , I can tell the component to clear itself simply by calling:

EZ_Clear "Form1", 100

Now EZGUI will generate an event and send it to the component. The form event routine of the component will get the %EZ_ClearUpdated event.

Now it becomes the components responsiblity to clear itself (whatever that may mean for the form and how it was designed to work.


Now let's say a component handles text. Maybe it is a mini-Wordpad emulator and has a richtext control on it.

For a component with ID = 100 and on Form1 you could call:

EZ_SetText "Form1", 100, SomeRTFtext$

The components form level event code will get the event:

%EZ_TextUpdated

Then in this event the component can retrieve the text using the EZ_GetCmpText function.

A component can store up to 32,768  unique strings. They have an Index number.

It is up to you what indexes you want to use to store your strings.

%EZ_TextUpdated will pass an index number in CVal&.  EZ_SetText always passes a zero index (undefined). EZ_SetCmpText has a parameter to pass an index value which will be passed through the Cval& parameter for the event.

EZGUI does not use an array to store stings for a component. It stores them in a single string data type. It separates the records (each individual indexed string) using an ascii character 1 ( CHR$(1) ). So do not pass the ascii character 1 in your strings.

So if a component is not defined with a form name, what name do you use for the component itself (it is technically a form) when calling EZGUI commands which require a form name ?

The easiest way is to use the Form macro:

"{ME}"

Forms know their own name, so if a command is called within a components form events and you are calling itself, then this macro is what to use.

You can also retrieve the components actual form name by using the function:

EZ_CMPName

You pass the function the parent form of the component and the components ID number (remember it acts like a control to your app and has an ID rather than name) and you can get the internal form name for the component.








Raymond Couzens

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Components
« Reply #3 on: March 23, 2023, 05:22:52 am »
I've created a test control that has two labels and a ListView. I've also successfully created the dll for using it within the ezgui designer but at the moment just testing within my code.  I can create the control and display it fine.  What I was hoping was to be able to add my custom control to the main form's auto resizing by using the EZ_UseAutoSize and EZ_AddAutoSize commands but this is not working so have no doubt missed something.  I can of course write my own code for resizing the custom control but was just wondering if I've missed something obvious and can use ezgui's resize engine?  Thanks.
« Last Edit: March 23, 2023, 08:25:15 am by Raymond Couzens »

Raymond Couzens

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Components
« Reply #4 on: March 23, 2023, 08:27:03 am »
It's okay, I've discovered the %EZ_NoAutoSize event so just had to set Cancel to 1.  Slowly getting the idea of this.