有没有办法阅读F#控制台应用程序中特定行上显示的文本?

时间:2018-07-26 20:30:44

标签: .net f#

我想将特定行中的文本放入变量中。我可以使用Console.CursorLeft和Console.CursorTop做到这一点吗?程序甚至可能知道光标当前在哪个字母上?我有一个程序,您可以在其中使用箭头键突出显示某一行,但是它要求您已经知道该行上的内容并重复该操作。

到目前为止,该程序可以正常运行,以便您可以了解我要做什么。

open System

Console.BackgroundColor <- ConsoleColor.White
Console.ForegroundColor <- ConsoleColor.Black
printfn "OPTION 1"
Console.BackgroundColor <- ConsoleColor.Black
Console.ForegroundColor <- ConsoleColor.White
printfn "Option 2"
printfn "Option 3"

Console.SetCursorPosition(0, 0)

let mutable exit = false

while not exit do
    let mutable key = Console.ReadKey()
    if key.Key.Equals(ConsoleKey.UpArrow) then
        Console.SetCursorPosition(0, Console.CursorTop - 1)
    if key.Key.Equals(ConsoleKey.DownArrow) then
        Console.SetCursorPosition(0, Console.CursorTop + 1)
    if key.Key.Equals(ConsoleKey.Enter) then
        let selected = Console.CursorTop + 1
        Console.SetCursorPosition(0, 3)
        printfn "You selected %i" (selected)
        exit <- true
    let mutable test = Console.CursorTop
    Console.SetCursorPosition(0, 0)
    printfn "Option 1"
    printfn "Option 2"
    printfn "Option 3"
    if test = 0 then
        Console.SetCursorPosition(0, 0)
        Console.BackgroundColor <- ConsoleColor.White
        Console.ForegroundColor <- ConsoleColor.Black
        printfn "OPTION 1"
    if test = 1 then
        Console.SetCursorPosition(0, 1)
        Console.BackgroundColor <- ConsoleColor.White
        Console.ForegroundColor <- ConsoleColor.Black
        printfn "OPTION 2"
    if test = 2 then
        Console.SetCursorPosition(0, 2)
        Console.BackgroundColor <- ConsoleColor.White
        Console.ForegroundColor <- ConsoleColor.Black
        printfn "OPTION 3"
    Console.BackgroundColor <- ConsoleColor.Black
    Console.ForegroundColor <- ConsoleColor.White
    Console.SetCursorPosition(0, test)

Console.Read() |> ignore

1 个答案:

答案 0 :(得分:2)

鉴于评论中的澄清,我认为绝对没有理由以需要读取打印到控制台的文本的方式编写应用程序。

如果这样做,从本质上讲您将依赖控制台文本来维护应用程序的状态。换句话说,您将状态保持在有限大小的2D字符数组中!

更好的方法是使用F#类型表示状态。例如,您可以定义一条记录,其中保留菜单选项,选择内容和标记是否进行选择的标记:

type State = 
  { Options : string list
    Selection : int
    Completed : bool }

现在,您可以定义一个打印状态的函数:

let printMenu menu = 
  Console.SetCursorPosition(0, 0)
  for i, option in Seq.indexed menu.Options do
    if i = menu.Selection then
      Console.BackgroundColor <- ConsoleColor.White
      Console.ForegroundColor <- ConsoleColor.Black
    printfn "%s" option
    Console.BackgroundColor <- ConsoleColor.Black
    Console.ForegroundColor <- ConsoleColor.Gray

还有一个在按下键时计算新状态的函数:

let handleKey (key:ConsoleKeyInfo) state = 
  match key.Key with
  | ConsoleKey.UpArrow -> { state with Selection = state.Selection-1 }
  | ConsoleKey.DownArrow -> { state with Selection = state.Selection+1 }
  | ConsoleKey.Enter -> { state with Completed = true }
  | _ -> state

最后,您可以使用菜单选项定义初始状态。我将保留您的while循环,因此这将是一个可变变量:

let mutable state = 
  { Options = ["Option 1"; "Option 2"; "Option 3"] 
    Completed = false
    Selection = 0 }      

现在,主要的应用程序逻辑非常简单。只需在state.Completed为假时保持循环,打印菜单,读取键并更新状态即可:

while not state.Completed do
  printMenu state
  let key = Console.ReadKey()
  state <- handleKey key state

Console.SetCursorPosition(0, 3)
printfn "You selected %i" state.Selection

这种构造应用程序的方式更加清晰,因为它使状态保持在显式数据类型中,并且与在其上进行操作的各种功能分开。