Umbenennen im TreeGadget() mit PopupMenu()

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
Spirit
Beiträge: 174
Registriert: 13.04.2005 19:09

Umbenennen im TreeGadget() mit PopupMenu()

Beitrag von Spirit »

Ich habe letztens diesen Code gefunden, der zeigt wie man ein TreeGadget() dazu bringt, dass man die Einträge umbenennen kann. Das ganze funktioniert auch super. Ich möchte aber noch ein PopupMenu einbauen, in dem dann ein 'Umbennen' Item ist (so wie z.B. im Windows Explorer). Ich weiß aber jetzt nicht, wie ich das TreeGadget() dazu bringe, dass er den aktuellen Eintrag zu dem Eingabefeld umwandelt, damit man den Eintrag dann editieren kann. Mir kam bis jetzt die Idee ein SendMessage_(hWnd_TreeGadget, #WM_LButtonDown, bla, bla) zu machen, um einen Mausklick zu 'simulieren', doch dazu müsste ich die Koordinaten des Items kennen. Oder gibts da vielleicht eine andere Message? Kann mir damit jemand helfen? Danke schonmal im vorraus!

Hier ist noch der Source:

Code: Alles auswählen

; ---------------------------------------------------------------------
; How to make TreeGadget Items Editable by the User
; by Timo Harter
; ---------------------------------------------------------------------
;
; By implementing this in your Program, the User can edit the Items
; of a TreeGadget by first right-clicking, and then left-clicking on it.
; (just like in Windows-Explorer) 
;
; This is just a skeleton, how it is done, but it should be easy to 
; understand, and implement in your own Programs.
; ---------------------------------------------------------------------


; This Constant will be needed:

#TVS_EDITLABELS = 8  ; The Window Style for Label Editing

; We'll need a Callback procedure for that. (If you never used one, don't be afraid, 
; it's not that hard.). I'll just declare it here, the Procedure will be further down.

Declare Callback(Window.l, Message.l, wParam.l, lParam.l)

; First, we'll just create a Window, and a a TreeGadget.

OpenWindow(0, 0, 0, 200, 400, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "TreeGadget Example")
CreateGadgetList(WindowID())

; Store the Handle in the Global value:

hWndTV = TreeGadget(1, 5, 5, 190, 390)

; Now, here we run into our first Problem: There's no Flag for enabling Label Editing.
; so we'll have to to it ourselves.
; We can change that using the API Functions GetWindowLong_() and SetWindowLong_()
; What we do, is change a Style of the Window (That's the Stuff you specify with the Flags)

; First, get the existing Styles:

Styles.l = GetWindowLong_(hWndTV, #GWL_STYLE)

; Then Add Label Editing to these Styles:

Styles = Styles | #TVS_EDITLABELS

; Now Set the new Styles for the Gadget:

SetWindowLong_(hWndTV, #GWL_STYLE, Styles)

; Now Label Editing is allowed in this TreeGadget

; We'll now add some Items

AddGadgetItem(1, -1, "Item0")
AddGadgetItem(1, -1, "Item0")
OpenTreeGadgetNode(1)
AddGadgetItem(1, -1, "Item0")
AddGadgetItem(1, -1, "Item0")
CloseTreeGadgetNode(1)

; Now we'll need to set the Callback Procedure (for more Inofrmation see 'SetWindowCallback()'
; in the Help Files in the 'Window' Library.

SetWindowCallback(@Callback())

; That was all that was to be done in the Main prog, now your Main Loop can follow, that
; will handle all normal PureBasic Events.
; In this case, we handle no other Events, so this Loop only waits for the Close
; Button to be Pressed, and then Ends the Program.

Repeat
  Event=WaitWindowEvent()
Until Event=#PB_Event_CloseWindow
End

; This is the End of the Main Code.
; ------------------------------------------------------------------------------------

; Now following is the Callback Procedure. Here we handle the Editing.
; The Events are Send as Messages, where a Message is just a Constantt
; like the Event-Constants, wParam and lParam are just the parameters for
; these Events. You see, the Callback-thingy is not that hard.
; the only thing is to always use the skeleton you can find in the Help files
; (at 'SetWindowCallback()') as otherwise, your Program will crash.


Procedure Callback(Window.l, Message.l, wParam.l, lParam.l)
  result = #PB_ProcessPureBasicEvents 
  
  ; The Messages we need are sent as a WM_NOTIFY Message. THis means, the Message will
  ; in our case always be #WM_NOTIFY, and the selection of the real Message will be made
  ; later.
  
  ; So we only need to find this Message:
  
  If Message = #WM_NOTIFY 
      
      ; lParam contains the Pointer to a Structure with the actual Message: 
      
      *lp.NMHDR = lParam
      
      ; now, we need to check, if it's really the TreeGadget that sent the Message
      
      If *lp\hwndFrom = GadgetID(1)
      
      ; now we see, what Message it was: (the code Member of the Structure contains the Message.)
      ; We'll need only 2 Messages:
      
      Select *lp\code
      
        ; fist is #TVN_BEGINLABELEDIT, this one is sent, if the user want's to edit an Item.
        
        Case #TVN_BEGINLABELEDIT
          Debug 1
          Debug wParam
           ; here you can check, if you want to allow the user to edit this Item, or not.
           ; use GetGadgetState() to check, which Item in the TreeGadget is being edited.
           ; If you want to allow it, just do nothing, if not, you have to set
           ; 'result' to #TRUE.
           ; So if you want to always allow it, just write nothing here.
           
           ; In our case, we forbit editing Item 1: (which is actually the second in the Tree)
           ; but you can also do any other thing to find you, if you want to allo editing, this
           ; depends, on, what the Program will be for.
           
           If GetGadgetState(1) = 1
             result = #True
           EndIf
           
           ; ------------------------------------------
           
       Case #TVN_ENDLABELEDIT
        Debug 2
           ; here you can check, if you want to accept the edited Text. For this, we'll
           ; need to get the new Text.
           
           ; lParam contains the Pointer to a Stucture with the Information
           ; As we allready know, lParam also pointed to the Structure from the
           ; #WM_NOTIFY Message. That's why this new Structure also contains the
           ; Structure NMHDR, which was from #WM_NOTIFY.
           
           *pvdi.NMTVDISPINFO = lParam
           
           ; The 'pszText' of the TV_ITEM Structure inside this Structure is a Pointer
           ; to the new entered Text. If this Pointer is #NULL, the Editing was
           ; chanceled by the User, and nothing will be changed. So we can ignore
           ; this Message in this case.
           ; Note: The Text can still be "", if the user deleted everything, but in this
           ; case, the Pointer will still not be #NULL.
           
           ; Check, that the 'pszText' Member is not #NULL
           
           If *pvdi\item\pszText <> #Null
           
             ; now, we get the entered Text:
             
             Text.s = PeekS(*pvdi\item\pszText)
             
             ; now you can decide, if you want to accept this Text, or not. If you want
             ; to find out the Item Number, use GetGadgetState().
             
             ; If you want to accept the Text, set 'result' to #True, if not, set it to
             ; #False.
             
             ; In our case, we don't want the user to enter an empty String.
             
             If Text = ""
               result = #False
             Else
               result = #True
             EndIf
          
           EndIf
           
           ; ------------------------------------------
          
           ; Well, that was all, you need, to make a TreeGadget editable, no a very big deal ;)
           ; We now just close all started Contitions
      
      ; the selection of the Message    
       
      EndSelect
      
      ; The If of the Check for right Gadget
      
      EndIf
      
  ; The If contition for #WM_NOTIFY
  
  EndIf
  
  ; now, we return the 'return' value:
  
  ProcedureReturn result

; that's it, for the callback procedure.
  
EndProcedure
horst
Beiträge: 70
Registriert: 08.09.2004 19:33
Wohnort: München
Kontaktdaten:

Re: Umbenennen im TreeGadget() mit PopupMenu()

Beitrag von horst »

BlueSpirit hat geschrieben:...Ich weiß aber jetzt nicht, wie ich das TreeGadget() dazu bringe, dass er den aktuellen Eintrag zu dem Eingabefeld umwandelt,...
Ich verwende immer eine kleine Funktion, die den rechts-geklickten Eintrag zum aktuellen Eintrag macht (Markierung).

Code: Alles auswählen

Procedure TreeClick(Gadget_Handle)
  var.TV_HITTESTINFO
  GetCursorPos_(@var.TV_HITTESTINFO\pt)               ; get mousepointer position screen coordenates 
  ScreenToClient_(Gadget_Handle,@var.TV_HITTESTINFO\pt)   ; convert these coordenates to the TreeView reference 
  SendMessage_(Gadget_Handle,#TVM_HITTEST,0,var)          ; this is to know what is the item i am pointing. 
  If var.TV_HITTESTINFO\flags & #TVHT_ONITEM 	            ; if clicked inside an item bitmap or item label 
    SendMessage_(Gadget_Handle,#TVM_SELECTITEM,#TVGN_CARET,var\hItem) ; and this selects the pointed item 
    ok = 1
   EndIf 
ProcedureReturn ok 
EndProcedure 

Einfach bei #PB_EventType_RightClick ausführen, z.B. TreeClick(gadgetID(#tree))
Die Funktion gibt #true zurück, wenn direkt auf einem Eintrag geklickt wurde, sonst #false.
Auf jeden Fall ist die aktuelle Position dann richtig eingestellt.

Dank an denjenigen, der die Funktion mal irgendwo gepostet hat (ich hab's nur geklaut).
horst
Benutzeravatar
Spirit
Beiträge: 174
Registriert: 13.04.2005 19:09

Beitrag von Spirit »

Jetzt fehlt nur noch eins. Bei SendMessage_(GagdetId(1), #TVM_EDITLABEL, 0, ?) muss man bei lParam das Handle des Items angeben, ich weiß aber nicht, wie ich dieses Handle herausfinden kann. Hat vielleicht irgend jemand 'ne Idee?
horst
Beiträge: 70
Registriert: 08.09.2004 19:33
Wohnort: München
Kontaktdaten:

Beitrag von horst »

Spirit hat geschrieben:Jetzt fehlt nur noch eins. Bei SendMessage_(GagdetId(1), #TVM_EDITLABEL, 0, ?) muss man bei lParam das Handle des Items angeben, ich weiß aber nicht, wie ich dieses Handle herausfinden kann. Hat vielleicht irgend jemand 'ne Idee?
Sieht bei mir so aus:

Code: Alles auswählen

Procedure EditItem() ; by click/F2 or insert page
  hItem = SendMessage_(TreeHandle,#TVM_GETNEXTITEM,#TVGN_CARET,0)
  SendMessage_(TreeHandle,#TVM_EDITLABEL,0,hItem)
EndProcedure 
horst
Benutzeravatar
Spirit
Beiträge: 174
Registriert: 13.04.2005 19:09

Beitrag von Spirit »

Es funktioniert! Vielen Dank! :allright:
Benutzeravatar
Justy
Beiträge: 131
Registriert: 10.09.2004 13:31
Wohnort: Feldbach / Steiermark / Österreich
Kontaktdaten:

Beitrag von Justy »

Könntest du bitte einen vollständigen Code z.b. für das CodeArchiv erstellen?

Ein solche Funktion kann man immer wieder mal brauchen! :D


mfg. Justy
Am Anfang erschuf der Mensch Gott.
Friedrich Nietzsche
Benutzeravatar
Spirit
Beiträge: 174
Registriert: 13.04.2005 19:09

Beitrag von Spirit »

Code: Alles auswählen

; ---------------------------------------------------------------------
; How to make TreeGadget Items Editable by the User
; by Timo Harter
; ---------------------------------------------------------------------
;
; By implementing this in your Program, the User can edit the Items
; of a TreeGadget by first right-clicking, and then left-clicking on it.
; (just like in Windows-Explorer) 
;
; This is just a skeleton, how it is done, but it should be easy to 
; understand, and implement in your own Programs.
; ---------------------------------------------------------------------

Procedure TreeClick(Gadget_Handle) 
  var.TV_HITTESTINFO 
  GetCursorPos_(@var.TV_HITTESTINFO\pt)               ; get mousepointer position screen coordenates 
  ScreenToClient_(Gadget_Handle,@var.TV_HITTESTINFO\pt)   ; convert these coordenates to the TreeView reference 
  SendMessage_(Gadget_Handle,#TVM_HITTEST,0,var)          ; this is to know what is the item i am pointing. 
  If var.TV_HITTESTINFO\flags & #TVHT_ONITEM                ; if clicked inside an item bitmap or item label 
    SendMessage_(Gadget_Handle,#TVM_SELECTITEM,#TVGN_CARET,var\hItem) ; and this selects the pointed item 
    ok = 1 
  EndIf 
  ProcedureReturn ok 
EndProcedure

Procedure EditItem()
  hItem = SendMessage_(GadgetID(1),#TVM_GETNEXTITEM,#TVGN_CARET,0)
  SendMessage_(GadgetID(1),#TVM_EDITLABEL,0,hItem)
EndProcedure 

; This Constant will be needed:

#TVS_EDITLABELS = 8  ; The Window Style for Label Editing

; We'll need a Callback procedure for that. (If you never used one, don't be afraid, 
; it's not that hard.). I'll just declare it here, the Procedure will be further down.

Declare Callback(Window.l, Message.l, wParam.l, lParam.l)

; First, we'll just create a Window, and a a TreeGadget.

OpenWindow(0, 0, 0, 200, 400, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "TreeGadget Example")
CreateGadgetList(WindowID())

; Store the Handle in the Global value:

hWndTV = TreeGadget(1, 5, 5, 190, 390)

; Now, here we run into our first Problem: There's no Flag for enabling Label Editing.
; so we'll have to to it ourselves.
; We can change that using the API Functions GetWindowLong_() and SetWindowLong_()
; What we do, is change a Style of the Window (That's the Stuff you specify with the Flags)

; First, get the existing Styles:

Styles.l = GetWindowLong_(hWndTV, #GWL_STYLE)

; Then Add Label Editing to these Styles:

Styles = Styles | #TVS_EDITLABELS

; Now Set the new Styles for the Gadget:

SetWindowLong_(hWndTV, #GWL_STYLE, Styles)

; Now Label Editing is allowed in this TreeGadget

; We'll now add some Items

AddGadgetItem(1, -1, "Item0")
AddGadgetItem(1, -1, "Item0")
OpenTreeGadgetNode(1)
AddGadgetItem(1, -1, "Item0")
AddGadgetItem(1, -1, "Item0")
CloseTreeGadgetNode(1)

CreatePopupMenu(0)
MenuItem(0, "Rename")

; Now we'll need to set the Callback Procedure (for more Inofrmation see 'SetWindowCallback()'
; in the Help Files in the 'Window' Library.

SetWindowCallback(@Callback())

; That was all that was to be done in the Main prog, now your Main Loop can follow, that
; will handle all normal PureBasic Events.
; In this case, we handle no other Events, so this Loop only waits for the Close
; Button to be Pressed, and then Ends the Program.

Repeat
  Event=WaitWindowEvent()
  If Event=#PB_Event_Gadget And EventType()=#PB_EventType_RightClick
    TreeClick(GadgetID(1))
    DisplayPopupMenu(0, WindowID())
  EndIf
  If Event=#PB_Event_Menu
    EditItem()
  EndIf
  
Until Event=#PB_Event_CloseWindow
End

; This is the End of the Main Code.
; ------------------------------------------------------------------------------------

; Now following is the Callback Procedure. Here we handle the Editing.
; The Events are Send as Messages, where a Message is just a Constantt
; like the Event-Constants, wParam and lParam are just the parameters for
; these Events. You see, the Callback-thingy is not that hard.
; the only thing is to always use the skeleton you can find in the Help files
; (at 'SetWindowCallback()') as otherwise, your Program will crash.


Procedure Callback(Window.l, Message.l, wParam.l, lParam.l)
  result = #PB_ProcessPureBasicEvents 
  
  ; The Messages we need are sent as a WM_NOTIFY Message. THis means, the Message will
  ; in our case always be #WM_NOTIFY, and the selection of the real Message will be made
  ; later.
  
  ; So we only need to find this Message:
  
  If Message = #WM_NOTIFY 
      
      ; lParam contains the Pointer to a Structure with the actual Message: 
      
      *lp.NMHDR = lParam
      
      ; now, we need to check, if it's really the TreeGadget that sent the Message
      
      If *lp\hwndFrom = GadgetID(1)
      
      ; now we see, what Message it was: (the code Member of the Structure contains the Message.)
      ; We'll need only 2 Messages:
      
      Select *lp\code
      
        ; fist is #TVN_BEGINLABELEDIT, this one is sent, if the user want's to edit an Item.
        
        Case #TVN_BEGINLABELEDIT
           ; here you can check, if you want to allow the user to edit this Item, or not.
           ; use GetGadgetState() to check, which Item in the TreeGadget is being edited.
           ; If you want to allow it, just do nothing, if not, you have to set
           ; 'result' to #TRUE.
           ; So if you want to always allow it, just write nothing here.
           
           ; In our case, we forbit editing Item 1: (which is actually the second in the Tree)
           ; but you can also do any other thing to find you, if you want to allo editing, this
           ; depends, on, what the Program will be for.
           
           If GetGadgetState(1) = 1
             result = #True
           EndIf
           
           ; ------------------------------------------
           
       Case #TVN_ENDLABELEDIT
           ; here you can check, if you want to accept the edited Text. For this, we'll
           ; need to get the new Text.
           
           ; lParam contains the Pointer to a Stucture with the Information
           ; As we allready know, lParam also pointed to the Structure from the
           ; #WM_NOTIFY Message. That's why this new Structure also contains the
           ; Structure NMHDR, which was from #WM_NOTIFY.
           
           *pvdi.NMTVDISPINFO = lParam
           
           ; The 'pszText' of the TV_ITEM Structure inside this Structure is a Pointer
           ; to the new entered Text. If this Pointer is #NULL, the Editing was
           ; chanceled by the User, and nothing will be changed. So we can ignore
           ; this Message in this case.
           ; Note: The Text can still be "", if the user deleted everything, but in this
           ; case, the Pointer will still not be #NULL.
           
           ; Check, that the 'pszText' Member is not #NULL
           
           If *pvdi\item\pszText <> #Null
           
             ; now, we get the entered Text:
             
             Text.s = PeekS(*pvdi\item\pszText)
             
             ; now you can decide, if you want to accept this Text, or not. If you want
             ; to find out the Item Number, use GetGadgetState().
             
             ; If you want to accept the Text, set 'result' to #True, if not, set it to
             ; #False.
             
             ; In our case, we don't want the user to enter an empty String.
             
             If Text = ""
               result = #False
             Else
               result = #True
             EndIf
          
           EndIf
           
           ; ------------------------------------------
          
           ; Well, that was all, you need, to make a TreeGadget editable, no a very big deal ;)
           ; We now just close all started Contitions
      
      ; the selection of the Message    
       
      EndSelect
      
      ; The If of the Check for right Gadget
      
      EndIf
      
  ; The If contition for #WM_NOTIFY
  
  EndIf
  
  ; now, we return the 'return' value:
  
  ProcedureReturn result

; that's it, for the callback procedure.
  
EndProcedure
Antworten