Apple 脚本:返回菜单中的功能
Apple Script: Go back-function in menus
我不太精通 AppleScript,所以也许有人可以在这里提供帮助:
我有几个菜单。比方说,菜单 A 有三个选项,这三个选项导致菜单 B1、B2、B3,具体取决于在菜单 A 中选择的选项。B 菜单导致 C 菜单,依此类推。我有点烦恼,每次我“取消”时,我都需要从头开始。 “返回”按钮在这种情况下会非常有用。
我知道 choose from list
-函数只允许是和否,可以这么说,但是有没有可能以某种方式实现后退按钮?
我的代码看起来像这样(我们在菜单 B 中):
if MenuB is false then error number -128 -- user canceled
然后我尝试通过以下方式实现“返回”功能:
if MenuB is false then set MenuA to (choose from list {"MenuB1", "MenuB2", "MenuB3"} with prompt "Menu A" default items "None" OK button name {"Go"} cancel button name {"Quit"})
然而,这会创建一个新菜单,而不是指在菜单 B 脚本之前创建的菜单。
Tl;dr:那么是否可以在不创建新菜单的情况下引用现有菜单 based on choose from list
。或者有没有办法通过 AppleScript 在菜单中实现“后退”按钮?
期待您的想法!
代码摘录:
# Main Menu
set MainMenu to (choose from list {"Item1", "Item2", "Item3"} with prompt "Main Menu" default items "None" OK button name {"Go"} cancel button name {"Quit"})
if MainMenu is false then error number -128 -- user canceled
# Button 1: Item 1
if MainMenu contains "Item1" then
# Sub-Button 1: Item 1
set SubButton to (choose from list {"Create", "Rename"} with prompt "Settings" default items "None" OK button name {"Choose"} cancel button name {"Quit"})
if SubButton is false then error number -128 -- user canceled
# Sub-Sub-Button 1: Item 1
if SubButton contains "Create" then
(...)
在不知道菜单的确切数量以及它们如何交互的情况下,最简单的方法可能是实现一个堆栈,其中可以根据对话框结果将项目推入或弹出堆栈。然后这只是组织和连接菜单的问题,因为在 运行 失去耐心之前,您可能会 运行 出栈 space。尝试仅使用一长串 if
语句在嵌套或互连的菜单中来回导航会导致阴暗面。
为了使菜单列表更易于管理,可以将它们放入记录之类的集合对象中,而不是对对话语句进行硬编码,记录键用于跟踪当前和上一个列出。从每个 choose from list
对话框中,可以将当前选择推到堆栈顶部,如果返回,则从中弹出前一个项目。
以下示例中使用了一点点 AppleScriptObjC 来动态查找记录键,因为常规 AppleScript 无法做到这一点。列表包含各种菜单项,它们也用于查找其他菜单列表的键 - 用管道围绕记录键允许它们具有 spaces 和标点符号,因此几乎任何文本都可以用作关键。使用菜单项文本作为记录键还允许绕圈和跳转(示例脚本也演示了这一点),所以在布置菜单连接时要注意。最终的最终值保存在不同的记录中,并且是单个项目(字符串或列表)。最终结果也用于选择对话框中以进行验证并允许返回。
请注意,使用时髦的逗号位置是为了让记录格式更易于阅读。
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property stack : {"base"} -- LIFO, starting with key of the base menu
property menus : ¬
{base:{"menu A", "menu B", "menu C"} ¬
, |menu A|:{"subMenu A1", "subMenu A2", "subMenu A3"} ¬
, |menu B|:{"subMenu B1", "subMenu B2", "subMenu B3"} ¬
, |menu C|:{"A key", "A little longer key", "The quick brown fox jumped over the lazy dog's key"} ¬
, |subMenu A1|:{"Action1", "Action2", "Action3"} ¬
, |subMenu A2|:{"Action4", "Action5", "Action6"} ¬
, |subMenu A3|:{"Action7", "Action8", "Action9"} ¬
, |subMenu B1|:{"menu A", "menu B", "menu C"} ¬
, |subMenu B2|:{"subMenu A1", "subMenu A2", "subMenu A3"} ¬
, |subMenu B3|:{"A key", "A little longer key", "The quick brown fox jumped over the lazy dog's key"} ¬
, |A key|:{"Action1", "Action2", "Action3"} ¬
, |A little longer key|:{"Action4", "Action5", "Action6"} ¬
, |The quick brown fox jumped over the lazy dog's key|:{"Action7", "Action8", "Action9"}}
property actions : ¬
{Action1:"Action one", Action2:"Action two", Action3:"Action three", Action4:"Action four", Action5:"Action five", Action6:"Action six", Action7:"Action seven", Action8:"Action eight", Action9:"Action 9"}
on run -- example
set menuDict to current application's NSDictionary's dictionaryWithDictionary:menus
set actionDict to current application's NSDictionary's dictionaryWithDictionary:actions
set cancelName to "Quit"
repeat
set tos to first item of stack
set choices to (menuDict's objectForKey:tos) -- get menu
if choices is missing value then -- handle missing key
log "menu key " & quoted form of tos & " not found, trying actions"
set choices to (actionDict's objectForKey:tos) -- try actions
if choices is missing value then log "actions key " & quoted form of tos & " not found"
end if
set theChoice to (choose from list (choices as list) default items {"msng"} cancel button name cancelName) -- select missing value
if theChoice is false then
if (count stack) is 1 then error number -128 -- cancel
set stack to rest of stack -- pop
if (count stack) is 1 then set cancelName to "Quit" -- last one
else
if (count (choices as list)) is 1 then exit repeat -- final action result selected
set beginning of stack to theChoice as text -- push
set cancelName to "Go Back"
end if
end repeat
#showResult(stack, actionDict) -- uncomment to show the result
runWorkflow(((actionDict's objectForKey:(first item of stack)) as text))
end run
to showResult(stack, dictionary) -- show the final result action
set {tempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " > "}
set keys to (reverse of stack) as text
set AppleScript's text item delimiters to tempTID
set value to quoted form of ((dictionary's objectForKey:(first item of stack)) as text)
if value is quoted form of "missing value" then set value to value & return & return & "A menu or actions key was not found - see log."
display dialog "Key sequence: " & keys & return & "Final value: " & value with title "Final Result" buttons "OK" default button 1
end showResult
to runWorkflow(workflowName) -- run an Automator workflow
set basepath to POSIX path of (path to desktop) -- change as desired
set workflowpath to basepath & workflowName -- POSIX path/name to add to the basePath
set command to "/usr/bin/automator " & quoted form of workflowpath
set output to (do shell script command)
-- do whatever with the output
end runAction
我不太精通 AppleScript,所以也许有人可以在这里提供帮助:
我有几个菜单。比方说,菜单 A 有三个选项,这三个选项导致菜单 B1、B2、B3,具体取决于在菜单 A 中选择的选项。B 菜单导致 C 菜单,依此类推。我有点烦恼,每次我“取消”时,我都需要从头开始。 “返回”按钮在这种情况下会非常有用。
我知道 choose from list
-函数只允许是和否,可以这么说,但是有没有可能以某种方式实现后退按钮?
我的代码看起来像这样(我们在菜单 B 中):
if MenuB is false then error number -128 -- user canceled
然后我尝试通过以下方式实现“返回”功能:
if MenuB is false then set MenuA to (choose from list {"MenuB1", "MenuB2", "MenuB3"} with prompt "Menu A" default items "None" OK button name {"Go"} cancel button name {"Quit"})
然而,这会创建一个新菜单,而不是指在菜单 B 脚本之前创建的菜单。
Tl;dr:那么是否可以在不创建新菜单的情况下引用现有菜单 based on choose from list
。或者有没有办法通过 AppleScript 在菜单中实现“后退”按钮?
期待您的想法!
代码摘录:
# Main Menu
set MainMenu to (choose from list {"Item1", "Item2", "Item3"} with prompt "Main Menu" default items "None" OK button name {"Go"} cancel button name {"Quit"})
if MainMenu is false then error number -128 -- user canceled
# Button 1: Item 1
if MainMenu contains "Item1" then
# Sub-Button 1: Item 1
set SubButton to (choose from list {"Create", "Rename"} with prompt "Settings" default items "None" OK button name {"Choose"} cancel button name {"Quit"})
if SubButton is false then error number -128 -- user canceled
# Sub-Sub-Button 1: Item 1
if SubButton contains "Create" then
(...)
在不知道菜单的确切数量以及它们如何交互的情况下,最简单的方法可能是实现一个堆栈,其中可以根据对话框结果将项目推入或弹出堆栈。然后这只是组织和连接菜单的问题,因为在 运行 失去耐心之前,您可能会 运行 出栈 space。尝试仅使用一长串 if
语句在嵌套或互连的菜单中来回导航会导致阴暗面。
为了使菜单列表更易于管理,可以将它们放入记录之类的集合对象中,而不是对对话语句进行硬编码,记录键用于跟踪当前和上一个列出。从每个 choose from list
对话框中,可以将当前选择推到堆栈顶部,如果返回,则从中弹出前一个项目。
以下示例中使用了一点点 AppleScriptObjC 来动态查找记录键,因为常规 AppleScript 无法做到这一点。列表包含各种菜单项,它们也用于查找其他菜单列表的键 - 用管道围绕记录键允许它们具有 spaces 和标点符号,因此几乎任何文本都可以用作关键。使用菜单项文本作为记录键还允许绕圈和跳转(示例脚本也演示了这一点),所以在布置菜单连接时要注意。最终的最终值保存在不同的记录中,并且是单个项目(字符串或列表)。最终结果也用于选择对话框中以进行验证并允许返回。
请注意,使用时髦的逗号位置是为了让记录格式更易于阅读。
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property stack : {"base"} -- LIFO, starting with key of the base menu
property menus : ¬
{base:{"menu A", "menu B", "menu C"} ¬
, |menu A|:{"subMenu A1", "subMenu A2", "subMenu A3"} ¬
, |menu B|:{"subMenu B1", "subMenu B2", "subMenu B3"} ¬
, |menu C|:{"A key", "A little longer key", "The quick brown fox jumped over the lazy dog's key"} ¬
, |subMenu A1|:{"Action1", "Action2", "Action3"} ¬
, |subMenu A2|:{"Action4", "Action5", "Action6"} ¬
, |subMenu A3|:{"Action7", "Action8", "Action9"} ¬
, |subMenu B1|:{"menu A", "menu B", "menu C"} ¬
, |subMenu B2|:{"subMenu A1", "subMenu A2", "subMenu A3"} ¬
, |subMenu B3|:{"A key", "A little longer key", "The quick brown fox jumped over the lazy dog's key"} ¬
, |A key|:{"Action1", "Action2", "Action3"} ¬
, |A little longer key|:{"Action4", "Action5", "Action6"} ¬
, |The quick brown fox jumped over the lazy dog's key|:{"Action7", "Action8", "Action9"}}
property actions : ¬
{Action1:"Action one", Action2:"Action two", Action3:"Action three", Action4:"Action four", Action5:"Action five", Action6:"Action six", Action7:"Action seven", Action8:"Action eight", Action9:"Action 9"}
on run -- example
set menuDict to current application's NSDictionary's dictionaryWithDictionary:menus
set actionDict to current application's NSDictionary's dictionaryWithDictionary:actions
set cancelName to "Quit"
repeat
set tos to first item of stack
set choices to (menuDict's objectForKey:tos) -- get menu
if choices is missing value then -- handle missing key
log "menu key " & quoted form of tos & " not found, trying actions"
set choices to (actionDict's objectForKey:tos) -- try actions
if choices is missing value then log "actions key " & quoted form of tos & " not found"
end if
set theChoice to (choose from list (choices as list) default items {"msng"} cancel button name cancelName) -- select missing value
if theChoice is false then
if (count stack) is 1 then error number -128 -- cancel
set stack to rest of stack -- pop
if (count stack) is 1 then set cancelName to "Quit" -- last one
else
if (count (choices as list)) is 1 then exit repeat -- final action result selected
set beginning of stack to theChoice as text -- push
set cancelName to "Go Back"
end if
end repeat
#showResult(stack, actionDict) -- uncomment to show the result
runWorkflow(((actionDict's objectForKey:(first item of stack)) as text))
end run
to showResult(stack, dictionary) -- show the final result action
set {tempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " > "}
set keys to (reverse of stack) as text
set AppleScript's text item delimiters to tempTID
set value to quoted form of ((dictionary's objectForKey:(first item of stack)) as text)
if value is quoted form of "missing value" then set value to value & return & return & "A menu or actions key was not found - see log."
display dialog "Key sequence: " & keys & return & "Final value: " & value with title "Final Result" buttons "OK" default button 1
end showResult
to runWorkflow(workflowName) -- run an Automator workflow
set basepath to POSIX path of (path to desktop) -- change as desired
set workflowpath to basepath & workflowName -- POSIX path/name to add to the basePath
set command to "/usr/bin/automator " & quoted form of workflowpath
set output to (do shell script command)
-- do whatever with the output
end runAction