List AHK多维列表可使用箭头键导航并输入

List AHK多维列表可使用箭头键导航并输入,list,multidimensional-array,autohotkey,arrow-keys,List,Multidimensional Array,Autohotkey,Arrow Keys,在AHK(自动热键)中,我需要从一个表中加载一个列表,该表包含主要类别,每个类别都有自己的条目 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

在AHK(自动热键)中,我需要从一个表中加载一个列表,该表包含主要类别,每个类别都有自己的条目

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 
(如果能够从文件中加载表而不是直接将其写入脚本代码,那就太好了。但是我不知道保存表的格式以及如何将其动态地包含到脚本中。但这只是一个旁注)

该表格也可以在此处作为实际表格查看:

这是一个详细的视频模拟(可以在浏览器中播放):

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
视频:

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

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

使用退格键或向左箭头键(如视频中所示)可以返回主类别列表

但是,如果不返回,而是在一个列表项上按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键和Arrow Left键浏览两个列表的帮助,我们将不胜感激。

关于从原始文件加载,这可能是一个问题。我还没有找到任何关于AHK与谷歌表单直接交互的信息。如果您可以将文件导出为类似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
事实证明,这比我预期的要长得多(也许有更好的方法??),但它确实有效。如果您在遵循代码时遇到问题,请告诉我,我将编辑并添加一些注释进行解释

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

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

关于从原始文件加载,这可能是一个问题。我还没有找到任何关于AHK与谷歌表单直接交互的信息。如果您可以将文件导出为类似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
事实证明,这比我预期的要长得多(也许有更好的方法??),但它确实有效。如果您在遵循代码时遇到问题,请告诉我,我将编辑并添加一些注释进行解释

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

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中的项目名称中隐藏父名称。这两个选项中的一个是可能的?不过,到目前为止,还是做得很好!使用不同的表文件格式完全可以。虽然我不知道如何将它的内容放入我已经有的实际列表框中。对不起,我对Gui编程相当陌生。期待您的“工作榜样”。非常感谢你!没问题。我用代码更新了它,供您测试。如果你有任何问题,请告诉我。到目前为止,这真是太棒了!操作非常完美。有一件事:据我观察,目前在您的版本中,每个子列表的项目必须在与主类别关联的名称中包含主类别的名称,对吗?实际上,我把这些名字放在表格里只是为了演示。。。。。。如果这不是一个必要的条件,但如果它仅仅通过在表格中的位置来认识到它的关联,那么它将是完美的。