Announcement

Collapse
No announcement yet.

Is there a function to create a new control id for a visual control?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Is there a function to create a new control id for a visual control?

    Traditionally we define our objects ahead of time and give them all constant values. PBForms does this, and I imagine the other forms designers do as well.

    So I thought I would dip my toe in the object waters and decided to use a progress bar as my guniea pig. Since I can create multiple instances of my object, can I avoid pre-defining the control id for my progress bar? Is there a function like the GUID function to create a random id (and hopefully make sure it is not already in use)?

    Here my experiment in code:

    Code:
    #COMPILE EXE
    #DIM ALL
    
    %ID_VAL       = 1001
    
    FUNCTION PBMAIN () AS LONG
    
    DIM x AS LONG
    DIM y AS LONG
    DIM hdlg AS DWORD
    
    DIM mymeter AS MeterProperty
    DIM othermeter AS MeterProperty
    
    mymeter = CLASS "progressmeter"
    othermeter = CLASS "progressmeter"
    
    mymeter.x  = 5
    mymeter.y  = 20
    mymeter.xx = 350
    mymeter.yy = 15
    mymeter.text = "Where does this show?"
    
    othermeter.x  = 5
    othermeter.y  = 50
    othermeter.xx = 350
    othermeter.yy = 15
    
    DIALOG NEW 0, "Test Object", 5,5,360,70 TO hdlg
    DIALOG SHOW MODELESS hdlg
    
    mymeter.make (hdlg,%ID_VAL)
    mymeter.range (1,100)
    
    othermeter.make (hdlg,%ID_VAL+1)
    othermeter.range (1,100)
    
    FOR y = 1 TO 100
        othermeter.pos = y
        FOR x = 1 TO 100
            mymeter.pos = x
            DIALOG DOEVENTS
        NEXT x
    NEXT y
    
    MSGBOX "Well?"
    
    END FUNCTION
    
    CLASS ProgressMeter
        ' Define values that would be required across methods
        INSTANCE hdlg AS DWORD
        INSTANCE ID AS DWORD
    
        'Define values it might be convenient to pre-define before creating control
        INSTANCE ptext AS STRING
        INSTANCE x AS LONG
        INSTANCE y AS LONG
        INSTANCE xx AS LONG
        INSTANCE yy AS LONG
        INSTANCE exists AS LONG
    
        CLASS METHOD CreateControl(BYVAL hdlgin AS DWORD, IDin AS LONG)
            CONTROL ADD PROGRESSBAR, hdlgin, IDin, ptext, x,y,xx,yy,%WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %PBS_SMOOTH
            exists = 1
            hdlg = hdlgin
            ID = idin
        END METHOD
    
        CLASS METHOD SetRange(BYVAL RANGE AS LONG)
        END METHOD
    
        INTERFACE MeterProperty
            INHERIT IUNKNOWN
    
            PROPERTY GET x AS LONG
                PROPERTY = x
            END PROPERTY
            PROPERTY SET x (BYVAL v AS LONG)
                x=v
            END PROPERTY
    
            PROPERTY GET y AS LONG
                PROPERTY = y
            END PROPERTY
            PROPERTY SET y (BYVAL v AS LONG)
                y=v
            END PROPERTY
    
            PROPERTY GET xx AS LONG
                PROPERTY = xx
            END PROPERTY
            PROPERTY SET xx (BYVAL v AS LONG)
                xx=v
            END PROPERTY
    
            PROPERTY GET yy AS LONG
                PROPERTY = yy
            END PROPERTY
            PROPERTY SET yy (BYVAL v AS LONG)
                yy=v
            END PROPERTY
    
            PROPERTY GET TEXT AS STRING
                PROPERTY = ptext
            END PROPERTY
            PROPERTY SET TEXT (BYVAL v AS STRING)
                ptext=v
            END PROPERTY
    
            PROPERTY GET lorange AS LONG
                LOCAL waste AS LONG
                LOCAL value AS LONG
                IF exists = 1 THEN
                    PROGRESSBAR GET RANGE hdlg, ID TO value, waste
                    PROPERTY = value
                ELSE
                    PROPERTY = -1
                END IF
            END PROPERTY
            PROPERTY GET hirange AS LONG
                LOCAL waste AS LONG
                LOCAL value AS LONG
                IF exists = 1 THEN
                    PROGRESSBAR GET RANGE hdlg, ID TO waste,value
                    PROPERTY = value
                ELSE
                    PROPERTY = -1
                END IF
            END PROPERTY
            METHOD RANGE (BYVAL loval AS LONG,hival AS LONG)
                IF exists = 1 THEN
                    PROGRESSBAR SET RANGE hdlg, ID, loval, hival
                END IF
            END METHOD
            PROPERTY GET POS AS LONG
                LOCAL value AS LONG
                IF exists = 1 THEN
                    PROGRESSBAR GET POS hdlg, ID TO value
                    PROPERTY = value
                ELSE
                    PROPERTY = -1
                END IF
            END PROPERTY
            PROPERTY SET POS (BYVAL value AS LONG)
                IF exists = 1 THEN
                    PROGRESSBAR SET POS hdlg, ID, value
                END IF
            END PROPERTY
    
            METHOD make(BYVAL hdlgin AS DWORD, idin AS LONG)
                me.CreateControl (hdlgin, idin)
            END METHOD
    
        END INTERFACE
    
    
    END CLASS
    Thanks,

    John Kovacich
    Ivory Tower Software

    #2
    >METHOD make(BYVAL hdlgin AS DWORD, idin AS LONG

    Why not just add a property for Control_ID and assign that property value when processing here?

    FWIW, you can get the assigned ID of any control with GetDlgCtrlID(Hwnd), so if you have a handle to the control
    you have the control ID automatically.

    Assigning an ID is not a good idea... since neither you nor the user knows what ADDITIONAL controls might have to be placed on this screen AFTER this one is added... and a conflict here would be a Bad Thing.


    MCM
    Last edited by Michael Mattias; 4 Apr 2009, 05:14 PM.
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


      #3
      I'd like something that worked like freefile. As long as it returns a unique unused number to create the control, there is no need for my main program to ever know what the number is, as long as the instance knows. Remember, I'm not requiring any call back for this.

      How about a function that would tell me if a given control id existed? If I can generate the number and simply test if a control already uses it, I could make that work.
      Thanks,

      John Kovacich
      Ivory Tower Software

      Comment


        #4
        >I'd like something that worked like freefile

        And what's the rule for freefile? If one file is opened using FREEFILE, all files must be opened using freefile.

        There is no Windows call to "freecontrol ID" , and it's probably a real good thing there isn't... do you really want to code your screens testing CBCTL (LOWRD(wParam)) equal to some VARIABLE rather than a constant like %IDOK or %IDM_OPEN? I didn't think so.

        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


          #5
          How about a function that would tell me if a given control id existed? If I can generate the number and simply test if a control already uses it, I could make that work.
          Just enum all the child windows of the parent window and test GetDlgCtrlID() in the callback procedure.

          And put a warning on the outside of the box so I don't buy one.
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


            #6
            It might be possible to do something like that, but in order to do it, you'd have to forgo the ability to add any controls at design time and instead use several classes to manage your controls, with a master class holding all of them in one big monster arrangement. Then your tests would be something like:
            Code:
            SELECT CASE CB.CTL
              CASE MasterControl.Buttons("Ok Button")ControlID
              CASE MasterControl.Buttons("Cancel Button").ControlID
            Yeah, I can see it working, but you'd have to adopt a whole new paradigm in creating programs.

            P.S. My syntax may be wrong, this is off the top of my head.
            Furcadia, an interesting online MMORPG in which you can create and program your own content.

            Comment


              #7
              The identifier of a control can be retrieved and set dynamically using the
              GetWindowLong and SetWindowLong functions. It is also very easy to avoid conflicts
              by using the EnumChildWindows function to check the controls on a form.

              The code snippet below shows how this could be done. By convention, IDC_STATIC(-1) is used
              in Windows programming to indicate that we do not care about the identifier of a control.
              Therefore, if the value in the variable, lControlId, is unchanged when EnumChildWindows returns,
              the identifier is not in use. If it is -1, the identifier is in use.
              Code:
              '-------------------------------------------------------------------------------
              
              FUNCTION IsIdentifierInUse(BYVAL hWnd AS DWORD, BYVAL lParam AS LONG) AS LONG
              
                LOCAL plControlId AS LONG PTR
              
                plControlId = lParam
              
                IF GetWindowLong(hWnd, %GWL_ID) = @plControlId THEN
                  @plControlId = -1
                  FUNCTION = %FALSE
                  EXIT FUNCTION
                END IF
              
                FUNCTION = %TRUE
              
              END FUNCTION
              
              '-------------------------------------------------------------------------------
              
              FUNCTION Form1_SetId_Clicked _
                ( _
                BYVAL hWndParent  AS DWORD, _ ' handle of parent window
                BYVAL hWndCtrl    AS DWORD _  ' handle of control
                ) AS LONG
              
                LOCAL lControlId  AS LONG
              
                lControlId = 205
                EnumChildWindows hWndParent, CODEPTR(IsIdentifierInUse), VARPTR(lControlId)
                IF lControlId = -1 THEN
                  MSGBOX "Identifier in use"
                ELSE
                  MSGBOX "Identifier not in use" 
                  SetWindowLong hWndCtrl, %GWL_ID, 205
                  MSGBOX "New Id = " + FORMAT$(GetDlgCtrlID(hWndCtrl))
                END IF
              
              END FUNCTION
              Dominic Mitchell
              Phoenix Visual Designer
              http://www.phnxthunder.com

              Comment


                #8
                The hWnd of the control is already unique.
                hellobasic

                Comment


                  #9
                  It is also very easy to avoid conflicts
                  by using the EnumChildWindows function to check the controls on a form.
                  Yes, it is, but that presupposes you go last...

                  I'd guess about one hundred six percent of Windows programs use constants for control ids.... so what happens in this case....
                  Code:
                      Create window or dialog  ==> hWnd 
                      Add control with ID_1 
                      Add control with ID_2 
                      Call class method to add this control; ID assigned by the METHOD ==> ID_A 
                      Add control with ID_3
                         oops, ID_3, not in use when ID_A was assigned, equals ID_A 
                      ....
                  As has been noted, if there were "one central place from which all control IDs for a given owner window are assigned" you could make this work... but 'mix and match' cannot because the class method cannot know what control IDs the programmer wants to use later.

                  MCM
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                    #10
                    Except maybe if you...
                    Code:
                      CLASS whatever 
                    
                             METHOD GiveMeAControlID (hwndOwner as LONG)   () AS LONG 
                    
                    ....
                    ???
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                      #11
                      Originally posted by John Kovacich View Post
                      Traditionally we define our objects ahead of time and give them all constant values. PBForms does this, and I imagine the other forms designers do as well.
                      I am probably the last person who should reply to your post as hopeless at GUI and don't like COM but I think your basic assumptions are wrong, particularly as you are using DDT. New controls can be added at any constant value as long as it does not conflict with an existing control ID. Example, you design your basic form in PBForms with many controls and lets say the last ID it used 1563. Simply write your own simple FreeID Function or even a COM Object if you prefer where you start allocating ID's from a number much higher than could have been your highest allocated by your forms designing program. So in the case of highest 1563 your program would start by setting a STATIC variable to say 2000 in the fuction or whatever its equivalent is in COM. Each call to the function or object just increments the variable and returns it as a new Control ID (in DDT) to use.
                      Yes it is possible to write a program that will run out of usable number but I suspect that Windows will run out of available resources long before that happens.

                      Comment


                        #12
                        Originally posted by Michael Mattias View Post
                        >I'd like something that worked like freefile

                        And what's the rule for freefile? If one file is opened using FREEFILE, all files must be opened using freefile.

                        There is no Windows call to "freecontrol ID" , and it's probably a real good thing there isn't... do you really want to code your screens testing CBCTL (LOWRD(wParam)) equal to some VARIABLE rather than a constant like %IDOK or %IDM_OPEN? I didn't think so.

                        MCM
                        Can't agree with either of those statements Michael, proofs please.
                        I use lots of what in VB are called Control Arrays so typical (actually real case examples from a running program) case statements from a SELECT CASE AS LONG CBCTL, just two for you CASE %CBgr TO %CBgr + 23
                        or CASE %CBred1 TO %CBred7, %CBred1 + 1000 TO %CBred7 + 1000
                        The CASE statement is very powerful.

                        Comment


                          #13
                          On the first, FREEFILE, consider....
                          Code:
                           F = FREEFILE
                           OPEN "MYFILE " for mode AS F 
                          ...
                           OPEN "otherfile"  for somemode as #6 
                          ..
                          FREEFILE might return 6.... oops, file in use error. To avoid this, either all files use FREEFILE, or none of them do.

                          On the second - "freecontrolId" - I can't give you an example of what I claim does not exist. Can't prove a negative, you know.

                          MCM
                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                            #14
                            As has been noted, if there were "one central place from which all control IDs for a given
                            owner window are assigned" you could make this work... but 'mix and match' cannot because
                            the class method cannot know what control IDs the programmer wants to use later.
                            Sorry, but that statement dead wrong. Your next post showed why.

                            I know what I showed in my post works, because the Phoenix Visual Designer uses it. It is the only
                            designer available for PowerBASIC where the programmer can assign any numeric identifier to an object
                            and never have to worry about conflicts. The programmer can also import into a project forms from other
                            unrelated projects written by other programmers, and does not have to worry about conflicts.

                            It is relatively easy to determine whether a control ID is already in use, or to generate one that
                            is not in use.
                            Last edited by Dominic Mitchell; 5 Apr 2009, 07:24 PM.
                            Dominic Mitchell
                            Phoenix Visual Designer
                            http://www.phnxthunder.com

                            Comment


                              #15
                              I'm not saying it CAN'T be done, I'm saying in a practical sense it cannot work effectively unless ALL controls use some kind of 'GetMeAControldID' facility.

                              You end up at the source code level dealing with the same potential conflict with control IDs as you get with the mixed FREEFILE/numeric literal file handle example above: a maintenance nightmare.

                              Maybe... reserving a RANGE of control Ids which the 'auto-assigner' returns would work, but that's a kludge.

                              Maybe we are not on the same page here... I read this as a request to assign control IDs at run time. Designer products, to be sure, can assign control Ids to avoid conflicts, but these products do so at compile time.
                              Michael Mattias
                              Tal Systems (retired)
                              Port Washington WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                                #16
                                Originally posted by Michael Mattias View Post
                                On the first, FREEFILE, consider....
                                Code:
                                 F = FREEFILE
                                 OPEN "MYFILE " for mode AS F 
                                ...
                                 OPEN "otherfile"  for somemode as #6 
                                ..
                                FREEFILE might return 6.... oops, file in use error. To avoid this, either all files use FREEFILE, or none of them do.

                                On the second - "freecontrolId" - I can't give you an example of what I claim does not exist. Can't prove a negative, you know.

                                MCM
                                You really should take the time to test before you post erronious information as the following code shows
                                Code:
                                #COMPILE EXE
                                #DIM ALL
                                
                                FUNCTION PBMAIN () AS LONG
                                
                                    LOCAL f AS LONG
                                    LOCAL x AS LONG
                                    f = FREEFILE
                                    ? STR$(f)
                                    OPEN "c:\test.txt" FOR OUTPUT AS #3
                                    FOR x = 1 TO 5
                                        f = FREEFILE
                                        ? STR$(f)
                                    NEXT
                                END FUNCTION
                                At least in 8.03 freefile returns 1,2,4,5,6,7 so the possible error you claim doesn't happen. Power Basic compilers are better than that and as there is no mention of that restriction in the help (at least in 8.03) I fail to understand how you came up with that idea.
                                Of course there is no FreeControlID function, I had already described how simple it was to write one for DDT, I was refering to the second part of your claim about storing the ID in variables when it is actually simple and safe code. In fact in the examples I gave I don't even store the IDs as the values returned in the callback are self describing.

                                Comment


                                  #17
                                  You really should take the time to test before you post erronious information as the following code shows
                                  And you should really run your tests as I posted the demo ... where the attempted OPEN using the numeric literal occurs after the OPEN using FREEFILE....
                                  Michael Mattias
                                  Tal Systems (retired)
                                  Port Washington WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment


                                    #18
                                    Micheal
                                    How about you read your own posts? Your first definative statement was
                                    And what's the rule for freefile? If one file is opened using FREEFILE, all files must be opened using freefile.
                                    My simple example shows that to be wrong as it does exactly what that statement says cannot be done. If you are referring to those few lines of dashed off non working code then they will only fail if you have already opened a file using that number allocated by freefile which is not what you said or even demonstrated.
                                    Maybe we are not on the same page here... I read this as a request to assign control IDs at run time. Designer products, to be sure, can assign control Ids to avoid conflicts, but these products do so at compile time.
                                    If that statement had any truth then I would be in big trouble as I have PB programs that assign hundreds of control IDs at run time (and yes the word hundreds is for real not an exageration) and the create controls on them with no conflicts or problems.
                                    I note you have posted many times that you don't use DDT which the OP said he was using so is this one of the many threads in which you post even though you have limited experience.
                                    John

                                    Comment


                                      #19
                                      Originally posted by Dominic Mitchell View Post
                                      ...It is the only
                                      designer available for PowerBASIC where the programmer can assign any numeric identifier to an object
                                      and never have to worry about conflicts.
                                      I may have misread but what objects do you speak of?
                                      If you speak about controls.. if the user decides to reset a control id, it's just just fine..
                                      In a rare occasion a control id is required like for the non-visual controls like the openfiledialog.
                                      PwrDev tags a control for eventhandling and does not care for it's ID.
                                      hellobasic

                                      Comment


                                        #20
                                        Maybe we are not on the same page here... I read this as a request to assign control IDs at run time.
                                        Designer products, to be sure, can assign control Ids to avoid conflicts, but these products do so at compile time.
                                        Run-time or design-time is irrelevant for the Phoenix Visual Designer. Any changes to a control must be
                                        done at design-time, because certain utilities like the Layout Manager will fail miserably when the form
                                        is resized.

                                        Maybe... reserving a RANGE of control Ids which the 'auto-assigner' returns would work, but that's a kludge.
                                        You have got to be joking!

                                        If you speak about controls.. if the user decides to reset a control id, it's just just fine.
                                        Any object that requires and id, for example, a menu item, string, bitmap or control.
                                        For example, when the user copies an object from one form to another form, if both objects have the same
                                        id and are of the same type(e.g. controls), how is this conflict handled?
                                        Dominic Mitchell
                                        Phoenix Visual Designer
                                        http://www.phnxthunder.com

                                        Comment

                                        Working...
                                        X
                                        😀
                                        🥰
                                        🤢
                                        😎
                                        😡
                                        👍
                                        👎