DetectStatusBar Events

Share your advanced PureBasic knowledge/code with the community.
QuimV
Enthusiast
Enthusiast
Posts: 337
Joined: Mon May 29, 2006 11:29 am
Location: BARCELONA - SPAIN

DetectStatusBar Events

Post by QuimV »

Code updated For 5.20+

Hello,

Could anybody help me in order to detect the StatusBar events?

Here it is an example from fsw, but if we add a TreeGadget, the detection goes wrong.

Code: Select all

; Example Of A Statusbar Click Event
; (c) 2003 - By FSW
;
; Tested under WinXP
; do whatever you want with it
;
#Window = 10
#StatusbarFocus = 528
#StatusBar = 1
#Tree = 2

Procedure  LoWord (var)
  ProcedureReturn var & $FFFF
EndProcedure


Procedure MyWindowCallback(WindowID, Message, wParam, lParam)
  Result = #PB_ProcessPureBasicEvents
  
  wParamLo = LoWord(wParam)
  lParamLo = LoWord(lParam)
  
  ;513 = $201
  
  If Message = #StatusbarFocus ;#StatusbarFocus  ;528 = $210 = #WM_PARENTNOTIFY
    If wParamLo = #WM_LBUTTONDOWN And lParamLo < 270 ; 270 is the width of field 1
      MessageRequester("Message", "Left Mouse Click In StatusBar Field 1. "+"MousePos: "+Str(lParamLo))
    ElseIf wParamLo = 513 And lParamLo > 270 + 2 ; there is a BAR between the 2 fields...
      MessageRequester("Message", "Left Mouse Click In StatusBar Field 2. "+"MousePos: "+Str(lParamLo))
    ElseIf wParamLo = 516
      MessageRequester("Message", "Right Mouse Click In StatusBar. "+"MousePos: "+Str(lParamLo))
    EndIf
    
  EndIf
  
  ProcedureReturn Result
EndProcedure


If OpenWindow(#Window,0,0,355,180,"Statusbar Click",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  
  CreateStatusBar(#StatusBar, WindowID(#Window))
  AddStatusBarField(90)
  
  StatusBarText(#StatusBar, 0, "Hello World!")
  AddStatusBarField(270)
  AddStatusBarField(80)
  
  TreeGadget(#Tree,10,45,100,100,#PB_Tree_AlwaysShowSelection)
  SendMessage_(GadgetID(#Tree),$111D,0,14675967)
  
  
  SetWindowCallback(@MyWindowCallback())
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  
EndIf


Thanks in advanced.

QuimV
QuimV
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8452
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Looks like a message is getting processed as a statusbar click that shouldn't be. Other childwindows can generate #wm_parentnotify messages. You can always add a quick check to make sure the active child window is the status bar:

Code: Select all

; Example Of A Statusbar Click Event 
; (c) 2003 - By FSW 
; 
; Tested under WinXP 
; do whatever you want with it 
; 
#Window = 10 
#StatusbarFocus = 528 
#StatusBar = 1 
#Tree = 2 

Global Statusbar

Procedure.l  LoWord (var.l) 
  ProcedureReturn var & $FFFF 
EndProcedure 

Procedure MyWindowCallback(WindowID, Message, wParam, lParam) 
  Result = #PB_ProcessPureBasicEvents 

  wParamLo = LoWord(wParam) 
  lParamLo = LoWord(lParam) 

  ;513 = $201 

    If Message = #StatusbarFocus ;#StatusbarFocus  ;528 = $210 = #WM_PARENTNOTIFY 
      If ChildWindowFromPoint_(WindowID(#Window),WindowMouseX(#Window),WindowMouseY(#Window)) = Statusbar
        If wParamLo = #WM_LBUTTONDOWN And lParamLo < 270 ; 270 is the width of field 1 
          MessageRequester("Message", "Left Mouse Click In StatusBar Field 1. "+"MousePos: "+Str(lParamLo)) 
        ElseIf wParamLo = 513 And lParamLo > 270 + 2 ; there is a BAR between the 2 fields... 
          MessageRequester("Message", "Left Mouse Click In StatusBar Field 2. "+"MousePos: "+Str(lParamLo)) 
        ElseIf wParamLo = 516 
          MessageRequester("Message", "Right Mouse Click In StatusBar. "+"MousePos: "+Str(lParamLo)) 
        EndIf 
      EndIf 
    EndIf
  
  ProcedureReturn Result 
EndProcedure 

If OpenWindow(#Window,0,0,355,180,"Statusbar Click",#PB_Window_SystemMenu|#PB_Window_ScreenCentered) 
  If CreateGadgetList(WindowID(#Window))    
   Statusbar = CreateStatusBar(#StatusBar, WindowID(#Window)) 
    StatusBarText(#StatusBar, 0, "Hello World!") 
      AddStatusBarField(270) 
      AddStatusBarField(80) 
      
    TreeGadget(#Tree,10,45,100,100,#PB_Tree_AlwaysShowSelection) 
      SendMessage_(GadgetID(#Tree),$111D,0,14675967) 
  EndIf    
    
  SetWindowCallback(@MyWindowCallback()) 
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow 
    
EndIf 
A global var and ChildWindowFromPoint seems the most efficient solution as #WM_PARENTNOTIFY messages don't carry the childwindow identifier with them for buttondown events.

A somewhat cleaner solution imho would be to subclass the statusbar and then its callback is only catching events for it and there's no need to test for the right childwindow. I have to go out right now for a couple hours but I can post code for that if nobody beats me to it in the meantime.
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8452
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Here is the subclassed version, I think it's much cleaner this way:

Code: Select all

#Window = 10 
#StatusBar = 1 
#Tree = 2 

Global OldStatusBar

Procedure.l  LoWord (var.l) 
  ProcedureReturn var & $FFFF 
EndProcedure 

Procedure SubClassedStatusBar(hwnd, msg, wParam, lParam) 
  result = CallWindowProc_(OldStatusBar, hwnd, msg, wparam, lparam) 
  lParamLo = LoWord(lParam) 
  Select msg 
    Case #WM_LBUTTONDOWN 
      If lParamLo < 270 ; 270 is the width of field 1 
        MessageRequester("Message", "Left Mouse Click In StatusBar Field 1. "+"MousePos: "+Str(lParamLo)) 
      ElseIf lParamLo > 270 + 2 ; there is a BAR between the 2 fields... 
        MessageRequester("Message", "Left Mouse Click In StatusBar Field 2. "+"MousePos: "+Str(lParamLo)) 
      EndIf
    Case #WM_RBUTTONDOWN
      MessageRequester("Message", "Right Mouse Click In StatusBar. "+"MousePos: "+Str(lParamLo)) 
  EndSelect
  ProcedureReturn Result 
EndProcedure 

If OpenWindow(#Window,0,0,355,180,"Statusbar Click",#PB_Window_SystemMenu|#PB_Window_ScreenCentered) 
  If CreateGadgetList(WindowID(#Window))    
    StatusBar = CreateStatusBar(#StatusBar, WindowID(#Window)) 
    StatusBarText(#StatusBar, 0, "Hello World!") 
      AddStatusBarField(270) 
      AddStatusBarField(80) 
    TreeGadget(#Tree,10,45,100,100,#PB_Tree_AlwaysShowSelection) 
    SendMessage_(GadgetID(#Tree),$111D,0,14675967) 
  EndIf    
    
  OldStatusBar = SetWindowLong_(StatusBar, #GWL_WNDPROC, @SubclassedStatusBar()) 
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow 
    
EndIf 
BERESHEIT
BarryG
Addict
Addict
Posts: 4312
Joined: Thu Apr 18, 2019 8:17 am

Re: DetectStatusBar Events

Post by BarryG »

Updated netmaestro's code to work with the latest PureBasic:

Code: Select all

#Window=10
#StatusBar=1

Global StatusBarProc

Procedure SubClassedStatusBar(hWnd,Msg,wParam,lParam)
  result=CallWindowProc_(StatusBarProc,hWnd,Msg,wParam,lParam)
  lParamLo=lParam & $FFFF
  Select Msg
    Case #WM_LBUTTONDOWN
      If lParamLo<100 ; 100 is the width of field 1 
        MessageRequester("Message","Left Mouse Click In StatusBar Field 1. "+"MousePos: "+Str(lParamLo)) 
      ElseIf lParamLo>100+2 And lParamLo<270 ; there is a BAR between the 2 fields... 
        MessageRequester("Message","Left Mouse Click In StatusBar Field 2. "+"MousePos: "+Str(lParamLo)) 
      EndIf
    Case #WM_RBUTTONDOWN
      MessageRequester("Message","Right Mouse Click In StatusBar. "+"MousePos: "+Str(lParamLo)) 
  EndSelect
  ProcedureReturn Result 
EndProcedure 

If OpenWindow(#Window,0,0,355,180,"Statusbar Click",#PB_Window_SystemMenu|#PB_Window_ScreenCentered) 
  StatusBar=CreateStatusBar(#StatusBar,WindowID(#Window)) 
  AddStatusBarField(100) 
  StatusBarText(#StatusBar,0,"Field 1") 
  AddStatusBarField(270) 
  StatusBarText(#StatusBar,1,"Field 2") 
  
  StatusBarProc=SetWindowLongPtr_(StatusBar,#GWL_WNDPROC,@SubclassedStatusBar()) 
  
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow 
  
EndIf 
User avatar
jacdelad
Addict
Addict
Posts: 2062
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: DetectStatusBar Events

Post by jacdelad »

If I'm not wrong, usually Windows controls react on button up. So button up events should be more "natural"?
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/2*DX517, 164TB+82TB+28TB+2TB SSD
User avatar
mk-soft
Always Here
Always Here
Posts: 6512
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: DetectStatusBar Events

Post by mk-soft »

Why not as in the Code Questions already solved.
Only adapted with query of the StatusBarID (Handle).

Code: Select all

; Self made clickable statusbar 
; written by Axolotl 
; 
Procedure WinCallback(Hwnd, UMsg, WParam, LParam) 
  Protected field, *nmm.NMMOUSE 

  Select UMsg 
    Case #WM_NOTIFY
        *nmm = LParam 
        If *nmm\hdr\hwndFrom = StatusBarID(0)
          field = *nmm\dwItemSpec   ; zero-based index of the fields 
          ; field is -2 for an undefined area as field :) 
          Select *nmm\hdr\code 
            Case #NM_CLICK    : Debug "Left Click on " + field 
            Case #NM_DBLCLK   : Debug "Left Double Click on " + field 
            Case #NM_RCLICK   : Debug "Right Click on " + field 
            Case #NM_RDBLCLK  : Debug "Right Double Click on " + field 
          EndSelect
        EndIf
  EndSelect 
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 

If OpenWindow(0, 100, 150, 300, 100, "PureBasic - StatusBar Example", #PB_Window_SystemMenu | #PB_Window_SizeGadget)

  If CreateStatusBar(0, WindowID(0))
    AddStatusBarField(100)
    AddStatusBarField(50)
    AddStatusBarField(100)
  EndIf

  StatusBarText(0, 0, "Area 1")
  StatusBarText(0, 1, "Area 2", #PB_StatusBar_BorderLess)
  StatusBarText(0, 2, "Area 3", #PB_StatusBar_Right | #PB_StatusBar_Raised)

  SetWindowCallback(@WinCallback(), 0) 
  Repeat
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
BarryG
Addict
Addict
Posts: 4312
Joined: Thu Apr 18, 2019 8:17 am

Re: DetectStatusBar Events

Post by BarryG »

mk-soft wrote: Tue Jan 20, 2026 12:28 pmWhy not as in the Code Questions already solved
Because as I said there:
BarryG wrote:See also netmaestro's code here, which shows the mouse X position in any field
So, some extra useful functionality if you want to click a specific position in a StatusBar field. ;)
Post Reply