【问题标题】:AHK Multidimensional list navigatable with Arrow keys and EnterAHK 多维列表可使用箭头键和 Enter 导航
【发布时间】:2019-07-30 08:58:55
【问题描述】:

在 AHK (Autohotkey) 中,我需要从一个表中加载一个列表,该表具有主要类别和每个单独的条目。

blue            red             green               yellow
Item 1 of blue  Item 1 of red   Item 1 of green     Item 1 of yellow
Item 2 of blue  Item 2 of red   Item 2 of green     Item 2 of yellow
Item 3 of blue  Item 3 of red   Item 3 of green     Item 3 of yellow
Item 4 of blue                  Item 4 of green     Item 4 of yellow
Item 5 of blue                  Item 5 of green 
                                Item 6 of green 
                                Item 7 of green 

(如果能够从文件中加载表格而不是将其直接写入脚本代码,那就太好了。但是我不知道将表格保存在哪种表格格式以及如何将其动态包含到脚本中. 但这只是一个旁注)。

此处的表格也可以视为实际表格:

https://docs.google.com/spreadsheets/d/1rFDX_XpD0seDHpkvqSHLnE8HwTmJHwjSv_zgaPCqG0Y

这是一个详细的视频模拟(可以在浏览器中流式传输):

视频: https://drive.google.com/open?id=1k4JBy9DShBKwQRswdz8Rxrb9wfvXXGmy

视频是用我能够创建的一些列表的屏幕截图制作的。然后将它一起编辑,使其看起来像是一个实际的工作脚本。

如视频中所示,列表必须可以使用向上和向下箭头键导航。按 Enter 键应打开所选类别的列表。列表项本身也应该可以使用箭头键导航。

应该可以使用 Backspace 或 Arrow Left 键返回到主类别列表(如视频中所示)。

虽然,当不返回,而是在一个列表项上按 Enter 时,脚本应该将所选主类别的索引号和实际所选项目的索引号存储到两个临时变量中。有了这些变量,我必须执行进一步的操作。

这是我到目前为止所得到的。我只能为视频模拟创建列表。

#SingleInstance, Force

;GUi Layout
;-----------------------------------

Gui, +AlwaysOnTop

;Gui,+Delimiter
Gui, Add, ListBox, x20 y20 w180 r10 AltSubmit vList1 gSubit_All ,blue|red|green|yellow|
Gui, Add, ListBox, x+40 w200 r10 AltSubmit vList2 gSubit_All ,Item 1 of green|Item 2 of green|Item 3 of green|Item 4 of green|Item 5 of green|Item 6 of green|Item 7 of green|
Gui, Add, ListBox, x+40 w200 r10 AltSubmit vList3 gSubit_All ,Item 1 of blue|Item 2 of blue|Item 3 of blue|Item 4 of blue|Item 5 of blue|
Gui, Add, ListBox, x+40 w200 r10 AltSubmit vList4 gSubit_All ,
Gui, Show, x800 y150 w500 h200, Helper HS

return

任何有关动态加载表格的帮助,或如何使用 Enter 键和左箭头键在两个列表中导航的任何帮助都将不胜感激。

【问题讨论】:

    标签: list multidimensional-array autohotkey arrow-keys


    【解决方案1】:

    关于从原始文件加载,这可能是个问题。我找不到任何关于 AHK 直接与 Google 表格交互的信息。如果您可以将文件导出为 CSV 之类的文件,那么您可以使用 FileRead 从中读取文件,然后基本上可以随心所欲地使用它。下面的示例使用您作为 CSV 导出到桌面的文件。它将第一行用于第一个列表并将其余部分一起转储以用于第二个列表。

    FileRead , sCSVRaw , %A_Desktop%/AHK list.csv
    Loop , Parse , sCSVRaw , `n
    {
        If A_Index = 1
        {
            sHeader := RegExReplace( A_LoopField , ",|`r" , "|" )
            Continue
        }
        sDataDump .= A_LoopField
    }
    sDataDump := StrReplace( sDataDump , "`r" , "," )
    

    对于您问题的主要部分,我会通过使用OnMessage() 函数让您的脚本监控某些按键,然后在检测到适当的按键后执行您想要的操作来解决此问题。

    OnMessage( 0x203 , "f_DblClick" ) ; Monitors left doubleclick
    OnMessage( 0x100 , "f_KeyPress" ) ; Monitors keypresses (specifically, keyup events)
    

    如果有机会,我会添加一个工作示例。 编辑:我有机会;给你:

    aData := []
    FileRead , sCSVRaw , %A_Desktop%/AHK list.csv
    Loop , Parse , sCSVRaw , `n
    {
        If A_Index = 1
        {
            sHeader := RegExReplace( A_LoopField , ",|`r" , "|" )
            Continue
        }
        ++nCt
        Loop , Parse , A_LoopField , `,
            aData[ A_Index , nCt ] := RegExReplace( A_LoopField , "`r" , "" )
    }
    
    Gui , +AlwaysOnTop
    Gui , Add , ListBox , x20 y20 w180 r10 Choose1 vList1 AltSubmit gSubmit1 , %sHeader%
    Gui , Add , ListBox , x+40 w200 r10 vList2 AltSubmit gSubmit2 ,
    Gui , Show , x800 y150 w500 h200 , Helper HS
    
    OnMessage( 0x100 , "f_KeyPress" )
    Return
    
    f_KeyPress( wP ) ; 37 = left, 39 = right, 13 = enter
    {
        global bLeft := false , global bRight := false , global bEnter := false
        If ( wP = 37 )
            bLeft := true
        If ( wP = 39 )
            bRight := true
        If ( wP = 13 )
            bEnter := true
        If ( bLeft || bRight || bEnter )
            GoSub , sub_KeyPress
    }
    
    sub_KeyPress:
    GuiControlGet , sFocus , FocusV
    Gui , Submit , NoHide
    If ( bLeft && sFocus = "List2" )
    {
        List2 := ""
        GuiControl ,, List2 , |
        GuiControl , Focus , List1
    }
    If (( bRight || bEnter ) && sFocus = "List1" )
    {
        sList2 := ""
        Loop , % nCt
            If !( aData[ List1 , A_Index ] = "")
                sList2 .= "|" . aData[ List1 , A_Index ]
        GuiControl ,, List2 , %sList2% 
        GuiControl , Focus , List2
        GuiControl , Choose , List2 , 1
    }
    If ( bEnter && sFocus = "List2" )
        MsgBox , List1: %List1%`nList2: %List2%
    Return
    
    Submit1:
    If (( bLeft || bRight ) && List1 )
    {
        bLeft := false , bRight := false
        GuiControl , Choose , List1 , %List1%
    }
    Return
    Submit2:
    If (( bLeft || bRight ) && List2 )
    {
        bLeft := false , bRight := false
        GuiControl , Choose , List2 , %List2%
    }
    Return
    

    这比我预期的要长得多(也许有更好的方法??),但它有效。如果您在遵循代码时遇到问题,请告诉我,我将编辑并添加一些 cmets 进行解释。

    此处显示的旧代码供参考和/或比较:

    FileRead , sCSVRaw , %A_Desktop%/AHK list.csv
    Loop , Parse , sCSVRaw , `n
    {
        If A_Index = 1
        {
            sHeader := RegExReplace( A_LoopField , ",|`r" , "|" )
            Continue
        }
        sDataDump .= A_LoopField
    }
    sDataDump := StrReplace( sDataDump , "`r" , "," )
    
    Gui , +AlwaysOnTop
    Gui , Add , ListBox , x20 y20 w180 r10 Choose1 vList1 gSubmit1 , %sHeader%
    Gui , Add , ListBox , x+40 w200 r10 vList2 AltSubmit gSubmit2 ,
    Gui , Show , x800 y150 w500 h200 , Helper HS
    
    OnMessage( 0x100 , "f_KeyPress" )
    Return
    
    f_KeyPress( wP ) ; 37 = left, 39 = right, 13 = enter
    {
        global bLeft := false , global bRight := false , global bEnter := false
        If ( wP = 37 )
            bLeft := true
        If ( wP = 39 )
            bRight := true
        If ( wP = 13 )
            bEnter := true
        If ( bLeft || bRight || bEnter )
            GoSub , sub_KeyPress
    }
    
    sub_KeyPress:
    GuiControlGet , sFocus , FocusV
    Gui , Submit , NoHide
    If ( bLeft && sFocus = "List2" )
    {
        List2 := ""
        GuiControl ,, List2 , |
        GuiControl , Focus , List1
    }
    If (( bRight || bEnter ) && sFocus = "List1" )
    {
        sList2 := ""
        Loop , Parse , sDataDump , `,
            If InStr( A_LoopField , Trim( List1 ))
                sList2 .= "|" . A_loopField
        GuiControl ,, List2 , %sList2% 
        GuiControl , Focus , List2
        GuiControl , Choose , List2 , 1
    }
    If ( bEnter && sFocus = "List2" )
    {
        Loop , Parse , sHeader , "|"
            If ( A_LoopField = List1 )
                nList1Output := A_Index
        nList2Output := List2
        MsgBox , List1: %nList1Output%`nList2: %nList2Output%
    }
    Return
    
    Submit1:
    If (( bLeft || bRight ) && List1 )
    {
        bLeft := false , bRight := false
        GuiControl , ChooseString , List1 , %List1%
    }
    Return
    Submit2:
    If (( bLeft || bRight ) && List2 )
    {
        bLeft := false , bRight := false
        GuiControl , Choose , List2 , %List2%
    }
    Return
    

    【讨论】:

    • 使用不同的表格文件格式是完全可以的。虽然我不知道如何将其内容放入我已经拥有的实际列表框中。我对 Gui 编程相当陌生,抱歉。期待您的“工作示例”。非常感谢!
    • 没问题。我用代码更新了它供您测试。如果您有任何问题或疑问,请告诉我。
    • 到目前为止真是太棒了!处理是完美的。一件事:据我观察,目前在您的版本中,每个子列表的项目必须在名称中具有主类别的名称才能与主类别关联,对吗?实际上,我在表中包含名称只是为了演示。 ...
    • ...如果这不是必要条件,但如果它能够仅通过表格中的位置识别其关联,则完美。我刚刚向表中添加了一些不包含其父名称的值。如果这些也能显示出来,那就完美了……
    • ...如果不可避免地必须包含父名称,那么我需要一种机制来至少将父名称隐藏在 UI 中的项目名称中。这两个选项之一可能吗?但是,到目前为止,工作非常出色!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-14
    • 1970-01-01
    相关资源
    最近更新 更多