Page 1 of 2 12 LastLast
Results 1 to 40 of 41

Thread: [RESOLVED] User action versus code causing event to raise

  1. #1

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Resolved [RESOLVED] User action versus code causing event to raise

    You know something that would be immensely useful to me? A flag (passed to many events) that indicated whether it was user interaction or other code that made the event fire. You know, something like the UnloadMode argument in Form_QueryUnload.

    I'm often creating module (form) scoped variables with names like mbSettingMyCheckbox, and then wrapping my code setting like the following:

    Code:
    
        mbSettingMyCheckbox = True
        chkMyCheckbox.Value = MyCheckboxValueFromCode
        mbSettingMyCheckbox = False
    
    
    And then, in the event, I'll have something like the following:

    Code:
    
    Private Sub chkMyCheckbox_Click()
        If mbSettingMyCheckbox Then Exit Sub
    
        ' Other code that deals with issues related
        ' to the USER (not code) changing this.
    
    End Sub
    
    
    It'd just be nice to have a way to do this without the need for a module scoped flag. It can get cumbersome when there are many controls for which this must be monitored. I can sometimes use the same flag for all of them, but not always (depending on how things work).

    Addendum: I sometimes also use this method to prevent recursion. For instance, there are sometimes situations when they're not allowed to change the CheckBox value at a certain time. So, I might do something like the following:

    Code:
    
    Private Sub chkMyCheckbox_Click()
        If mbSettingMyCheckbox Then Exit Sub
    
    
        If [some tested condition that doesn't allow changing right now] Then
            mbSettingMyCheckbox = True
            chkMyCheckbox.Value = IIf(chkMyCheckbox = vbChecked, vbUnchecked, vbChecked)
            mbSettingMyCheckbox = False
        End If
    
    End Sub
    
    Again, it'd just be nice if I didn't need the extra variable to do this.

    Further Clarification: And yes, I'm aware that, if the code isn't actually changing the CheckBox's value that the click event doesn't fire. But, if it is changing the value, it does fire the click event. But that's not the point I'm trying to get at.
    Last edited by Elroy; Dec 1st, 2021 at 11:12 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  2. #2
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    4,417

    Re: User action versus code causing event to raise

    I don't understand your "whether the user or other code fired the event"
    In your example it's the user firing it (actually: it still "hidden" code firing it)

    Do you mean something like
    Code:
    'Own Method
    Private Sub MySub()
       'DoSomething
       Command1_Click
    End Sub
    
    'Event of a Button
    Private Sub Command1_Click()
       'DoSomethingElse
    End Sub
    Last edited by Zvoni; Tomorrow at 31:69 PM.
    ----------------------------------------------------------------------------------------

    One System to rule them all, One Code to find them,
    One IDE to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    Code is like a joke: If you have to explain it, it's bad

  3. #3

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by Zvoni View Post
    I don't understand your "whether the user or other code fired the event"
    In your example it's the user firing it (actually: it still "hidden" code firing it)
    Hmmm, no, in my example it's code firing it:

    Code:
    
        mbSettingMyCheckbox = True
        chkMyCheckbox.Value = MyCheckboxValueFromCode ' <--- That's code!!!
        mbSettingMyCheckbox = False
    
    
    Now, we can contrast that with the user taking their mouse, moving it to the chkMyCheckbox control, and then clicking. That would be user interaction firing the change event.

    I do think that's clear. However, I did make a small change to my language in the OP, hopefully making it even more clear.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  4. #4
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: User action versus code causing event to raise

    I would never code that like
    all the buttons will always call another function

    Private Sub Command1_Click()
    Call Function or Call Class.Function
    End Sub

    if I need a value I would instead get it directly from that function

    Value = GetValue()
    Value = Class.GetValue

    that why Command1_Click will always be a user-action.

    also,
    why not make the Command/CheckBox disabled when the user can not use it?


    another thing.
    since I work with "games", I only have 1 area for all the hundreds of "virtual" buttons, checkboxes, captions, lists etc.
    that is giving me total control of the user, I can decide what works and not.
    I assume its possible to do something similar here,
    that all buttons, would call a "master-functions"
    examples:

    Private Sub Command1_Click()
    MasterFunction "Click", "Command1", "Flags"
    End Sub

    and inside MasterFunction I can decide how things works for everything.
    if you make an array for all the buttons, it will not create that much more code.
    Last edited by baka; Dec 1st, 2021 at 11:16 AM.

  5. #5

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by baka View Post
    I would never code that like
    all the buttons will always call another function

    Private Sub Command1_Click()
    Call Function or Call Class.Function
    End Sub

    if I need a value I would instead get it directly from that function
    So, if existing data (such as something coming out of a database) determines the initial value of the CheckBox, how do you set it? But, if a user changing it requires additional action (such as possibly saving the change back into the database), how do you handle that?

    Quote Originally Posted by baka View Post
    why not make the Command/CheckBox disabled when the user can not use it?
    Yes, I quite often do precisely that. However, that's somewhat a different issue. That's only the recursion addendum I added. And also, often, things get so complex that it's just easier to not worry about whether the control is enabled or not, and to just check things in the change (click, whatever) event. And that's certainly more bullet-proof than trying to keep track of what should be enabled or not.

    Anyway, this is getting off into the weeds. I was really hoping for ideas on how to actually do this. I haven't really thought it all through, but it seems there may be a way to make a call that tells us whether the last event was raised from code or user interaction.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  6. #6

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Here, I'll outline the specific situation on which I'm working. The red circled CheckBox is a new feature I'm adding to this form:

    Name:  Spine.jpg
Views: 291
Size:  55.6 KB

    Now, when the user comes into this form, there can be one of two situations: 1) They're starting to analyze newly collected data, or 2) They're re-analyzing data that's already been analyzed.

    If they're re-analyzing, that "NoBoxFlexionDone" setting (from that CheckBox) will be saved in the database record, and must be set to that setting when they come back in.

    Otherwise, if it's a new analysis, that CheckBox is set the last way the user set it from when they last analyzed new data.

    As you can see, it gets a bit complex, but there are clear rules.

    Now, the problem comes in where, if it's a new analysis and the user changes the status of that CheckBox, I've got to save that change for the next time a new analysis is performed. However, if it's a re-analysis of data, I don't change that "default" CheckBox status. So, there are several situations I've got to keep track of.

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

    Anyway, it still boils down to what I outlined in the OP (or, at least that's a part of it, the part I was trying to focus on in this thread).
    Last edited by Elroy; Dec 1st, 2021 at 11:37 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    4,417

    Re: User action versus code causing event to raise

    Ah…. Ok, i think i got it now.
    But, AFAIK, not possible, since an event (in your case click on checkbox) is basically just a callback-function executed in the underlying c-code, and as with each callback you have an unchangeable signature that procedure must adhere to.
    the only thing i can think of would be to subclass the checkbox, and do some test what window-messages arrive for your different scenarios (value set by user, value coming from database).
    I’m thinking here looking out for WM_BUTTONUP or some such. If it‘s there, then a user clicked, if it‘s missing, probably from database

    EDIT: don‘t remember anymore, but does a checkbox has a MouseDown/Up-Event?
    if yes, why not put your user-interaction there?
    if value comes from db, it would fire click, but click would be empty (or whatever other code)
    Last edited by Zvoni; Dec 1st, 2021 at 11:48 AM.
    Last edited by Zvoni; Tomorrow at 31:69 PM.
    ----------------------------------------------------------------------------------------

    One System to rule them all, One Code to find them,
    One IDE to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    Code is like a joke: If you have to explain it, it's bad

  8. #8
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: User action versus code causing event to raise

    as I wrote, a master-function

    all buttons/checkboxes would (if they are in an array)
    call the master-function,
    that way u only need to add 1 time the "if=exit sub" thingy.
    instead of each one and makes it look ugly.

    also, I would create a class, where everything happens inside, instead of inside each checkbox.

    but, the best solution is to continue doing what u have, If mbSettingMyCheckbox Then Exit Sub
    not sure how much work it would be to "move" everything in a class.

  9. #9

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by Zvoni View Post
    Ah…. Ok, i think i got it now.
    But, AFAIK, not possible, since an event (in your case click on checkbox) is basically just a callback-function executed in the underlying c-code, and as with each callback you have an unchangeable signature that procedure must adhere to.
    the only thing i can think of would be to subclass the checkbox, and do some test what window-messages arrive for your different scenarios (value set by user, value coming from database)
    Yeah, I thought about subclassing too. However, I don't think I'm up for subclassing every control I'd need to do this on. Also, there are probably about a dozen or so situations for which I do subclassing, and, as of now, they're all either cosmetic or not absolutely essential to correct functioning of the code. I'd hate to make "correct functioning" contingent upon some subclassing. I suppose there already is another situation where "correct functioning" is contingent upon subclassing, but it's buried down in a custom user control.

    Hmmm, I suppose I could make custom UCs where I wanted to do this. That isn't the worst of ideas. Maybe make two events: 1) TheControl_Click_FromUser, and 2) TheControl_Click_FromCode. IDK, I'll have to think about that.

    I'm still wondering if I can just build some kind of thread-hook that tells me what the last user action was. IDK, it's still very much in the "brainstorming" phase in my head.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  10. #10
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    4,417

    Re: User action versus code causing event to raise

    See my edit
    you could even go with baka‘s master-function passing a flag as a local argument (an Enum maybe). In the master-function it would be a Select Case against the Enum
    Last edited by Zvoni; Tomorrow at 31:69 PM.
    ----------------------------------------------------------------------------------------

    One System to rule them all, One Code to find them,
    One IDE to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    Code is like a joke: If you have to explain it, it's bad

  11. #11

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    I'm certainly not opposed to creating a class that gets attached to each of these controls (where I want this). I'm not sure I see how that helps though, at least not at this time.

    (Just one class, but instantiated for each control I want this on.)
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  12. #12

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by Zvoni View Post
    you could even go with baka‘s master-function passing a flag as a local argument (an Enum maybe). In the master-function it would be a Select Case against the Enum
    Yeah, maybe I'm just now seeing the point that baka is making. I'm still not sure I see how that's really solving the issue. Without subclassing, when the user clicks the CheckBox, it's still going to raise the Click event, and I might need to do something if it's the user who clicked it. And, whether it's some function I call, or just done like the code in the OP, I've still got to change the CheckBox value from code, and, in those cases, not do what I'll do if the user clicked it.

    Creating a procedure to set the CheckBox is just burying the problem deeper in code, but not solving it.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  13. #13
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    5,872

    Re: User action versus code causing event to raise

    Quite annoying that for example Check1.Value = vbChecked fires the Click() event.
    That's why I've a have boolean variable m_bSelf in each form
    Almost every event does an Exit Sub if m_bSelf = True
    The first line in the Form_Load is m_bSelf = True and the last line is m_bSelf = False
    Also when calling routines which load data from whatever source, first set the variable, update control values then set it back to false.

  14. #14

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by Arnoutdv View Post
    Quite annoying that for example Check1.Value = vbChecked fires the Click() event.
    That's why I've a have boolean variable m_bSelf in each form
    Almost every event does an Exit Sub if m_bSelf = True
    The first line in the Form_Load is m_bSelf = True and the last line is m_bSelf = False
    Also when calling routines which load data from whatever source, first set the variable, update control values then set it back to false.
    Arnoutdv, that's precisely the point I'm making. And I often do precisely that.

    However, in my present situation, it's even more complex than that, depending on whether I'm analyzing new data or re-analyzing old data (which can change without ever leaving the form, see the "test numbers").

    But yeah, you get it.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  15. #15
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: User action versus code causing event to raise

    that is why you have a master-function

    everything is going through the master-function
    u could have a "stop"
    like

    - u click button1
    - button1 calls master-function
    - inside master-function, for that particular button1, u want to get the value from Checkbox1
    - you set "ForceStop=True"
    - get value from CheckBox1
    - CheckBox1 will trigger click, and will call the master-function as well, but if ForceStop = True it will not continue
    - now, when all the code is done for button1, you set ForceStop = False to allow the user to do whatever.

    now u can click anything again.
    so, the ForceStop will only be active inside the function u have in the master-function.

    that way u only need 1 condition, not 1 for each click/mouseup/down/move etc for each buttons/checkboxes etc.

    the master-function can be created in many ways.
    u could send the entire control, or just an "ID" to tell what is what.

    master-function is only used for those buttons/checkboxes that have this issue.

  16. #16
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: User action versus code causing event to raise

    I think you are talking about some very low volume events. So low the performance isn't an issue.

    So while they're a little clunky, being String, the Tag property of controls can be used to manage event handling suppression. Then you don't need any extra flags with Form scope.

    Since we don't have expando properties for controls hosted in a Form that's about all we can do. I wouldn't recommend other things that would work, for example repurposing the UseMaskColor property of many controls which is free to exploit when a control's Style is non-graphical. That would probably just be confusing.

  17. #17

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by dilettante View Post
    I think you are talking about some very low volume events. So low the performance isn't an issue.

    So while they're a little clunky, being String, the Tag property of controls can be used to manage event handling suppression. Then you don't need any extra flags with Form scope.

    Since we don't have expando properties for controls hosted in a Form that's about all we can do. I wouldn't recommend other things that would work, for example repurposing the UseMaskColor property of many controls which is free to exploit when a control's Style is non-graphical. That would probably just be confusing.
    Dil, the Tag property (or maybe borrowing some other property) isn't the worst of ideas. At least they're specific to the control, and I don't have to clutter up my module-level code with these flags. And yeah, I'm not worried about anything related to performance. No loops here.

    However, I still have to attend to "setting" it (and "unsetting" it) when changing a ComboBox's value within code.

    I was just hoping there was some call I could make (or maybe setup a hooked thread monitor that could be called) such that I could make the determination solely within the actual Click event.

    I'm doing okay regarding the modification I'm presently working on ... but this is a recurring problem for me, and it'd be nice to have an elegant solution.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  18. #18
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,531

    Re: User action versus code causing event to raise

    What about using the .Tag property? Just before you set the checkbox value, set the .Tag to a known value... then set the checkbox.... then in the event of the checkbox, check the .Tag property, if it's your predetermined value, bail... if not, continue. And then I look up and see Dill has suggested something similar. It's probably the route I'd go in this case.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  19. #19

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    You know? I think this thing might be doable. At first, I thought of EbMode, but I've never been able to get that to be useful except for Add-Ins. However, then I got to thinking about the IDEs Call-Stack button.

    That Call-Stack button certainly has the answer. If we create a Check1, and then put the following code in:

    Code:
    Private Sub Check1_Click()
        Stop
    End Sub
    And then click our IDE's Call-Stack button, we have the answer. So, maybe the answer is somewhere in the VBA6.dll?

    Hmmm, at least it's something to look into. At the present, I've got no idea how to get the call-stack from code.

    Just an FYI, whatever I come up with has to work when compiled too.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  20. #20
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: User action versus code causing event to raise

    I think the behavior is hard-wired at a pretty low level within the underlying Win32 controls.

    Code:
    Option Explicit
    
    Private Const BM_SETCHECK As Long = &HF1&
    
    Private Enum BUTTON_STATES
        BST_UNCHECKED = &H0
        BST_CHECKED = &H1
        BST_INDETERMINATE = &H2
        BST_PUSHED = &H4
        BST_FOCUS = &H8
    End Enum
    
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
        ByVal hWnd As Long, _
        ByVal wMsg As Long, _
        ByVal wParam As Long, _
        ByVal lParam As Long) As Long
    
    Private Sub Check1_Click()
        Debug.Print "Click"
    End Sub
    
    Private Sub cmdCheckIt_Click()
        SendMessage Check1.hWnd, BM_SETCHECK, BST_CHECKED, 0
    End Sub
    
    Private Sub cmdUncheckIt_Click()
        SendMessage Check1.hWnd, BM_SETCHECK, BST_UNCHECKED, 0
    End Sub
    The BN_CLICK notice always occurs for BM_SETCHECK and there is nothing in the notification or the WM_COMMAND message to tell you the source.

    This isn't a VB6 thing, it's a Windows thing.

  21. #21
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: User action versus code causing event to raise

    another thing. why use "click"?
    why not Mouse_Down/Up? as Zvoni suggested.

  22. #22

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by baka View Post
    another thing. why use "click"?
    why not Mouse_Down/Up? as Zvoni suggested.
    My users do occasionally use the keyboard for navigation. So that starts to feel like more work than I'm already doing. IDK, I'm just getting hard-headed about a call that's named something like: EventRaisedByCodeOrUser() that returns vbRaisedByCode or vbRaisedByUser.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  23. #23

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    I thought I was onto something with the GetCallStackCount call within the vba6.dll, but it returns 1& in both cases. Hmmm.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  24. #24
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: User action versus code causing event to raise

    This kind of problem is exactly why I'm such a huge fan of data classes and why I also love the concept of separating UI from business logic. If I were doing this, this entire process would be controlled by a class. Here's an example:-
    Code:
    'Intenal value
    Private g_skipFlex As Boolean
    
    Public Sub LoadData()
        ''' Loads data including setting the SkipFlexion property internally
    End Sub
    
    Public Property Get SkipFlexion() As Boolean
         SkipFlexion = g_skipFlex
    End Property
    
    Public Property Let SkipFlexion(ByVal value As Boolean)
        ''' Performs internal tests for conditions that would
        ''' allow us to change this. If changing it is allowed then the
        ''' change will be allowed if not, it will silently fail and not change
    End Property
    The above would be a part of a data class and it would relate to a CheckBox like this:-
    Code:
    Private g_data As New MyData
    
    Private Sub Form_Load()
          
        g_data.LoadData
        
        UpdateUI
    End Sub
    
    
    Private Sub Check1_Click()
        g_data.SkipFlexion = CBool(Check1.value)
        
        UpdateUI
    End Sub
    
    'This function is responsible for syncing the UI with the
    'actual data
    Private Sub UpdateUI()
        Check1.value = IIf(g_data.SkipFlexion, 1, 0)
    End Sub
    This arrangement makes the problem more manageable. The real problem here is not about detecting how the CheckBox was changed, it is about whether that change is allowed under certain conditions. That has nothing to do with the UI and should be separated from UI logic. The UI only cares about displaying what the data currently is, not controlling how and when it should be changed.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  25. #25

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    So Dil, with your info in post #20, it doesn't look like subclassing would do any good. A fancy thread hook (monitoring both mouse and keyboard) could probably do it, but that seems like a rough way to go.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  26. #26

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by Niya View Post
    The real problem here is not about detecting how the CheckBox was changed, it is about whether that change is allowed under certain conditions. That has nothing to do with the UI and should be separated from UI logic. The UI only cares about displaying what the data currently is, not controlling how and when it should be changed.
    Niya, that's sometimes true, but it's actually not true in my present case. In this case, the user is always allowed to click/change the checkbox.

    As stated above, there are two conditions you can be in on that above form: 1) You're processing new data, 2) You're re-processing already once-processed data. And those conditions can change without ever leaving the form.

    Code:
    So, when loading the form, we do the following:
    * Examine data to see if we've already processed:
            Yes: Set value for CheckBox from data.
            No: Set value for CheckBox from a "default value".
    
    The USER changes value of Checkbox:
        Are we re-processing already processed data:
            Yes: Save new CheckBox value with data.
            No: Save new CheckBox value as the new "default value" and also save with data if/when data is saved.
    So, in this case, it really is all about whether it's code or user changing value.
    Last edited by Elroy; Dec 1st, 2021 at 01:47 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  27. #27
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: User action versus code causing event to raise

    hold on
    what about this:

    MouseDown
    MouseUp

    and

    KeyPress
    KeyRelease

    those u can get from subclassing

    when MouseDown or KeyPress u set "UserEvent=True"
    when MouseUp or KeyRelease u set "UserEvent=False"

    sure its not perfect,
    but should work most of the time.

    the UserEvent boolean will mostly be false.

    to make it even more accurate, u can check the hwnd (its parents)
    and if its your form, u know for sure its a click/press inside your form.

    (u can use SetWindowsHookEx and PeekMessage as well, if normal subclassing will not work)
    Last edited by baka; Dec 1st, 2021 at 01:54 PM.

  28. #28

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by baka View Post
    hold on
    what about this:

    MouseDown
    MouseUp

    and

    KeyPress
    KeyRelease

    those u can get from subclassing

    when MouseDown or KeyPress u set "UserEvent=True"
    when MouseUp or KeyRelease u set "UserEvent=False"

    sure its not perfect,
    but should work most of the time.

    the UserEvent boolean will mostly be false.

    to make it even more accurate, u can check the hwnd (its parents)
    and if its your form, u know for sure its a click/press inside your form.
    Not bad, baka. I'm actually on a tablet right now, eating lunch. I'll play around with that when I get back to my development computer. I could even use some WithEvents and get that done with a class attached to the CheckBox. That might work.

    EDIT: Hmmm, I'm still having to create an instantiation (a variable) for each control on which I want to do this. This takes me back to a custom UC, to make it clean. That might be the answer.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  29. #29
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: User action versus code causing event to raise

    Quote Originally Posted by Elroy View Post
    Niya, that's sometimes true, but it's actually not true in my present case. In this case, the user is always allowed to click/change the checkbox.

    As stated above, there are two conditions you can be in on that above form: 1) You're processing new data, 2) You're re-processing already once-processed data. And those conditions can change without ever leaving the form.

    Code:
    So, when loading the form, we do the following:
    * Examine data to see if we've already processed:
            Yes: Set value for CheckBox from data.
            No: Set value for CheckBox from a "default value".
    
    The USER changes value of Checkbox:
        Are we re-processing already processed data:
            Yes: Save new CheckBox value with data.
            No: Save new CheckBox value as the new "default value" and also save with data if/when data is saved.
    So, in this case, it really is all about whether it's code or user changing value.
    Hmm. I must be missing something then because even so I don't see a need to ever care about anything on the UI:-
    Code:
    'Intenal value
    Private g_skipFlex As Boolean
    
    Public Sub LoadData()
    '* Examine data to see if we've already processed:
    '        Yes: Set value for SkipFlexion from data.
    '        No: Set value for SkipFlexion from a "default value".
    
    End Sub
    
    Public Property Get SkipFlexion() As Boolean
         SkipFlexion = g_skipFlex
    End Property
    
    Public Property Let SkipFlexion(ByVal value As Boolean)
    
    '    Are we re-processing already processed data:
    '        Yes: Save new SkipFlexion value with data.
    '        No: Save new SkipFlexion value as the new "default value" and also save with data if/when data is saved.
    
    End Property
    The UI logic I posted before would remain unchanged.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  30. #30
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: User action versus code causing event to raise

    I have one question. What determines if it's a new analysis or a re-analysis? Is it something on the Form or something else entirely outside of the program?
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  31. #31
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: User action versus code causing event to raise

    Quote Originally Posted by Elroy View Post
    Now, the problem comes in where, ...
    if it's a new analysis and the user changes the status of that CheckBox,
    I've got to save that change for the next time a new analysis is performed.

    ...if it's a re-analysis of data, I don't change that "default" CheckBox status.
    That's exactly where ADO (with its DataBinding-capabilities) would be of great assistance...
    By using such a Binding-approach, you will not need "any Events".
    (I'm aware you are using DAO to talk with your DB, but ADO could be used in parallel with a fabricated ADO-Rs)

    Here's what this would look like in an empty, virginal Project.

    Into Form1 (which needs a Control Check1 on it, nothing more):
    Code:
    Option Explicit
    
    Public Sub ShowWithBinding(BindingRs As Object, Caption)
      Me.Caption = Caption
      
      'ensure the Binding to the externally sitting DataSource-Rs
      Set Check1.DataSource = BindingRs: Check1.DataField = "ChkState"
      
      Me.Show vbModal
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
      CallByName Check1.DataSource, "Move", VbMethod, 0 'enforce Control->Rs synchronization, before saving
      
      SaveCheckStateToDB 'call the module-defined save-function
    End Sub
    As you see in the above code, we do not use any Check1-Events.

    Now ensure that the Project will start from Sub Main() - and put the following into a Module:
    Code:
    Option Explicit
    
    Private RsDefNew As Object, RsReEval As Object
    
    Sub Main()
     'initial run of the Form, passing RsDefNew along
      Set RsDefNew = CreateBindingRs(ReadCheckStateFromDB)
      Form1.ShowWithBinding RsDefNew, "Def-New-Mode"
     
          'now show the Form for re-evaluation, passing RsReEval along to set state
          Set RsReEval = CreateBindingRs(ReadCheckStateFromDB) 'on first run, init the value from the DB
          Form1.ShowWithBinding RsReEval, "Re-Eval-Mode"
          'again show the Form for re-evaluation, passing RsReEval along to not lose the state of the last re-eval-run
          Form1.ShowWithBinding RsReEval, "Re-Eval-Mode"
    
      'and finally a last run, again passing RsDefNew along
      Form1.ShowWithBinding RsDefNew, "Def-New-Mode"
    End Sub
    
    Function CreateBindingRs(ByVal ChkState As Boolean) As Object 'ADODB.Recordset
      Set CreateBindingRs = CreateObject("ADODB.Recordset")
          CreateBindingRs.Fields.Append "ChkState", vbBoolean
          '...put more Binding-Fields here, if you want to bind more than a single Control to such an Rs
          CreateBindingRs.Open
      CreateBindingRs.AddNew Array(0), Array(ChkState)
    End Function
    
    Public Sub SaveCheckStateToDB() 'we save only the State of RsDefNew (not the state of RsReEval)
      SaveSetting "TestApp", "TestSection", "TestKey", RsDefNew!ChkState
    End Sub
    Public Function ReadCheckStateFromDB() As Boolean
      ReadCheckStateFromDB = GetSetting("TestApp", "TestSection", "TestKey", True)
    End Function
    HTH

    Olaf

  32. #32

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by Niya View Post
    I have one question. What determines if it's a new analysis or a re-analysis? Is it something on the Form or something else entirely outside of the program?
    Whether or not a database record exists for the analysis. Also, just FYI, that database record now has an added field that is the saved state of that CheckBox, which is where it's saved. The "default" is saved elsewhere (global to the program).
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  33. #33

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Ok, I actually did manage to get something working. Not sure if I'll actually use it or not. We'll see.

    Project is attached, but here's the code. It's based on the idea of a custom UC. (I didn't expose every single property of a CheckBox, but I did expose the ones I typically use.)

    Here's the code for a UC named CheckBoxEx with a single CheckBox on it (named chk) and a Timer on it (named tmr), that's it:
    Code:
    
    Option Explicit
    '
    Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
    Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long
    Private cFreq As Currency
    Private dKeyMouseTime As Double
    Private dClickTime As Double
    '
    Event ClickFromUser()
    Event ClickFromCode()
    '
    
    Private Sub UserControl_Initialize()
        QueryPerformanceFrequency cFreq
        tmr.Enabled = False
        tmr.Interval = 5& ' 0.005 seconds.  This MUST be slower than the Abs(dKeyMouseTime - dClickTime) check.
    End Sub
    
    Private Function PreciseTiming() As Double
        ' Returns seconds, a double, with high-precision.
        Dim cValue As Currency
        QueryPerformanceCounter cValue
        PreciseTiming = cValue / cFreq  ' The division will return a double, and it also cancels out the Currency decimal points.
    End Function
    
    
    
    Private Sub chk_KeyUp(KeyCode As Integer, Shift As Integer)
        dKeyMouseTime = PreciseTiming
    End Sub
    
    Private Sub chk_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
        dKeyMouseTime = PreciseTiming
    End Sub
    
    Private Sub chk_Click()
        ' On keyboard events, the KeyUp happens before Click,
        ' BUT, on mouse events, the Click happens before MouseUp,
        ' So, we just use a fast timer for both.
        dClickTime = PreciseTiming
        tmr.Enabled = True
    End Sub
    
    Private Sub tmr_Timer()
        tmr.Enabled = False
        Debug.Print Abs(dKeyMouseTime - dClickTime)
        If Abs(dKeyMouseTime - dClickTime) < 0.001 Then ' This MUST be at least enough time for both UI events (..Up & Click) to fire.
            RaiseEvent ClickFromUser                    ' On my computer, this timing is ~0.0002 seconds.
        Else
            RaiseEvent ClickFromCode
        End If
    End Sub
    
    
    
    
    
    Public Property Get Alignment() As AlignmentConstants:      Alignment = chk.Alignment:      End Property
    Public Property Get Appearance() As Long:                   Appearance = chk.Appearance:    End Property
    Public Property Get BackColor() As OLE_COLOR:               BackColor = chk.BackColor:      End Property
    Public Property Get Caption() As String:                    Caption = chk.Caption:          End Property
    Public Property Get Enabled() As Boolean:                   Enabled = chk.Enabled:          End Property
    Public Property Get Font() As Font:                     Set Font = chk.Font:                End Property
    Public Property Get ForeColor() As OLE_COLOR:               ForeColor = chk.ForeColor:      End Property
    Public Property Get Value() As CheckBoxConstants:           Value = chk.Value:              End Property
    
    
    Public Property Let Alignment(prop As AlignmentConstants):      chk.Alignment = prop:   PropertyChanged "Alignment":    End Property
    Public Property Let Appearance(prop As Long):                   chk.Appearance = prop:  PropertyChanged "Appearance":   End Property
    Public Property Let BackColor(prop As OLE_COLOR):               chk.BackColor = prop:   PropertyChanged "BackColor":    End Property
    Public Property Let Caption(prop As String):                    chk.Caption = prop:     PropertyChanged "Caption":      End Property
    Public Property Let Enabled(prop As Boolean):                   chk.Enabled = prop:     PropertyChanged "Enabled":      End Property
    Public Property Set Font(prop As Font):                     Set chk.Font = prop:        PropertyChanged "Font":         End Property
    Public Property Let ForeColor(prop As OLE_COLOR):               chk.ForeColor = prop:   PropertyChanged "ForeColor":    End Property
    Public Property Let Value(prop As CheckBoxConstants):           chk.Value = prop:       PropertyChanged "Value":        End Property
    
    
    
    Private Sub UserControl_Resize() ' Keep sub-controls the same size as the UserControl.
        chk.Top = 0: chk.Left = 0: chk.Width = Width: chk.Height = Height
    End Sub
    
    Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
        chk.Alignment = PropBag.ReadProperty("Alignment", vbLeftJustify)
        chk.Appearance = PropBag.ReadProperty("Appearance", 1&)
        chk.BackColor = PropBag.ReadProperty("BackColor", &H8000000F)
        chk.Caption = PropBag.ReadProperty("Caption", vbNullString)
        chk.Enabled = PropBag.ReadProperty("Enabled", True)
        Set chk.Font = PropBag.ReadProperty("Font", chk.Font)
        chk.ForeColor = PropBag.ReadProperty("ForeColor", &H80000012)
        chk.Value = PropBag.ReadProperty("Value", vbUnchecked)
    End Sub
    
    Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
        PropBag.WriteProperty "Alignment", chk.Alignment, vbLeftJustify
        PropBag.WriteProperty "Appearance", chk.Appearance, 1&
        PropBag.WriteProperty "BackColor", chk.BackColor, &H8000000F
        PropBag.WriteProperty "Caption", chk.Caption, vbNullString
        PropBag.WriteProperty "Enabled", chk.Enabled, True
        PropBag.WriteProperty "Font", chk.Font
        PropBag.WriteProperty "ForeColor", chk.ForeColor, &H80000012
        PropBag.WriteProperty "Value", chk.Value, vbUnchecked
    End Sub
    
    
    
    And here's some test code in a Form1 (with CheckBoxEx1 on it, and a Command1 on it):
    Code:
    
    Option Explicit
    
    Private Sub CheckBoxEx1_ClickFromCode()
        Debug.Print "ClickFromCode"
    End Sub
    
    Private Sub CheckBoxEx1_ClickFromUser()
        Debug.Print "ClickFromUser"
    End Sub
    
    Private Sub Command1_Click()
        If CheckBoxEx1.Value = vbChecked Then
            CheckBoxEx1.Value = vbUnchecked
        Else
            CheckBoxEx1.Value = vbChecked
        End If
    End Sub
    
    
    Again, test project is attached.

    IDK, I can't break it. It does have some timings in it though. I don't think there's a race condition, but there might be.

    EDIT: I also like this because there is not subclassing and there are no hooks. All straight-up VB6.
    Attached Files Attached Files
    Last edited by Elroy; Dec 1st, 2021 at 03:49 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  34. #34

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Quote Originally Posted by Schmidt View Post
    That's exactly where ADO (with its DataBinding-capabilities) would be of great assistance...
    Yeah, and I can do data binding with the DAO as well.

    This might be one of those areas where I have an irrational aversion to doing things a certain way. I'm not totally sure why, but I have a strong aversion to ever binding controls to a data source.

    In the past, I've just found that it severely limits certain flexibilities that I'm not willing to sacrifice, so I've just developed a habit of never doing it.

    Thanks for the idea though.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  35. #35

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    CAUTION: I rewrote this (see post #38) in a way that doesn't need the timings. I'd recommend using that version, and not the one in this post if you wish to use this.

    Arghhh, I did some testing, and my timings are all over the place. Specifically, the time between a MouseUp and Click, or a KeyUp and Click.

    In fact, once in a while, they climb over 0.001, which is where I have it set.

    Here's the code I used to test the timings ... just a Form1 with a single CheckBox (Check1) on it.

    You can either "click" it, or "tap the space bar" to test the timings. If others would want to test this and report their timings, that would be much appreciated.


    (Just Form1 with a single Check1 on it.)
    Code:
    
    Option Explicit
    '
    Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
    Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long
    Private cFreq As Currency
    Private dKeyTime As Double
    Private dMouseTime As Double
    Private dClickTime As Double
    '
    
    Private Sub Form_Initialize()
        QueryPerformanceFrequency cFreq
    End Sub
    
    Private Function PreciseTiming() As Double
        ' Returns seconds, a double, with high-precision.
        Dim cValue As Currency
        QueryPerformanceCounter cValue
        PreciseTiming = cValue / cFreq  ' The division will return a double, and it also cancels out the Currency decimal points.
    End Function
    
    Private Sub Check1_KeyUp(KeyCode As Integer, Shift As Integer)
        dKeyTime = PreciseTiming
    End Sub
    
    Private Sub Check1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
        dMouseTime = PreciseTiming
        If dKeyTime < dMouseTime And Abs(dMouseTime - dClickTime) < 0.1 Then Debug.Print Format$(Abs(dMouseTime - dClickTime), "0.000000")
    End Sub
    
    Private Sub Check1_Click()
        ' On keyboard events, the KeyUp happens before Click,
        ' BUT, on mouse events, the Click happens before MouseUp,
        ' So, we just use a fast timer for both.
        dClickTime = PreciseTiming
        If dKeyTime > dMouseTime And Abs(dKeyTime - dClickTime) < 0.1 Then Debug.Print Format$(Abs(dKeyTime - dClickTime), "0.000000")
    End Sub
    
    
    
    Last edited by Elroy; Dec 2nd, 2021 at 10:07 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  36. #36
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: User action versus code causing event to raise

    Elroy: Here's another suggestion I use:

    #If kDEBUGON Then
    Debug.Print "Begin BlankProc"
    #End If

    Some Code

    # If DEBUGON Then
    Debug.Print "End BlankProc"
    #End If
    One can set a conditional variable of whatever name in Project Properties > Compile > Conditional Compilation Arguments.
    The name can very. So one can use a different name based on the Scope of interest.
    For example DEBUGON could be DEBUGCHK for checkboxes.

    HTH

    ==========================
    This is what I get with your code in VB5
    ==========================
    0.000024 Checked
    0.000023 Unchecked

    ============================
    I'm sure you're aware of this, but if Not in IDE
    ============================
    If one errors, and goes to the Call Stack, if one double clicks
    any of the list entries, one will jump Not only to that Procedure,
    but the line from which the Call was made.
    Last edited by vb6forever; Dec 2nd, 2021 at 06:00 AM.

  37. #37
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,721

    Re: User action versus code causing event to raise

    I tried GetMem/PutMem API (HScroll1)
    I was able to Get and Set the value using ObjPtr() + 232/234

    this is for HScroll (and VScroll)

    Code:
    Private Declare Sub PutMem2 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Integer)
    
    Sub ChangeValueForScroll(ctr As Control, ByVal value As Integer)
        Dim ctrPointer&
    
        ctrPointer = ObjPtr(ctr)
        PutMem2 ctrPointer + 232, value 
        PutMem2 ctrPointer + 234, value 
        ctr.value = value
    End Sub
    ChangeValueForScroll HScroll1, 8176
    MsgBox HScroll1.value

    and I get the value 8176, without triggering "Change"
    ctr.value = value, will "refresh" the component without triggering "change", so the bar will move to the right value but, since its already the same value it will not trigger "change"
    now Im not sure if 232/234 will work on all computers

    edit: did some more testing with CheckBox and I found 224 is changing from 0 to 8.
    but it will trigger a click event when I try to update it using ctr.value =. so no good.
    need more understanding why it triggers the click event.

    edit: for OptionButton it works:

    Code:
    Private Declare Sub PutMem1 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Byte)
    
    Sub ChangeValueForOption(ctr As Control, ByVal value As Boolean)
        Dim ctrPointer&
    
        ctrPointer = ObjPtr(ctr)
        PutMem1 ctrPointer + 224, CByte(IIf(value, 32, 0))
        ctr.value = value
    End Sub
    ChangeValueForOption Option1, True
    Last edited by baka; Dec 2nd, 2021 at 08:46 AM.

  38. #38

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: User action versus code causing event to raise

    Ok, my mind is clearly not as clever as it once was. I don't need all those "timing" things in my new UC. Since I'm wrapping my CheckBox in this UC, I've got Get/Let properties for Value, so I know precisely when it's the user versus code. I'm embarrassed that this didn't dawn on me before.

    Here's the new UC code that does it perfectly (no timings needed). I also decided to pass-through all the mouse and keyboard events since I'm not using them for this detection, and I might use them in the main code.

    The new UC code:
    Code:
    
    Option Explicit
    '
    Event ClickFromUser()   ' New event, to detect when USER changes Value.
    Event ClickFromCode()   ' New event, to detect when CODE changes Value (doesn't fire if code sets Value but isn't changing it).
    Event Click()           ' This is just a passthrough of the standard click event.
    '
    Event KeyDown(KeyCode As Integer, Shift As Integer)
    Event KeyPress(KeyAscii As Integer)
    Event KeyUp(KeyCode As Integer, Shift As Integer)
    Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Event MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Event MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    '
    Dim mbSettingValueFromCode As Boolean
    '
    
    Public Property Get Value() As CheckBoxConstants
        Value = chk.Value
    End Property
    Public Property Let Value(prop As CheckBoxConstants)
        mbSettingValueFromCode = True
        chk.Value = prop
        mbSettingValueFromCode = False
        PropertyChanged "Value"
    End Property
    
    Private Sub chk_Click()
        RaiseEvent Click        ' We just always raise this one.  It'll work as the typical CheckBox does.
        '
        ' And now to differentiate how it was generated.
        If mbSettingValueFromCode Then
            RaiseEvent ClickFromCode
        Else
            RaiseEvent ClickFromUser
        End If
    End Sub
    
    
    
    
    Public Property Get Alignment() As AlignmentConstants:      Alignment = chk.Alignment:      End Property
    Public Property Get Appearance() As Long:                   Appearance = chk.Appearance:    End Property
    Public Property Get BackColor() As OLE_COLOR:               BackColor = chk.BackColor:      End Property
    Public Property Get Caption() As String:                    Caption = chk.Caption:          End Property
    Public Property Get Enabled() As Boolean:                   Enabled = chk.Enabled:          End Property
    Public Property Get Font() As Font:                     Set Font = chk.Font:                End Property
    Public Property Get ForeColor() As OLE_COLOR:               ForeColor = chk.ForeColor:      End Property
    
    
    Public Property Let Alignment(prop As AlignmentConstants):      chk.Alignment = prop:   PropertyChanged "Alignment":    End Property
    Public Property Let Appearance(prop As Long):                   chk.Appearance = prop:  PropertyChanged "Appearance":   End Property
    Public Property Let BackColor(prop As OLE_COLOR):               chk.BackColor = prop:   PropertyChanged "BackColor":    End Property
    Public Property Let Caption(prop As String):                    chk.Caption = prop:     PropertyChanged "Caption":      End Property
    Public Property Let Enabled(prop As Boolean):                   chk.Enabled = prop:     PropertyChanged "Enabled":      End Property
    Public Property Set Font(prop As Font):                     Set chk.Font = prop:        PropertyChanged "Font":         End Property
    Public Property Let ForeColor(prop As OLE_COLOR):               chk.ForeColor = prop:   PropertyChanged "ForeColor":    End Property
    
    
    
    Private Sub chk_KeyDown(KeyCode As Integer, Shift As Integer):  RaiseEvent KeyDown(KeyCode, Shift):     End Sub
    Private Sub chk_KeyPress(KeyAscii As Integer):                  RaiseEvent KeyPress(KeyAscii):          End Sub
    Private Sub chk_KeyUp(KeyCode As Integer, Shift As Integer):    RaiseEvent KeyUp(KeyCode, Shift):       End Sub
    
    Private Sub chk_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single):   RaiseEvent MouseDown(Button, Shift, X, Y):  End Sub
    Private Sub chk_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single):   RaiseEvent MouseMove(Button, Shift, X, Y):  End Sub
    Private Sub chk_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single):     RaiseEvent MouseUp(Button, Shift, X, Y):    End Sub
    
    
    
    Private Sub UserControl_Resize() ' Keep sub-controls the same size as the UserControl.
        chk.Top = 0: chk.Left = 0: chk.Width = Width: chk.Height = Height
    End Sub
    
    Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
        chk.Alignment = PropBag.ReadProperty("Alignment", vbLeftJustify)
        chk.Appearance = PropBag.ReadProperty("Appearance", 1&)
        chk.BackColor = PropBag.ReadProperty("BackColor", &H8000000F)
        chk.Caption = PropBag.ReadProperty("Caption", vbNullString)
        chk.Enabled = PropBag.ReadProperty("Enabled", True)
        Set chk.Font = PropBag.ReadProperty("Font", chk.Font)
        chk.ForeColor = PropBag.ReadProperty("ForeColor", &H80000012)
        chk.Value = PropBag.ReadProperty("Value", vbUnchecked)
    End Sub
    
    Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
        PropBag.WriteProperty "Alignment", chk.Alignment, vbLeftJustify
        PropBag.WriteProperty "Appearance", chk.Appearance, 1&
        PropBag.WriteProperty "BackColor", chk.BackColor, &H8000000F
        PropBag.WriteProperty "Caption", chk.Caption, vbNullString
        PropBag.WriteProperty "Enabled", chk.Enabled, True
        PropBag.WriteProperty "Font", chk.Font
        PropBag.WriteProperty "ForeColor", chk.ForeColor, &H80000012
        PropBag.WriteProperty "Value", chk.Value, vbUnchecked
    End Sub
    
    
    
    Simple Form1 (with CheckBoxEx1 and Command1) code for testing:
    Code:
    
    Option Explicit
    
    Private Sub CheckBoxEx1_Click()
        Debug.Print "Typical Click ... same as before"
    End Sub
    
    Private Sub CheckBoxEx1_ClickFromCode()
        Debug.Print "ClickFromCode"
    End Sub
    
    Private Sub CheckBoxEx1_ClickFromUser()
        Debug.Print "ClickFromUser"
    End Sub
    
    Private Sub Command1_Click()
        If CheckBoxEx1.Value = vbChecked Then
            CheckBoxEx1.Value = vbUnchecked
        Else
            CheckBoxEx1.Value = vbChecked
        End If
    End Sub
    
    
    And, the test project (with above code) is attached.

    I'm quite happy with this solution, and I'm going to call this one resolved.

    Also, just as an FYI, these ideas (specifically the two new events, ClickFromUser & ClickFromCode) could easily be implemented in Krool's version if I so desired.

    Another also ... I'll probably implement these ideas into an OptionButton and a TextBox (and maybe others), but I'll let people work those things out on their own.
    Attached Files Attached Files
    Last edited by Elroy; Dec 2nd, 2021 at 10:12 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  39. #39
    New Member
    Join Date
    Oct 2021
    Posts
    10

    Re: User action versus code causing event to raise

    Quote Originally Posted by Elroy View Post
    So, if existing data (such as something coming out of a database) determines the initial value of the CheckBox, how do you set it? But, if a user changing it requires additional action (such as possibly saving the change back into the database), how do you handle that?
    What I typically use is a form-level variable:

    Code:
    Private m_isLoading As Boolean
    When the form is opening, I'll set it to True, so when data comes from the database and sets the form controls, the event handlers won't run.

    Code:
    Private Sub Button1_Click()
    
        If m_isLoading = False Then
            ' do stuff that only applies when a user initiates the action
        End If
    
    End Sub
    After all data is loaded and the form is displayed, I'll set it to False. You may have a more complex set of requirements that don't apply to "all controls' event handlers" however.

  40. #40

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: [RESOLVED] User action versus code causing event to raise

    HardCode, yeah, that's where I started. But some of my forms are quite complex (see post #6 for one that's far from the worst).

    Sometimes I'll have several CheckBoxes or OptionButtons that change their function differently based on other form configurations. I was just looking for a way to bury the module-level variable down deeper in the code, and my custom UC does precisely that. Done with a UC, I can do it on several controls (possibly in different ways) all on the same form, without cluttering up my module level code with a bunch of variables.

    Also, probably a good 50% of my controls are already custom UCs, so I've got no problem adding this functionality to them.

    EDIT: Just an FYI, this is one of my favorite UCs ... an OptionButton that has a GroupNum property and doesn't require different containers to have different "groupings" of them. I make tremendous use of that one, and adding the above functionality to it would be trivial.
    Last edited by Elroy; Dec 2nd, 2021 at 04:37 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width