Tab-Items sperren und bei Bedarf enablen

  • Hallo,

    ich hab mir ne GUI mit 3 Tab-Items "gebastelt".
    Die zweite Tab soll komplett gesperrt sein, bis in der ersten Tab ein Eintrag einer Listview geklickt/doppelgeklickt wird.

    Das mit dem Doppelklick und wechseln in die zweiteTab ist kein Thema, aber wie sperre ich hier den einen Tab ?

    Geht das überhaupt? Mit GUICtrlSetState(... ging es schon mal nicht..

    3 Mal editiert, zuletzt von Torni (4. Juni 2012 um 16:40)

  • Du kannst soweit ich weiß nur das ganze Tab Control disablen. Nicht einzelne Tabs. Zumindest habe ich noch keine Möglichkeit gesehen.
    Du kannst aber alternativ auch die OwnTab UDF (ich glaube so hieß die) von funkey verwenden, oder einfach verhindern, dass der User die Tabs umschaltet indem du im Script immer automatisch zum vorherigen Tab zurückschaltest.

    • Offizieller Beitrag

    Ich hatte das, wie folgt gelöst. Im Bsp. ist TAB-Item3 Passwort-geschützt (pass)

    Spoiler anzeigen
    [autoit]

    #include <GuiConstantsEx.au3>
    #include <GuiTab.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    OnAutoItExitRegister('OnAutoItExit')
    AdlibRegister('_CheckPass', 50)

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $HC_ACTION = 0

    [/autoit] [autoit][/autoit] [autoit]

    Global $hStub_MouseProc = DllCallbackRegister("_MouseProc", "long", "int;wparam;lparam")
    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hStub_MouseProc), $hmod)
    Global $hHook2 = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
    Global $hTab, $lastTab = 0, $checkPass = False

    [/autoit] [autoit][/autoit] [autoit]

    Global $Passwort = 'pass', $passItem = 2 ; <== 0-basierter Index des PW-geschützten TabItems

    [/autoit] [autoit][/autoit] [autoit]

    $Form1 = GUICreate("Testfenster", 297, 341, 210, 144)
    $Tab = GUICtrlCreateTab(8, 8, 280, 304)
    GUICtrlSetResizing(-1, $GUI_DOCKWIDTH + $GUI_DOCKHEIGHT)
    $tab1 = GUICtrlCreateTabItem("Tab1")
    $tab2 = GUICtrlCreateTabItem("Tab2")
    $tab3 = GUICtrlCreateTabItem("Tab3")
    $tab4 = GUICtrlCreateTabItem("Tab4")
    GUICtrlCreateTabItem("")
    GUISetState(@SW_SHOW)

    [/autoit] [autoit][/autoit] [autoit]

    Global $hookGUI = $Form1, $hookID = $Tab

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    Case $Tab
    Switch GUICtrlRead($Tab)
    Case 0
    WinSetTitle($Form1, '', ' >> Tab1 aktiviert <<')
    Case 1
    WinSetTitle($Form1, '', ' >> Tab2 aktiviert <<')
    Case 2
    WinSetTitle($Form1, '', ' >> Tab3 aktiviert <<')
    Case 3
    WinSetTitle($Form1, '', ' >> Tab4 aktiviert <<')
    EndSwitch
    Sleep(1000)
    WinSetTitle($Form1, '', 'Testfenster')
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _MouseProc($nCode, $wParam, $lParam)
    Select
    Case $nCode < 0
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Case Not _MouseOverTabItem($hookGUI, $hookID, $passItem)
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Case $wParam = $WM_LBUTTONDOWN
    If $nCode = $HC_ACTION Then
    $checkPass = True ; Überprüfung aktivieren
    Return -1 ; Mausklick wird ignoriert ==> TabItem noch nicht aktiviert
    EndIf
    EndSelect
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_MouseProc

    [/autoit] [autoit][/autoit] [autoit]

    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If ControlGetFocus($Form1) <> 'SysTabControl321' Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    Switch $vkCode
    Case 0x25 ; ==> Pfeil li.
    If GUICtrlRead($hookID) - 1 = $passItem Then
    $checkPass = True ; Überprüfung aktivieren
    Return -1 ; Tastendruck wird ignoriert ==> TabItem noch nicht aktiviert
    EndIf
    Case 0x27 ; ==> Pfeil re.
    If GUICtrlRead($hookID) + 1 = $passItem Then
    $checkPass = True ; Überprüfung aktivieren
    Return -1 ; Tastendruck wird ignoriert ==> TabItem noch nicht aktiviert
    EndIf
    EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_KeyProc

    [/autoit] [autoit][/autoit] [autoit]

    Func _CheckPass()
    If Not $checkPass Then Return
    If InputBox('Passwort', 'Bitte Passwort eingeben:') == $Passwort Then
    _GUICtrlTab_SetCurSel(GUICtrlGetHandle($Tab), $passItem)
    Else
    MsgBox(0, 'Fehler', 'Falsches Passwort!')
    EndIf
    $checkPass = 0
    EndFunc ;==>_CheckPass

    [/autoit] [autoit][/autoit] [autoit]

    Func _MouseOverTabItem($GUI, $TabID, $iTabItem)
    If Not BitAND(WinGetState($GUI), 8) Then Return False
    Local $old = Opt('MouseCoordMode', 2)
    Local $posM = MouseGetPos(), $tMouse = DllStructCreate($tagPOINT)
    DllStructSetData($tMouse, 1, $posM[0])
    DllStructSetData($tMouse, 2, $posM[1])
    Opt('MouseCoordMode', $old)
    Local $tTabItem = _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, 1)
    If _WinAPI_PtInRect($tTabItem, $tMouse) Then
    Return True
    Else
    Return False
    EndIf
    EndFunc ;==>_MouseOverTabItem

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Function Name: _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, $iReturnType=0)
    ; Description: Returns the co-ordinates of a TabItem relatively to the GUI co-ordinates
    ; Parameter(s): $GUI - window handle
    ; $TabID - Tab ID (not handle!)
    ; $iTabItem - TabItem index
    ; $iReturnType - Return type array=0 (default), RECT-structure=1
    ; Return Value(s): Array or structure with co-ordinates of a TabItem (left, top, right, bottom)
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ;===============================================================================
    Func _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, $iReturnType=0)
    Local $hWnd = GUICtrlGetHandle($TabID)
    Local $TabPos = ControlGetPos($GUI, '', $TabID)
    Local $tRECT = DllStructCreate("int Left;int Top;int Right;int Bottom")
    Local $pRect = DllStructGetPtr($tRECT)
    GUICtrlSendMsg($TabID, $TCM_GETITEMRECT, $iTabItem, $pRect)
    Local $posLeft = $TabPos[0]+2, $posTop = $TabPos[1]+2
    Local $width = (DllStructGetData($tRECT,3) - DllStructGetData($tRECT,1))
    Local $height = DllStructGetData($tRECT,4) - DllStructGetData($tRECT,2)
    If $iTabItem > 0 Then
    For $i = 0 To $iTabItem -1
    GUICtrlSendMsg($TabID, $TCM_GETITEMRECT, $iTabItem, $pRect)
    $posLeft += (DllStructGetData($tRECT,3) - DllStructGetData($tRECT,1))
    Next
    EndIf
    If $iReturnType Then
    DllCall("user32", 'long', 'SetRect', 'ptr', $pRECT, 'long', $posLeft, _
    'long', $posTop, 'long', $posLeft+$width, 'long', $posTop +$height)
    Return $tRECT
    Else
    Local $aOut[4] = [$posLeft, $posTop, $posLeft +$width, $posTop +$height]
    Return $aOut
    EndIf
    EndFunc ;==>_GUICtrlTab_GetItemRectRelativ

    [/autoit] [autoit][/autoit] [autoit]

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_MouseProc)
    _WinAPI_UnhookWindowsHookEx($hHook2)
    DllCallbackFree($hStub_KeyProc)
    EndFunc ;==>OnAutoItExit

    [/autoit] [autoit][/autoit] [autoit][/autoit]
  • hmm, super sache von dir BugFix, ich habe da nur ein Problem:

    Die Controls die auf der gesperrten Tab liegen, werden dabei nicht mehr angezeigt ?!?

    Ansonsten ist das ganze Teil sehr gut für alles Mögliche verwendbar.

    EDIT: hat sich geklärt, da fehle ein: GUICtrlSetState($TabSheet2, $GUI_SHOW) und alles wird gut.

    Hätte man ja gleich drauf kommen können, muss ne Pause machen *G*.

    Ich danke euch beide, muss mal betonen, die Comm. hier ist echt klasse.

    Einmal editiert, zuletzt von Torni (2. Juni 2012 um 19:41)

    • Offizieller Beitrag

    Hi,
    ich habs mal noch etwas umgebaut und eine Funktion eingefügt (_GuiCtrlTab_ItemStateAble) zum wahlweisen Enablen/Disablen eines (mehrerer) beliebigen Tab-Items.

    Spoiler anzeigen
    [autoit]

    #include <GuiConstantsEx.au3>
    #include <GuiTab.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    OnAutoItExitRegister('OnAutoItExit')
    AdlibRegister('_Check', 50)

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $HC_ACTION = 0

    [/autoit] [autoit][/autoit] [autoit]

    Global $hStub_MouseProc = DllCallbackRegister("_MouseProc", "long", "int;wparam;lparam")
    Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
    Global $hmod = _WinAPI_GetModuleHandle(0)
    Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hStub_MouseProc), $hmod)
    Global $hHook2 = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
    Global $check = False, $IndexMouseOver
    Global $aDisableItem[1] = [0] ; == Array zum Speichern der Disable-Item

    [/autoit] [autoit][/autoit] [autoit]

    $Form1 = GUICreate("Testfenster", 297, 341, 210, 144)
    $Tab = GUICtrlCreateTab(8, 8, 280, 304)
    GUICtrlSetResizing(-1, $GUI_DOCKWIDTH + $GUI_DOCKHEIGHT)
    $tab1 = GUICtrlCreateTabItem("Tab1")
    $tab2 = GUICtrlCreateTabItem("Tab2")
    $tab3 = GUICtrlCreateTabItem("Tab3")
    $tab4 = GUICtrlCreateTabItem("Tab4")
    GUICtrlCreateTabItem("")
    GUISetState(@SW_SHOW)

    [/autoit] [autoit][/autoit] [autoit]

    Global $hookGUI = $Form1, $hookID = $Tab

    [/autoit] [autoit][/autoit] [autoit]

    $countTimer = 0
    $fTimer = True
    $timer = TimerInit()
    While 1
    If $fTimer And TimerDiff($timer) >= 5000 Then
    $countTimer += 1
    $fTimer = False
    Switch $countTimer
    Case 1
    MsgBox(0, '', 'Disable Tab2 für 5 Sekunden')
    _GuiCtrlTab_ItemStateAble($Tab, 1, $GUI_DISABLE)
    $timer = TimerInit()
    $fTimer = True
    Case 2
    MsgBox(0, '', 'Enable Tab2 wieder')
    _GuiCtrlTab_ItemStateAble($Tab, 1, $GUI_ENABLE)
    EndSwitch
    EndIf
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _GuiCtrlTab_ItemStateAble($_hWnd, $_iIndex, $_iState) ; == $_iState: $GUI_ENABLE / $GUI_DISABLE
    If Not IsHWnd($_hWnd) Then $_hWnd = GUICtrlGetHandle($_hWnd)
    Local $iCount = _GUICtrlTab_GetItemCount($_hWnd)
    If $_iIndex < 0 Or $_iIndex > $iCount -1 Then Return
    If $_iState <> $GUI_ENABLE Then $_iState = $GUI_DISABLE
    Switch $_iState
    Case $GUI_ENABLE
    Local $found = False
    For $i = 1 To $aDisableItem[0]
    If $aDisableItem[$i] = $i Then
    $found = True
    ExitLoop
    EndIf
    Next
    If Not $found Then Return
    Local $k = 0, $aTmp[$aDisableItem[0]] = [$aDisableItem[0] -1]
    For $j = 1 To $aDisableItem[0]
    If $j = $i Then ContinueLoop
    $k += 1
    $aTmp[$k] = $aDisableItem[$j]
    Next
    $aDisableItem = $aTmp
    Case $GUI_DISABLE
    For $i = 1 To $aDisableItem[0]
    If $aDisableItem[$i] = $_iIndex Then Return
    Next
    $aDisableItem[0] += 1
    ReDim $aDisableItem[$aDisableItem[0]+1]
    $aDisableItem[$aDisableItem[0]] = $_iIndex
    EndSwitch
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _MouseProc($nCode, $wParam, $lParam)
    Select
    Case $nCode < 0
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Case Not _MouseOverTabItem($hookGUI, $hookID)
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    Case $wParam = $WM_LBUTTONDOWN
    If $nCode = $HC_ACTION Then
    $check = True ; Überprüfung aktivieren
    Return -1 ; Mausklick wird ignoriert ==> TabItem noch nicht aktiviert
    EndIf
    EndSelect
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_MouseProc

    [/autoit] [autoit][/autoit] [autoit]

    Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If ControlGetFocus($Form1) <> 'SysTabControl321' Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
    Switch $vkCode
    Case 0x25, 0x27
    $check = True
    Return -1
    EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    EndFunc ;==>_KeyProc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Check()
    If Not $check Then Return
    For $i = 1 To $aDisableItem[0]
    If $IndexMouseOver = $i Then
    $check = False
    Return
    EndIf
    Next
    _GUICtrlTab_SetCurSel(GUICtrlGetHandle($Tab), $IndexMouseOver)
    $check = False
    EndFunc ;==>_Check

    [/autoit] [autoit][/autoit] [autoit]

    Func _MouseOverTabItem($GUI, $TabID) ; == True wenn Maus über einem der TabItem
    If Not BitAND(WinGetState($GUI), 8) Then Return False
    Local $old = Opt('MouseCoordMode', 2)
    Local $posM = MouseGetPos(), $tMouse = DllStructCreate($tagPOINT)
    DllStructSetData($tMouse, 1, $posM[0])
    DllStructSetData($tMouse, 2, $posM[1])
    Opt('MouseCoordMode', $old)
    Local $tTabItem, $iCountItem = _GUICtrlTab_GetItemCount(GUICtrlGetHandle($TabID))
    $IndexMouseOver = -1
    For $i = 0 To $iCountItem -1
    $tTabItem = _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $i, 1)
    If _WinAPI_PtInRect($tTabItem, $tMouse) Then
    $IndexMouseOver = $i
    Return True
    EndIf
    Next
    Return False
    EndFunc ;==>_MouseOverTabItem

    [/autoit] [autoit][/autoit] [autoit]

    ;===============================================================================
    ; Function Name: _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, $iReturnType=0)
    ; Description: Returns the co-ordinates of a TabItem relatively to the GUI co-ordinates
    ; Parameter(s): $GUI - window handle
    ; $TabID - Tab ID (not handle!)
    ; $iTabItem - TabItem index
    ; $iReturnType - Return type array=0 (default), RECT-structure=1
    ; Return Value(s): Array or structure with co-ordinates of a TabItem (left, top, right, bottom)
    ; Author(s): BugFix ([email='bugfix@autoit.de'][/email])
    ;===============================================================================
    Func _GUICtrlTab_GetItemRectRelativ($GUI, $TabID, $iTabItem, $iReturnType=0)
    Local $hWnd = GUICtrlGetHandle($TabID)
    Local $TabPos = ControlGetPos($GUI, '', $TabID)
    Local $tRECT = DllStructCreate("int Left;int Top;int Right;int Bottom")
    Local $pRect = DllStructGetPtr($tRECT)
    GUICtrlSendMsg($TabID, $TCM_GETITEMRECT, $iTabItem, $pRect)
    Local $posLeft = $TabPos[0]+2, $posTop = $TabPos[1]+2
    Local $width = (DllStructGetData($tRECT,3) - DllStructGetData($tRECT,1))
    Local $height = DllStructGetData($tRECT,4) - DllStructGetData($tRECT,2)
    If $iTabItem > 0 Then
    For $i = 0 To $iTabItem -1
    GUICtrlSendMsg($TabID, $TCM_GETITEMRECT, $iTabItem, $pRect)
    $posLeft += (DllStructGetData($tRECT,3) - DllStructGetData($tRECT,1))
    Next
    EndIf
    If $iReturnType Then
    DllCall("user32", 'long', 'SetRect', 'ptr', $pRECT, 'long', $posLeft, _
    'long', $posTop, 'long', $posLeft+$width, 'long', $posTop +$height)
    Return $tRECT
    Else
    Local $aOut[4] = [$posLeft, $posTop, $posLeft +$width, $posTop +$height]
    Return $aOut
    EndIf
    EndFunc ;==>_GUICtrlTab_GetItemRectRelativ

    [/autoit] [autoit][/autoit] [autoit]

    Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_MouseProc)
    _WinAPI_UnhookWindowsHookEx($hHook2)
    DllCallbackFree($hStub_KeyProc)
    EndFunc ;==>OnAutoItExit

    [/autoit]
  • kleiner Nachtrag am Rande:

    [autoit]


    Switch.....
    ...
    Case $Tab
    If _GUICtrlTab_GetCurSel($Tab) = 1 Then; nicht erlaubte Tabsheet gewählt
    _GUICtrlTab_SetCurSel($Tab, 0); also wählen wir die erste wieder aus
    GUICtrlSetState($TabSheet1, $GUI_SHOW); und lassen sie anzeigen
    ...

    [/autoit]

    ginge es doch auch ?? Da hatte mir nämlich kene Ruhe gelassen und wollte "schmalen" Code *G*

  • Das geht auch. Aber BugFixs Lösung ist definitiv besser. Deine Version hängt von dem Intervall ab in dem du das ganze Abfragst. Bei BugFix gibt es sozusagen kein Intervall, da er mit Hooks arbeitet. Sein Script ist effizienter und sauberer. Ich würde das verwenden wenn ich du wäre ;).

  • Ja das ist / war mir fast klar, das das so viel effizienter ist. Ich habe nur (wieder) ein Problem damit:

    zeichne mal bitte unter irgendein Tabsheet etwas z.B. ein Label und wechsel dann mal in ein anderes Tab.

    Es wird nichts mehr dargestellt bzw. das zuerst ausgewählte bleibt immer auf dem aktuellen Tab stehen.
    Irgendwie wird nur der Tab-Reiter ausgewählt mit dme Code-Beispiel aber nicht der Inhalt angezeigt.

    Deswegen hatte ich ja in dem vorigen Code-Beispiel noch ein

    GUICtrlSetState($tab2, $GUI_SHOW)

    eingefügt. dies geht aber im "neuen" Code nicht mehr ?!?

    • Offizieller Beitrag

    Es wird nichts mehr dargestellt bzw. das zuerst ausgewählte bleibt immer auf dem aktuellen Tab stehen.
    Irgendwie wird nur der Tab-Reiter ausgewählt mit dme Code-Beispiel aber nicht der Inhalt angezeigt.


    Ahh, stimmt. Hatte ich nicht bedacht. Dadurch, dass der normale Aktivierungsvorgang des Tab-Item abgefangen wird, muß dass nachgeholt werden.
    Einfach eine Zeile mehr in der Funktion "_Check", sieht dann so aus:

    [autoit]

    Func _Check()
    If Not $check Then Return
    For $i = 1 To $aDisableItem[0]
    If $IndexMouseOver = $i Then
    $check = False
    Return
    EndIf
    Next
    _GUICtrlTab_SetCurSel(GUICtrlGetHandle($Tab), $IndexMouseOver)
    GUICtrlSetState(Execute('$Tab' & $IndexMouseOver +1), $GUI_SHOW) ; == TAB-Item-ID muß dazu fortlaufende Nummer haben um mit dem Index zu verknüpfen
    $check = False
    EndFunc ;==>_Check

    [/autoit]