Page 1 of 1

How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 6:22 am
by TI-994A
The PostEvent() function is able to include some data with its custom event:
PureBasic Manual wrote:EventData()
Return value: If the current event isn't a custom event sent with PostEvent(), this value is undefined.
Is there a way to determine if EventData() has been defined?

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 6:51 am
by infratec
For what you need this?

If you have a custom event , you have your own 'endpoint' in the eventloop, then you can ask for this value.
If it is a 'normal' PB event, you should not use eventdata. Maybe it is already used by the PB events.

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 7:05 am
by TI-994A
infratec wrote: Wed Sep 04, 2024 6:51 amIf it is a 'normal' PB event, you should not use eventdata. Maybe it is already used by the PB events.
Hi Bernd. Yes, maybe. Although I don't suppose so.

The documentation expressly mentions the use of the PostEvent() function with PureBasic events as well; with no caveats.

The data would be useful to differentiate between system-initiated events and user-posted ones.

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 9:01 am
by mk-soft
Normally you use your own custom events.
For standard events, eventdata is null

Code: Select all

;-TOP

#ProgramTitle = "Main Window"
#Version = "v1.01.1"

Enumeration Windows
  #Main
EndEnumeration

Enumeration Menus
  #MainMenu
EndEnumeration

Enumeration MenuItems
  #MainMenuExitApplication
EndEnumeration

Enumeration Gadgets
  
EndEnumeration

Enumeration Status
  #MainStatusBar
EndEnumeration

Global ExitApplication

; ----

; ---- String Helper ----
  
  Procedure AllocateString(String.s) ; Result = Pointer
    Protected *mem.string = AllocateStructure(String)
    If *mem
      *mem\s = String
    EndIf
    ProcedureReturn *mem
  EndProcedure
  
  Procedure.s FreeString(*mem.string) ; Result String
    Protected r1.s
    If *mem
      r1 = *mem\s
      FreeStructure(*mem)
    EndIf
    ProcedureReturn r1
  EndProcedure
  
  ; ----
  
Procedure DoEventCloseWindow()
  Protected window = EventWindow()
  Protected *pdata = EventData()
  Protected text.s
  
  If *pdata = 0
    Debug "Do any before event close window ..."
    PostEvent(#PB_Event_CloseWindow, window, 0, 0, AllocateString("Do Close Window Event 2"))
  Else
    text = FreeString(*pdata)
    Debug text
    ExitApplication = #True
  EndIf
  
EndProcedure

Procedure UpdateWindow()
  Protected dx, dy
  dx = WindowWidth(#Main)
  dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
  ; Resize gadgets
  
EndProcedure

; ----

Procedure Main()
  Protected dx, dy

  #MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
  
  If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, #ProgramTitle , #MainStyle)
    ; Menu
    CreateMenu(#MainMenu, WindowID(#Main))
    MenuTitle("File")
    MenuItem(#MainMenuExitApplication, "E&xit")
    ; For Mac
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
      If Not IsMenu(#MainMenu)
        CreateMenu(#MainMenu, WindowID(#Main))
      EndIf
      MenuItem(#PB_Menu_About, "")
      MenuItem(#PB_Menu_Preferences, "")
    CompilerEndIf
    ; StatusBar  
    CreateStatusBar(#MainStatusBar, WindowID(#Main))
    AddStatusBarField(#PB_Ignore)
    StatusBarText(#MainStatusBar, 0, " " + #Version)
    ; Gadgets
    dx = WindowWidth(#Main)
    dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
    
    ; Bind events
    BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
    BindEvent(#PB_Event_CloseWindow, @DoEventCloseWindow(), #Main, 0)
    
    ; Main loop
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          ;ExitApplication = #True
          
        Case #PB_Event_Menu
          Select EventMenu()
            CompilerIf #PB_Compiler_OS = #PB_OS_MacOS   
              Case #PB_Menu_About
                MessageRequester("Info", #ProgramTitle + " " + #Version)
                
              Case #PB_Menu_Preferences
                
              Case #PB_Menu_Quit
                ;ExitApplication = #True
                PostEvent(#PB_Event_CloseWindow, #Main, 0))
                
            CompilerEndIf
              
            Case #MainMenuExitApplication
              ;ExitApplication = #True
              PostEvent(#PB_Event_CloseWindow, #Main, 0)
              
          EndSelect
          
        Case #PB_Event_Gadget
          Select EventGadget()
            
          EndSelect
          
      EndSelect
      
    Until ExitApplication
    
  EndIf
  
EndProcedure : Main()

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 10:25 am
by TI-994A
mk-soft wrote: Wed Sep 04, 2024 9:01 am For standard events, eventdata is null...

Code: Select all

Procedure DoEventCloseWindow()
  Protected window = EventWindow()
  Protected *pdata = EventData()
  Protected text.s
  
  If *pdata = 0
    Debug "Do any before event close window ..."
    PostEvent(#PB_Event_CloseWindow, window, 0, 0, AllocateString("Do Close Window Event 2"))
  Else
    text = FreeString(*pdata)
    Debug text
    ExitApplication = #True
  EndIf
  
EndProcedure

Hi @mk-soft, and thanks for the example. However, this is not always the case.

Code: Select all

; *********************************************
;
;   EventData() not null with native events
;
;   tested on Windows, macOS, and Linux
;   with PureBasic x32 & x64 versions
;
; *********************************************

window = OpenWindow(#PB_Any, 100, 100, 600, 300,
                    "PureBasic PostEvent() Function", 
                    #PB_Window_SystemMenu | 
                    #PB_Window_ScreenCentered)
canvas = CanvasGadget(#PB_Any, 10, 10, 580, 240)
output = StringGadget(#PB_Any, 10, 260, 580, 30, "")
AddWindowTimer(window, 0, 5000)

MessageRequester("PostEvent() Example", 
                 "Timer will simulate a left-click " +
                 "on the canvas gadget every 5 seconds. " +
                 "Manually left-click on the canvas gadget " +
                 "to see the value returned by EventData().")

Repeat
  event = WaitWindowEvent()   
  Select event
      
    Case #PB_Event_CloseWindow
      appQuit = #True
      
    Case #PB_Event_Timer
      PostEvent(#PB_Event_Gadget, window, canvas, #PB_EventType_LeftClick, 
                @"Timer-initiated left-click on canvas gadget!")
      
    Case #PB_Event_Gadget
      If EventGadget() = canvas        
        *eData = EventData()
        If EventType() = #PB_EventType_LeftClick
          If *eData
            eData.s = PeekS(*eData)
          Else
            eData.s = "User-initiated left-click on canvas gadget!"                                            
          EndIf 
          timeStamp.s = FormatDate("%hh:%ii:%ss", Date())
          SetGadgetText(output, timeStamp + ": " + eData + " (EventData() = " + *eData +")")
        EndIf          
      EndIf      
      
  EndSelect  
Until appQuit

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 12:22 pm
by Axolotl
Hi TI-994A,

I can only agree with the previous witers.
IMHO the correct value must be documented for pb events. Otherwise, I would not rely on (random values).
For my own events, I always use ZERO as undefined by definition. In exceptional cases also -1.

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 12:40 pm
by spikey
TI-994A wrote: Wed Sep 04, 2024 10:25 am However, this is not always the case.
But what you are doing in this case is turning a system event into a custom event by using #PB_EventType_LeftClick as an argument to PostEvent. By then specifying the data parameter too you're distorting both of these facilities slightly from their originally conceived purpose. There's always the possibility of unforeseen consequences in this sort of situation.

I'd be thinking about a fully custom event in this sort of circumstance.

It might be worth a feature request that standard events reset the EventData() value though...

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 12:57 pm
by TI-994A
Axolotl wrote: Wed Sep 04, 2024 12:22 pm...I always use ZERO as undefined by definition. In exceptional cases also -1.
Sure; but EventData() is not returning 0 or -1 for some of the native PureBasic events. As demonstrated in my example.

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 12:58 pm
by TI-994A
spikey wrote: Wed Sep 04, 2024 12:40 pm...turning a system event into a custom event by using #PB_EventType_LeftClick as an argument to PostEvent. By then specifying the data parameter too you're distorting both of these facilities slightly from their originally conceived purpose.
PureBasic Manual wrote:PostEvent()
Syntax: Result = PostEvent(Event [, Window, Object [, Type [, Data]]])
PureBasic allows the use of their own native events and event types in the PostEvent() function. This would be most useful for simulating UI events.

Nevertheless, in my example, the PostEvent() function (with the native event, event type, and custom data) is working well, without issue. It is the system-triggered event that is causing the issue; where its EventData() is not null when it should be.

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 4:42 pm
by Demivec
TI-994A wrote: Wed Sep 04, 2024 12:58 pm
spikey wrote: Wed Sep 04, 2024 12:40 pm...turning a system event into a custom event by using #PB_EventType_LeftClick as an argument to PostEvent. By then specifying the data parameter too you're distorting both of these facilities slightly from their originally conceived purpose.
PureBasic Manual wrote:PostEvent()
Syntax: Result = PostEvent(Event [, Window, Object [, Type [, Data]]])
PureBasic allows the use of their own native events and event types in the PostEvent() function. This would be most useful for simulating UI events.

Nevertheless, in my example, the PostEvent() function (with the native event, event type, and custom data) is working well, without issue. It is the system-triggered event that is causing the issue; where its EventData() is not null when it should be.
I would think it may actually be in an undefined state. If the event is not acustom one you don't try to interpret the EventData(). If it is a custom event you would interpret it in accordance with that events specification.

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 4:54 pm
by Fred
The canvas use the 'Data' field of the event to pass an object to a structure to get more info later (like MouseX, MouseY, etc.). It's not a warranty than the EventData() will be null for all PB events, it's only valid when documented. In EventData(), it's written:

"Get the data associated with the current event. The event needs to be a custom event sent with PostEvent()."

we may be could add more precision:

"Get the data associated with the current event. The event needs to be a custom event (not a native PureBasic event) sent with PostEvent()."

Re: How to check if EventData() is defined?

Posted: Wed Sep 04, 2024 5:18 pm
by TI-994A
Fred wrote: Wed Sep 04, 2024 4:54 pm...It's not a warranty than the EventData() will be null for all PB events, it's only valid when documented...
Alright; good to know, Fred. Thank you for chiming in and confirming the matter. :D

Perhaps best to tweak the descriptions in both the PostEvent() and EventData() entries of the manual to reflect this.