Tastatur-Navigation durch eine OptionGadget-Gruppe

Für allgemeine Fragen zur Programmierung mit PureBasic.
piccolo
Beiträge: 2
Registriert: 16.11.2018 23:58

Tastatur-Navigation durch eine OptionGadget-Gruppe

Beitrag von piccolo »

Hallo Leute und guten Tag.

Wenn ich eine OptionGadget-Gruppe in einem Fenster erstelle, kann ich zwar mit der Tabulatortaste dorthin navigieren, was ich am gepunkteten Fokus-Rechteck erkenne, aber nicht mit den Pfeiltasten zwischen den einzelnen Optionen wählen, wie in den meisten Windows-Anwendungen üblich. Hier ein Beispielcode zum Testen:

Code: Alles auswählen

If OpenWindow(0, 0, 0, 140, 160, "Optionen",
              #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
  ContainerGadget(0, 20, 20, 100, 120, #PB_Container_Flat)
  OptionGadget(1, 20, 20, 60, 20, "Option 1")
  OptionGadget(2, 20, 50, 60, 20, "Option 2")
  OptionGadget(3, 20, 80, 60, 20, "Option 3")
  CloseGadgetList()
  SetGadgetState(2, 1) ; Zweite Option aktivieren
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_CloseWindow
        Break
      Case #PB_Event_Gadget
        Debug "Auswahl"
    EndSelect
  ForEver
EndIf
Ist das ein Bug in PureBasic, getestet in den Versionen 3.94, 4.10, 5.46 und 5.72, oder so gewollt? In den Einstellungen des PureBasic-Editors kann ich nämlich auch nicht mit den Pfeiltasten zwischen den einzelnen OptionGadgets wählen. Wie kann ich diese Funktionalität einbauen? Mit

Code: Alles auswählen

CreateWindowEx_(#WS_EX_WINDOWEDGE, "BUTTON", "Option 4",
                #BS_RADIOBUTTON | #WS_CHILD | #WS_GROUP |
                #WS_TABSTOP | #WS_VISIBLE,
                40, 130, 60, 20, WindowID(0), #Null,
                GetModuleHandle_(#Null), #Null)
CreateWindowEx_(#WS_EX_WINDOWEDGE, "BUTTON", "Option 5",
                #BS_RADIOBUTTON | #WS_CHILD | #WS_VISIBLE,
                40, 160, 60, 20, WindowID(0), #Null,
                GetModuleHandle_(#Null), #Null)
bekomme ich zwar OptionGadget-Gruppen in hässlicher Fettschrift erstellt, aber welche Ereignisse (#WM_XXX) ich dafür abfragen muss, ist mir vollkommen unklar, weil ich mit denen von Windows noch nie ernsthaft direkt gearbeitet habe.
Ich nutze PureBasic 5.72 unter Windows XP SP3.

Gruß, piccolo
Zuletzt geändert von piccolo am 27.06.2021 07:07, insgesamt 1-mal geändert.
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Tastatur-Navigation durch eine OptionGadget-Gruppe

Beitrag von Kiffi »

Bestätigt. Unter W10 funktioniert das auch nicht. (In Optionen-Dialog von Notepad++ hingegen schon).
Sollte eigentlich ab PB5.45 klappen. Hier ein Thread zur weiteren Recherche: Keyboard interaction with OptionGadget
Hygge
matbal
Beiträge: 246
Registriert: 30.03.2011 20:53

Re: Tastatur-Navigation durch eine OptionGadget-Gruppe

Beitrag von matbal »

ts-soft hat einen Code veröffentlicht, um das gewünschte Verhalten zu emulieren:

EmulateDialog windows only
piccolo
Beiträge: 2
Registriert: 16.11.2018 23:58

Re: Tastatur-Navigation durch eine OptionGadget-Gruppe

Beitrag von piccolo »

Vielen herzlichen Dank euch beiden für die schnelle und kompetente Hilfe und natürlich auch an @Little John und @ts-soft für den tollen Code! Hat mir sehr weitergeholfen und den Fehler auf Anhieb behoben. Die Suchmaschine verschwieg mir leider diese Seiten.

@Kiffi: Den Code von Little John habe ich etwas erweitert, damit es auch möglich ist, nach der letzten Option nicht zur ersten zu springen und umgekehrt:

Code: Alles auswählen

EnableExplicit

Enumeration Windows
  #Win_Main
EndEnumeration

Enumeration Gadgets
  #Opt_1 = 1 ; Required for correct counting.
  #Opt_2
  #Opt_3
  #Opt_4
  #Opt_5
  #Opt_6
  #Btn_Okay
  #Btn_Cancel
EndEnumeration

Enumeration Shortcuts
  #Key_Up
  #Key_Down
  #Key_Return
EndEnumeration


Procedure.i ActiveOption(First.i, Last.i, Move.i = 0, Wrap.i = 0)
  ; In : First: Number of first OptionGadget() in the list.
  ;      Last : Number of last  OptionGadget() in the list.
  ;      Move : 0 (stay), -1 (up/left) or 1 (down/right).
  ;      Wrap : 0 (stay at first or last option) or
  ;             1 (wrap from last to first and vice versa).
  ; Out: Number of the (new) active OptionGadget() or
  ;      -1 if no OptionGadget() is active and Move = 0.
  Protected Option.i, Found.i = #False
  For Option = First To Last
    If GetGadgetState(Option) = #PB_Checkbox_Checked
      Found = #True
      Break
    EndIf
  Next
  If Not Found
    If Move = 0
      ProcedureReturn -1
    EndIf
    Option = GetActiveGadget()
  EndIf
  Option + Move
  If Option < First
    If Wrap
      Option = Last
    Else
      Option = First
    EndIf
  ElseIf Option > Last
    If Wrap
      Option = First
    Else
      Option = Last
    EndIf
  EndIf
  ProcedureReturn Option
EndProcedure


If Not OpenWindow(#Win_Main, #PB_Default, #PB_Default,
                  190, 137, "OptionGadgets",
                  #PB_Window_ScreenCentered |
                  #PB_Window_SystemMenu)
  End
EndIf

FrameGadget(#PB_Any, 10, 4, 80, 91, "")
OptionGadget(#Opt_1, 21, 19, 61, 19, "Option 1")
OptionGadget(#Opt_2, 21, 43, 61, 19, "Option 2")
OptionGadget(#Opt_3, 21, 67, 61, 19, "Option 3")
FrameGadget(#PB_Any, 100, 4, 80, 91, "")
OptionGadget(#Opt_4, 111, 19, 61, 19, "Option 4")
OptionGadget(#Opt_5, 111, 43, 61, 19, "Option 5")
OptionGadget(#Opt_6, 111, 67, 61, 19, "Option 6")
ButtonGadget(#Btn_Okay, 12, 105, 76, 23, "OK", #PB_Button_Default)
ButtonGadget(#Btn_Cancel, 102, 105, 76, 23, "Cancel")

; SetGadgetState(#Opt_2, 1) ; Required for correct tabstop.
; SetGadgetState(#Opt_4, 1) ; Required for correct tabstop.
SetActiveGadget(#Btn_Okay)

AddKeyboardShortcut(#Win_Main, #PB_Shortcut_Up, #Key_Up)
AddKeyboardShortcut(#Win_Main, #PB_Shortcut_Down, #Key_Down)
; Required for a working default button when pressing the return key:
AddKeyboardShortcut(#Win_Main, #PB_Shortcut_Return, #Key_Return)

Define Event, Gadget, Menu
Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      Gadget = EventGadget()
      Select Gadget
        Case #Btn_Okay
          Debug "You chose options " +
                ActiveOption(#Opt_1, #Opt_3) + " and " +
                ActiveOption(#Opt_4, #Opt_6)
          Break
        Case #Btn_Cancel
          Debug "Canceled"
          Break
      EndSelect
    Case #PB_Event_Menu
      Menu = EventMenu()
      Select Menu
        Case #Key_Up
          Gadget = GetActiveGadget()
          Select Gadget
            Case #Opt_1 To #Opt_3 ; Left options block.
              Gadget = ActiveOption(#Opt_1, #Opt_3, -1)
              SetGadgetState(Gadget, 1)
              SetActiveGadget(Gadget)
            Case #Opt_4 To #Opt_6 ; Right options block.
              Gadget = ActiveOption(#Opt_4, #Opt_6, -1)
              SetGadgetState(Gadget, 1)
              SetActiveGadget(Gadget)
          EndSelect
        Case #Key_Down
          Gadget = GetActiveGadget()
          Select Gadget
            Case #Opt_1 To #Opt_3 ; Left options block.
              Gadget = ActiveOption(#Opt_1, #Opt_3, 1)
              SetGadgetState(Gadget, 1)
              SetActiveGadget(Gadget)
            Case #Opt_4 To #Opt_6 ; Right options block.
              Gadget = ActiveOption(#Opt_4, #Opt_6, 1)
              SetGadgetState(Gadget, 1)
              SetActiveGadget(Gadget)
          EndSelect
        Case #Key_Return ; Trigger #Btn_Okay gadget event:
          PostEvent(#PB_Event_Gadget, #Win_Main, #Btn_Okay)
      EndSelect
  EndSelect
ForEver

End
Ein weiterer möglicher Fehler kommt zum Vorschein, solange kein OptionGadget() innerhalb der Gruppe aktiviert wurde (Zeilen 82 und 83): die Tabulatortaste fokussiert dann ein OptionGadget() nach dem anderen, statt nur eines (das erste) aus der Gruppe. Könnte man wahrscheinlich auch durch einen weiteren Shortcut beheben, werde ich aber vermutlich niemals benötigen.
Trotz Kennzeichnung des OK-ButtonGadget() als #PB_Button_Default löste PureBasic kein Ereignis beim Drücken der Returntaste aus. Diesen Umstand habe ich im Code schon behoben.

@matbal: Der Code von ts-soft funktioniert auch sehr gut, benötigt für meinen Geschmack und derzeitigen Zweck jedoch zu viele Callbacks (6 Stück im Beispiel) und springt obendrein vom letzten OptionGadget() zum ersten und umgekehrt, was ich momentan allerdings nicht will. Meine PureBasic-/WinAPI-Kenntnisse reichen zum Ändern leider nicht aus. Macht aber nichts, ich bin dank euch ja trotzdem ans Ziel gekommen. :) Der Code von Little John bzw. der von mir erweiterte dürfte im Gegensatz zu dem von ts-soft nicht nur auf Windows, sondern auch auf Linux und MacOS funktionieren.

Euch Vier nochmals herzlichst Danke!

Gruß, piccolo
Antworten