Subclassing a window

Sujets variés concernant le développement en PureBasic
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Subclassing a window

Message par Progi1984 »

Dans ce post,
http://forums.purebasic.com/english/vie ... hp?t=15090

elchoni me conseille de 'subclassing the window' mais je ne connais pas cette technique, quelqu'un peut m'aider ?
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Le subclassing est un moyen d'interfacer notre propre procédure avant l'appel de la procédure de traitement originale et ainsi pouvoir intervenir sur des messages auxquelles on aurait pas accès.

En voici un exemple que j'avais posté:

Code : Tout sélectionner

Procedure NouvelleProc( hWnd, Msg,  wParam, lParam) 
  ;Ici on récupère l'adresse d'origine de la procédure grâce à la 
  ;chaine qui l'identifie: "OriginProc" et le handle de la fenêtre 
  ;voir la fonction SetProp. 
  OriginProc.l= GetProp_(hWnd, "OriginProc") 
  Select Msg 
    Case #wm_char 
      If wParam=$0D 
        ;Simulation de la touche Tab 
        keybd_event_($09, 0, 0, 0) 
        keybd_event_($09, 0, #KEYEVENTF_KEYUP, 0) 
        ProcedureReturn 0 
      EndIf 
  EndSelect 
  ;On renvoie tous les autres évènements à la procédure d'origine. 
  ProcedureReturn CallWindowProc_(OriginProc,hWnd,Msg,wParam,lParam) 
EndProcedure    

If OpenWindow(0,0,0,322,275,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"StringGadget Flags") And CreateGadgetList(WindowID(0)) 
  StringGadget(0,8, 10,306,20,"Normal StringGadget...") 
  StringGadget(1,8, 35,306,20,"1234567",#PB_String_Numeric) 
  StringGadget(2,8, 60,306,20,"Readonly StringGadget",#PB_String_ReadOnly) 
  
  ;Avec cette fonction, on récupère l'adresse d'origine de la procédure 
  ;pour ensuite la restituer, une fois le traitement terminé. 
  OriginProc = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @NouvelleProc()) 
  
  ;Cette fonction est très utile car elle permet d'associer une nouvelle donnée 
  ;à n'importe quelles fenêtres crées en utlisant une chaine de caractère pour 
  ;l'identification; ça évite d'utiliser une valeur globale. 
  ;Ici on associe la valeur OriginProc identifiée par la chaine "OriginProc" 
  ;au StringGadget 
  SetProp_(GadgetID(0), "OriginProc", OriginProc) 
  
  Repeat 
    EventID = WaitWindowEvent() 
    Select EventID 
      Case  #PB_EventGadget 
        Select EventGadgetID() 
          Case 0 
            Debug "Normal StringGadget" 
            
        EndSelect 
        
      Case #WM_CLOSE 
        ;Supprimer avant fermeture du programme la donnée associée à la fenêtre. 
        RemoveProp_(GadgetID(0),"OriginProc") 
        Quit=1 
        
    EndSelect 
    
  Until Quit=1 
EndIf 
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Merci nico pour ton exemple, je ne connaissais pas SetProp_(...), GetProp_(...), RemoveProp_(...)
C'est en fait une simplification de ce genre de code

Code : Tout sélectionner

          Addr = GlobalAlloc_(#GMEM_FIXED,8) 
          OldCB = SetWindowLong_(hBouton,#GWL_WNDPROC,@BoutonRX14_CallBack()) 
          PokeL(Addr,OldCB) 
          PokeL(Addr+4,number) 
          SetWindowLong_(hBouton,#GWL_USERDATA,Addr) 
qui peut s'écrire

Code : Tout sélectionner

          OldCB = SetWindowLong_(hBouton,#GWL_WNDPROC,@BoutonRX14_CallBack()) 
          SetProp_(hBouton, "OldCB", OldCB)
          SetProp_(hBouton,"number", number)
C'est bien ça nico ?
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

Oui, pour moi ça revient à ça.

:)
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Je suis comme erix14,
je ne connaissais pas SetProp_(...), GetProp_(...), RemoveProp_(...)

Merci Nico
gansta93
Messages : 1448
Inscription : jeu. 26/févr./2004 11:17
Localisation : Le Village
Contact :

Message par gansta93 »

Salut,

Cool ! :-D Mais comment intégrer ça dans une lib ?
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

Je viens de lire ce post et je vois une question sans réponse ^^
à partir du code de nico je t'ai fait un exemple "général"

Code : Tout sélectionner

Declare WindowCallback(WindowID.l, Message.l, wParam.l, lParam.l)
Declare WindowSetMinMaxSize(WindowID.l, MinW.l, MinH.l, MaxW.l, MaxH.l)
Declare MinMax(Value.l, OldValue.l)

Procedure WindowCallback(WindowID.l, Message.l, wParam.l, lParam.l)
  Protected WndProc.l, Result.l, *MinMax.MinMaxInfo
  
  If Message = #WM_GetMinMaxInfo
    
    *MinMax = lParam
    *MinMax\ptMinTrackSize\x = MinMax(GetProp_(WindowID, "MinTrackWidth"),  *MinMax\ptMinTrackSize\x)
    *MinMax\ptMinTrackSize\y = MinMax(GetProp_(WindowID, "MinTrackHeight"), *MinMax\ptMinTrackSize\y)
    *MinMax\ptMaxTrackSize\x = MinMax(GetProp_(WindowID, "MaxTrackWidth"),  *MinMax\ptMaxTrackSize\x)
    *MinMax\ptMaxTrackSize\y = MinMax(GetProp_(WindowID, "MaxTrackHeight"), *MinMax\ptMaxTrackSize\y)
    
  EndIf
  
  WndProc = GetProp_(WindowID, "WndProc")
  If WndProc
    Result = CallWindowProc_(WndProc, WindowID, Message, wParam, lParam)
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure WindowSetMinMaxSize(WindowID.l, MinW.l, MinH.l, MaxW.l, MaxH.l)
  Protected WndProc.l
  
  SetProp_(WindowID, "MinTrackWidth",  MinW)
  SetProp_(WindowID, "MinTrackHeight", MinH)
  SetProp_(WindowID, "MaxTrackWidth",  MaxW)
  SetProp_(WindowID, "MaxTrackHeight", MaxH)
  
  If GetProp_(WindowID, "WndProc") = #Null
    WndProc = SetWindowLong_( WindowID, #GWL_WndProc, @WindowCallback() )
    SetProp_(WindowID, "WndProc", WndProc)
  EndIf
EndProcedure

Procedure MinMax(Value.l, OldValue.l)
  If Value <= 0
    Value = OldValue
  EndIf
  ProcedureReturn Value
EndProcedure

OpenWindow(0, 0, 0, 480, 360, #PB_Window_MinimizeGadget|#PB_Window_Sizegadget, "MinMax")
WindowSetMinMaxSize(WindowID(0), 320, 240, 640, 480)

OpenWindow(1, 100, 100, 400, 300, #PB_Window_MinimizeGadget|#PB_Window_Sizegadget, "Min")
WindowSetMinMaxSize(WindowID(1), 320, 240, 0, 0)

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
en gros dans ta lib tu auras la fonction callback (que l'utilisateur n'est pas censé connaître) et la fonction WindowSetMinMaxSize qu'il pourra utiliser autant de fois qu'il voudra pour autant de fenêtre...

Dri ;)
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Une petite question au passage : puisque tu parles de userlibs, est il possible de créer plusieurs callbacks pour une meme fenetre ?
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

plusieurs callback, pourquoi pas ? mais l'intérêt c'est zéro...
avec une callback tu gères toutes les fenêtres concernées et tous les messages que tu veux...

Dri ;)
gansta93
Messages : 1448
Inscription : jeu. 26/févr./2004 11:17
Localisation : Le Village
Contact :

Message par gansta93 »

Ah OK, je comprand... merci. :-D
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Disons que par exemple, j'ai un callback qui active ceci et un autre qui active cela. Comment faire pour en lancer un des deux ou les deux avec un seul callback ?
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

bah je te ferais un exemple de code dès que j'ai le temps ;)

Dri
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Bah Merci Dri ;)
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

voila un exemple avec deux fonctions pour une seule callback...

Code : Tout sélectionner

Declare WindowCallback(WindowID.l, Message.l, wParam.l, lParam.l)

Declare WindowSetMinMaxSize(WindowID.l, MinW.l, MinH.l, MaxW.l, MaxH.l)
Declare WindowLockPosition(WindowID.l, x.w, y.w)

Declare MinMax(Value.l, OldValue.l)

Procedure WindowCallback(WindowID.l, Message.l, wParam.l, lParam.l)
  Protected WndProc.l, Result.l, *MinMax.MinMaxInfo, *Pos.WindowPos, x.l, y.l
  
  If Message = #WM_GETMINMAXINFO
    
    *MinMax = lParam
    *MinMax\ptMinTrackSize\x = MinMax(GetProp_(WindowID, "MinTrackWidth"),  *MinMax\ptMinTrackSize\x)
    *MinMax\ptMinTrackSize\y = MinMax(GetProp_(WindowID, "MinTrackHeight"), *MinMax\ptMinTrackSize\y)
    *MinMax\ptMaxTrackSize\x = MinMax(GetProp_(WindowID, "MaxTrackWidth"),  *MinMax\ptMaxTrackSize\x)
    *MinMax\ptMaxTrackSize\y = MinMax(GetProp_(WindowID, "MaxTrackHeight"), *MinMax\ptMaxTrackSize\y)
    
  ElseIf Message = #WM_WINDOWPOSCHANGING
    
    *Pos = lParam
    x = GetProp_(WindowID, "PositionLockX")
    y = GetProp_(WindowID, "PositionLockY")
    
    If x & $10000 : *Pos\x = x & $FFFF : EndIf
    If y & $10000 : *Pos\y = y & $FFFF : EndIf
    
  EndIf
 
  WndProc = GetProp_(WindowID, "WndProc")
  If WndProc
    Result = CallWindowProc_(WndProc, WindowID, Message, wParam, lParam)
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure WindowSetMinMaxSize(WindowID.l, MinW.l, MinH.l, MaxW.l, MaxH.l)
  Protected WndProc.l
 
  SetProp_(WindowID, "MinTrackWidth",  MinW)
  SetProp_(WindowID, "MinTrackHeight", MinH)
  SetProp_(WindowID, "MaxTrackWidth",  MaxW)
  SetProp_(WindowID, "MaxTrackHeight", MaxH)
 
  If GetProp_(WindowID, "WndProc") = #Null
    WndProc = SetWindowLong_( WindowID, #GWL_WNDPROC, @WindowCallback() )
    SetProp_(WindowID, "WndProc", WndProc)
  EndIf
EndProcedure

Procedure WindowLockPosition(WindowID.l, x.w, y.w)
  Protected WndProc.l, xx.l, yy.l
 
  If x >= 0 : xx = $10000 | x : EndIf
  If y >= 0 : yy = $10000 | y : EndIf
  
  SetProp_(WindowID, "PositionLockX" ,xx)
  SetProp_(WindowID, "PositionLockY" ,yy)
 
  If GetProp_(WindowID, "WndProc") = #Null
    WndProc = SetWindowLong_( WindowID, #GWL_WNDPROC, @WindowCallback() )
    SetProp_(WindowID, "WndProc", WndProc)
  EndIf
EndProcedure

Procedure MinMax(Value.l, OldValue.l)
  If Value <= 0
    Value = OldValue
  EndIf
  ProcedureReturn Value
EndProcedure

OpenWindow(0, 0, 0, 480, 360, #PB_Window_MinimizeGadget|#PB_Window_SizeGadget, "MinMax + Lock")
WindowSetMinMaxSize(WindowID(0), 320, 240, 640, 480)
WindowLockPosition(WindowID(0), #PB_Default, 0)

OpenWindow(1, 400, 100, 400, 300, #PB_Window_MinimizeGadget|#PB_Window_SizeGadget, "Min")
WindowSetMinMaxSize(WindowID(1), 320, 240, #Null, #Null)

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
si la propriété n'existe pas, la fonction GetProp_() renvoie 0... donc faut s'arranger si c'est un long pour que 0 soit une valeur incorrecte... Ou alors on peut pointer vers une structure LONG si toutes les valeurs sont acceptées...

Dri
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Ptite question à quoi sert getProp_(), Setprop_() ?
Répondre