1- // Learn more about F# at http://docs.microsoft.com/dotnet/fsharp
2- module Program
3-
4- open System
5- open FSharp.Control
6- open Fable.Python
7- open Fable.Python .TkInter
8- open Fable.Python .Queue
9-
10- type Msg =
11- | Place of label : Label * x : int * y : int
12- //| Place of x: int * y: int
13- | Empty
14-
15- let root = Tk()
16- root.title( " Fable Python Rocks on Tkinter!" )
17- let queue = Queue< Msg> ()
18-
19- let source , mouseMoves : IAsyncObserver < int * int >* IAsyncObservable < int * int > = AsyncRx.subject()
20-
21- let workerAsync ( mb : MailboxProcessor < Event >) =
22- let rec messageLoop () =
23- async {
24- let! event = mb.Receive ()
25- do ! source.OnNextAsync(( event.x, event.y))
26-
27- return ! messageLoop ()
28- }
29- messageLoop ()
30-
31- let agent = MailboxProcessor< TkInter.Event>. Start( workerAsync)
32-
33- let frame = Frame( root, width= 800 , height= 600 , bg= " white" )
34- frame.bind( " <Motion>" , agent.Post) |> ignore
35- frame.pack()
36-
37- let stream =
38- Seq.toList " TIME FLIES LIKE AN ARROW"
39- |> Seq.mapi ( fun i c -> i, Label( frame, text=( string c), fg= " black" , bg= " white" ))
40- |> AsyncRx.ofSeq
41- |> AsyncRx.flatMap ( fun ( i , label ) ->
42- mouseMoves
43- |> AsyncRx.delay ( 100 * i)
44- |> AsyncRx.map ( fun ( x , y ) -> label, x + i * 12 + 15 , y))
45-
46- let sink ( ev : Notification < Label * int * int >) =
47- async {
48- match ev with
49- | OnNext ( label, x, y) -> queue.put( Place( label, x, y))
50- | OnError( err) -> printfn $" Stream Error: {err}"
51- | _ -> printfn " Stream Completed"
52- return ()
53- }
54-
55- let mainAsync =
56- async {
57- use! disposable = stream.SubscribeAsync( sink)
58-
59- let rec update () =
60- let size = queue.qsize()
61- for _ in 1 .. size do
62- let msg = queue.get( false )
63-
64- match msg with
65- | Place ( label, x, y) -> label.place( x, y)
66- | _ -> ()
67-
68- match size with
69- | n when n > 0 -> root.after( 1 , update)
70- | _ -> root.after( 10 , update)
71-
72- root.after( 1 , update)
73- root.mainloop()
74-
75- return ()
76- }
77-
78- [<EntryPoint>]
79- let main argv =
80- printfn " Started ..."
81- Async.Start mainAsync
82-
83- 0 // return an integer exit code
1+ // Learn more about F# at http://docs.microsoft.com/dotnet/fsharp
2+ module Program
3+
4+ open System
5+ open FSharp.Control
6+ open Fable.Python
7+ open Fable.Python .TkInter
8+ open Fable.Python .Queue
9+
10+ type Msg =
11+ | Place of label : Label * x : int * y : int
12+ //| Place of x: int * y: int
13+ | Empty
14+
15+ let root = Tk()
16+ root.title ( " Fable Python Rocks on Tkinter!" )
17+ let queue = Queue< Msg>()
18+
19+ let source , mouseMoves : IAsyncObserver < int * int > * IAsyncObservable < int * int > = AsyncRx.subject ()
20+
21+ let workerAsync ( mb : MailboxProcessor < Event >) =
22+ let rec messageLoop () =
23+ async {
24+ let! event = mb.Receive()
25+ do ! source.OnNextAsync(( event.x, event.y))
26+
27+ return ! messageLoop ()
28+ }
29+
30+ messageLoop ()
31+
32+ let agent = MailboxProcessor< TkInter.Event>. Start ( workerAsync)
33+
34+ let frame = Frame( root, width = 800 , height = 600 , bg = " white" )
35+ frame.bind ( " <Motion>" , agent.Post) |> ignore
36+ frame.pack ()
37+
38+ let stream =
39+ Seq.toList " TIME FLIES LIKE AN ARROW"
40+ |> Seq.mapi ( fun i c -> i, Label( frame, text = ( string c), fg = " black" , bg = " white" ))
41+ |> AsyncRx.ofSeq
42+ |> AsyncRx.flatMap
43+ ( fun ( i , label ) ->
44+ mouseMoves
45+ |> AsyncRx.delay ( 100 * i)
46+ |> AsyncRx.map ( fun ( x , y ) -> label, x + i * 12 + 15 , y))
47+
48+ let sink ( ev : Notification < Label * int * int >) =
49+ async {
50+ match ev with
51+ | OnNext ( label, x, y) -> queue.put ( Place( label, x, y))
52+ | OnError ( err) -> printfn $" Stream Error: {err}"
53+ | _ -> printfn " Stream Completed"
54+
55+ return ()
56+ }
57+
58+ let mainAsync =
59+ async {
60+ use! disposable = stream.SubscribeAsync( sink)
61+
62+ let rec update () =
63+ let size = queue.qsize ()
64+
65+ for _ in 1 .. size do
66+ let msg = queue.get ( false )
67+
68+ match msg with
69+ | Place ( label, x, y) -> label.place ( x, y)
70+ | _ -> ()
71+
72+ match size with
73+ | n when n > 0 -> root.after ( 1 , update)
74+ | _ -> root.after ( 10 , update)
75+
76+ root.after ( 1 , update)
77+ root.mainloop ()
78+
79+ return ()
80+ }
81+
82+ [<EntryPoint>]
83+ let main argv =
84+ printfn " Started ..."
85+ Async.Start mainAsync
86+
87+ 0 // return an integer exit code
0 commit comments