F# GUI应用:如何将按钮点击状态输出从控制台改为TextBox?
问题描述
正在通过修改一个处理点击事件的模板应用学习F#,当前点击按钮后仅能将状态输出到控制台,希望实现点击按钮时更新TextBox控件。
Main模块代码:
open FSharpx.Control.Observable // Fsharpx module Main = type State = int list module GuiInterface = type UserAction = | Zero | One | Two | Three let observables = List.reduce Observable.merge [ Observable.map (fun _-> Zero) Gui.btnAdd0.Click; Observable.map (fun _-> One) Gui.btnAdd1.Click; Observable.map (fun _-> Two) Gui.btnAdd2.Click; Observable.map (fun _-> Three) Gui.btnAdd3.Click; ] let rec loop observable (state : State) = async{ printfn "%A" state let! somethingObservable = Async.AwaitObservable(observable) match somethingObservable with | GuiInterface.Zero -> return! loop observable (0::state) | GuiInterface.One -> return! loop observable (1::state) | GuiInterface.Two -> return! loop observable (2::state) | GuiInterface.Three -> return! loop observable (3::state) | _ -> failwith "Not implemented yet!" } Async.StartImmediate(loop GuiInterface.observables []); System.Windows.Forms.Application.Run(Gui.form)
Gui模块代码:
module Gui = open System.Windows.Forms let form = new Form(Text="FSharpx", TopMost=true) let btnAdd0 = new Button(Text="Add 0") let btnAdd1 = new Button(Text="Add 1", Top=20) let btnAdd2 = new Button(Text="Add 2", Top=40) let btnAdd3 = new Button(Text="Add 3", Top=60) let display = new TextBox(Text="click the buttons", Width=200, Left=200) form.Controls.AddRange [| btnAdd0 ; btnAdd1; btnAdd2; btnAdd3; display |]
已理解observables是将按钮点击事件转换为定义的UserAction类型并合并,observable会等待用户输入后完成类型转换,但不知道如何将原本输出到控制台的int列表转换为字符串并更新TextBox,恳请技术指导。
解决方案
要实现点击按钮更新TextBox,只需在loop函数中添加更新文本框的逻辑,将状态列表转换为字符串后赋值给TextBox的Text属性即可。
修改后的Main模块代码:
open FSharpx.Control.Observable // Fsharpx module Main = type State = int list module GuiInterface = type UserAction = | Zero | One | Two | Three let observables = List.reduce Observable.merge [ Observable.map (fun _-> Zero) Gui.btnAdd0.Click; Observable.map (fun _-> One) Gui.btnAdd1.Click; Observable.map (fun _-> Two) Gui.btnAdd2.Click; Observable.map (fun _-> Three) Gui.btnAdd3.Click; ] let rec loop observable (state : State) = async{ // 将状态列表转换为字符串并更新TextBox let stateText = state |> List.map string |> String.concat ", " Gui.display.Text <- stateText printfn "%A" state let! somethingObservable = Async.AwaitObservable(observable) match somethingObservable with | GuiInterface.Zero -> return! loop observable (0::state) | GuiInterface.One -> return! loop observable (1::state) | GuiInterface.Two -> return! loop observable (2::state) | GuiInterface.Three -> return! loop observable (3::state) | _ -> failwith "Not implemented yet!" } Async.StartImmediate(loop GuiInterface.observables []); System.Windows.Forms.Application.Run(Gui.form)
关键修改说明:
- 状态转字符串:用
List.map string把列表中的每个整数转换成字符串,再通过String.concat ", "用逗号和空格连接所有元素,生成可读性好的文本。 - 更新TextBox:直接给
Gui.display.Text赋值,就能实时更新文本框内容。 - 线程安全:由于
Async.StartImmediate是在UI线程启动的,且Async.AwaitObservable处理WinForms事件时会自动回到UI线程上下文,所以不需要额外调用控件的Invoke方法,直接修改属性是安全的。
内容的提问来源于stack exchange,提问作者zellez11
相关产品推荐
相关产品推荐

