简体   繁体   中英

F# GUI question (translate C# into F#)

I am translating a C# project into F#. While the logic part is easy, I am confused with the GUI part:

public partial class GomokuGUI : Form {
    private void GomokuGUI_Load(object sender, EventArgs e)
    {
        this.Width = 500;
        this.Height = 550;
        ...
        this.Paint += new PaintEventHandler(GomokuGUI_Paint);
        Graphics gp = this.CreateGraphics();
        DrawChessbord(gp); 
    }

    private void GomokuGUI_Paint(object sender, PaintEventArgs e)
    {
        Graphics gp = e.Graphics;
        DrawChessbord(gp);
    }

    void DrawChessbord(Graphics gp)
    {
        float w, h;
        SolidBrush br = new SolidBrush(linecolor);
        Pen p = new Pen(br, frame);
        gp.DrawLine(p, 20, 45, this.Width - 25, 45);
  ...
    }

   private void Form1_Click(object sender, EventArgs e) {
          Graphics gp = this.CreateGraphics();
                DrawChess(gp);
     ...
}
}

Problem: How to write above C# code in F#...Thanks

Note that F# doesn't have any WinForms designer, so if you have some controls in the Form, you'll need to create them manually (alternatively you can design the form in C#, compile it and reference it from F#). You could start with something like this:

type GomokuGUI() as this =
  inherit Form(Width = 300, Height = 550)

  let DrawChessbord (gp:Graphics) =
    let br = new SolidBrush(linecolor)
    let p = new Pen(br, frame)
    gp.DrawLine(p, 20, 45, this.Width - 25, 45)
    // ...

  let paintGui (e:PaintEventArgs) =
    let gp = e.Graphics
    DrawChessbord(gp)

  do 
    this.Paint.Add(paintGui)
    this.Click.Add(fun _ ->
      let gp = this.CreateGraphics()
      DrawChess(gp) 
      (* ... *) )

It uses a couple of interesting things:

  • You can specify some parameters such as Width and Height in the constructor when calling the base class constructor.
  • You need to use as this in the class declaration, so that you can refer to the class in the do code (which is run during construction)
  • You can use Add to register event handler and you can either give it a named function (eg patinGui ) or a lambda function if you need to do only some simple call (eg handling of Click )

Here's another example of using a form but this time with an outside 3D library called Mogre .

type MogreForm() as this =
    inherit Form()

    let mogrePanel = new System.Windows.Forms.Panel()

    // Between Suspend and Resume Layout is normal form Designer Code
    do  base.SuspendLayout()

        mogrePanel.Location <- new System.Drawing.Point(0, 0)
        mogrePanel.Name <- "mogrePanel"
        mogrePanel.Size <- new System.Drawing.Size(483, 375)
        mogrePanel.TabIndex <- 0

        base.AutoScaleDimensions <- new System.Drawing.SizeF(6.0f, 13.0f)
        base.AutoScaleMode <- System.Windows.Forms.AutoScaleMode.Font
        base.ClientSize <- new System.Drawing.Size(483, 375)
        base.Controls.Add(mogrePanel)
        base.Name <- "MogreForm"
        base.Text <- "Simple F# Mogre Form";

        base.ResumeLayout(false)

        let mogreWin = new OgreWindow(Point(100, 30), mogrePanel.Handle)
        this.Disposed.Add(fun _ -> mogreWin.Dispose())
        this.Paint.Add(fun _ -> mogreWin.Paint())

Here is the full code if you want to try running it. You will need to download Mogre and reference the Mogre dll. Also since this code pulls resources out of the samples you have to set your projects working directory to "C:\\MogreSDK\\bin\\Debug"

open System
open System.Windows.Forms
open System.Drawing

open Mogre

type OgreWindow(origin, hWnd) =
    //----------------------------------------------------- 
    // 1 enter ogre 
    //----------------------------------------------------- 
    let root = new Root()

    do  //----------------------------------------------------- 
        // 2 configure resource paths
        //----------------------------------------------------- 
        let cf = new ConfigFile()
        cf.Load("resources.cfg", "\t:=", true)

        // Go through all sections & settings in the file
        let seci = cf.GetSectionIterator()

        // Normally we would use the foreach syntax, which enumerates the values, but in this case we need CurrentKey too;
        while seci.MoveNext() do
            for pair in seci.Current do
                ResourceGroupManager.Singleton.AddResourceLocation(pair.Value, pair.Key, seci.CurrentKey)

        //----------------------------------------------------- 
        // 3 Configures the application and creates the window
        //----------------------------------------------------- 
        root.RenderSystem <- root.GetAvailableRenderers() |> Seq.find (fun rs -> rs.Name = "Direct3D9 Rendering Subsystem")
        root.RenderSystem.SetConfigOption("Full Screen", "No")
        root.RenderSystem.SetConfigOption("Video Mode", "640 x 480 @ 32-bit colour")

        root.Initialise(false) |> ignore
        let misc = new NameValuePairList()
        misc.["externalWindowHandle"] <- hWnd.ToString()
        let window = root.CreateRenderWindow("Simple Mogre Form Window", 0u, 0u, false, misc.ReadOnlyInstance)
        ResourceGroupManager.Singleton.InitialiseAllResourceGroups()

        //----------------------------------------------------- 
        // 4 Create the SceneManager
        // 
        //      ST_GENERIC = octree
        //      ST_EXTERIOR_CLOSE = simple terrain
        //      ST_EXTERIOR_FAR = nature terrain (depreciated)
        //      ST_EXTERIOR_REAL_FAR = paging landscape
        //      ST_INTERIOR = Quake3 BSP
        //----------------------------------------------------- 
        let sceneMgr = root.CreateSceneManager(SceneType.ST_GENERIC, "SceneMgr")
        sceneMgr.AmbientLight <- new ColourValue(0.5f, 0.5f, 0.5f)

        //----------------------------------------------------- 
        // 5 Create the camera 
        //----------------------------------------------------- 
        let camera = sceneMgr.CreateCamera("SimpleCamera")
        camera.Position <- new Vector3(0.0f, 0.0f, 100.0f)
        // Look back along -Z
        camera.LookAt(new Vector3(0.0f, 0.0f, -300.0f))
        camera.NearClipDistance <- 5.0f

        let viewport = window.AddViewport(camera)
        viewport.BackgroundColour <- new ColourValue(0.0f, 0.0f, 0.0f, 1.0f)

        let ent = sceneMgr.CreateEntity("ogre", "ogrehead.mesh")
        let node = sceneMgr.RootSceneNode.CreateChildSceneNode("ogreNode")
        node.AttachObject(ent)

    member this.Paint() =
        root.RenderOneFrame() |> ignore

    member this.Dispose() =
        if root <> null then
            root.Dispose()

type MogreForm() as this =
    inherit Form()

    let mogrePanel = new System.Windows.Forms.Panel()

    // Between Suspend and Resume Layout is normal form Designer Code
    do  base.SuspendLayout()

        mogrePanel.Location <- new System.Drawing.Point(0, 0)
        mogrePanel.Name <- "mogrePanel"
        mogrePanel.Size <- new System.Drawing.Size(483, 375)
        mogrePanel.TabIndex <- 0

        base.AutoScaleDimensions <- new System.Drawing.SizeF(6.0f, 13.0f)
        base.AutoScaleMode <- System.Windows.Forms.AutoScaleMode.Font
        base.ClientSize <- new System.Drawing.Size(483, 375)
        base.Controls.Add(mogrePanel)
        base.Name <- "MogreForm"
        base.Text <- "Simple F# Mogre Form";

        base.ResumeLayout(false)

        let mogreWin = new OgreWindow(Point(100, 30), mogrePanel.Handle)
        this.Disposed.Add(fun _ -> mogreWin.Dispose())
        this.Paint.Add(fun _ -> mogreWin.Paint())

let main() =
    Application.EnableVisualStyles()
    Application.SetCompatibleTextRenderingDefault(false)
    Application.Run(new MogreForm())

[<STAThread>]
do main()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM