AHK Многомерный список, по которому можно перемещаться с помощью клавиш со стрелками и Enter

В 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_XpD0seDHpkvqSHLnE8HwTmJHwjPCqSv_zga>

Вот подробное видеомоделирование (можно транслировать в браузере):

Видео: https://drive.google.com/open?id=1k4JBy9DShBKwQRswdz8Rxrb9wfvXXGmy

Видео было сделано со скриншотами некоторых списков, которые мне удалось создать. Затем он редактируется вместе, чтобы он выглядел как настоящий рабочий сценарий.

Как видно из видео, списки должны перемещаться с помощью клавиш со стрелками вверх и вниз. Нажатие клавиши Enter должно открыть список выбранной категории. Сами элементы списка также должны быть доступны для навигации с помощью клавиш со стрелками.

Возврат к списку основных категорий должен быть возможен с помощью клавиши Backspace или стрелки влево (как на видео).

Однако, если не возвращаться назад, а вместо этого нажимать 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 и клавиши со стрелкой влево.


person DanielM    schedule 08.03.2019    source источник


Ответы (1)


Что касается загрузки из исходного файла, это может быть проблемой. Мне не удалось найти ничего о том, что AHK напрямую взаимодействует с Google Sheets. Если у вас все в порядке с экспортом файла во что-то вроде 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)

Когда у меня будет возможность, я добавлю рабочий пример. EDIT: у меня есть шанс; Ну вот:

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
person EJE    schedule 08.03.2019
comment
Использование другого формата файла таблицы совершенно нормально. Хотя я понятия не имею, как поместить его содержимое в фактические списки, которые у меня уже есть. Я довольно новичок в программировании Gui, извините. С нетерпением жду вашего рабочего примера. Большое спасибо! - person DanielM; 08.03.2019
comment
Без проблем. Я обновил его кодом для проверки. Пожалуйста, дайте мне знать, если у вас есть какие-либо проблемы или вопросы. - person EJE; 08.03.2019
comment
Пока это совершенно потрясающе! Управляемость идеальная. Одна вещь: насколько я заметил, в настоящее время в вашей версии элементы каждого подсписка должны иметь название основной категории в названии, чтобы быть связанным с основной категорией, верно? На самом деле я включил имена в таблицу только для демонстрации. ... - person DanielM; 08.03.2019
comment
...Идеально было бы, если бы это не было необходимым условием, а если бы он распознавал свою ассоциацию только по положению в таблице. Я просто добавил в таблицу некоторые значения, которые не содержат своего родительского имени. Если бы их тоже можно было показать, то было бы идеально.... - person DanielM; 08.03.2019
comment
...ЕСЛИ неизбежно включать родительские имена, тогда мне понадобится механизм, чтобы хотя бы скрыть родительские имена внутри имен элементов в пользовательском интерфейсе. Возможен один из этих 2-х вариантов? Но опять же, очень хорошая работа до сих пор! - person DanielM; 08.03.2019
comment
Ах, я был так сосредоточен на том, чтобы код работал, что не учел, что это всего лишь имена-заполнители. Это изменит способ хранения информации - возможно, в массиве. Я постараюсь передать вам что-нибудь в ближайшее время. - person EJE; 08.03.2019
comment
Новый код не требует, чтобы имя заголовка было в данных. Единственное, что может вызвать проблемы, это наличие пустых ячеек заголовка. Пожалуйста, дайте мне знать, как это происходит для вас. - person EJE; 09.03.2019