HiveBrain v1.2.0
Get Started
← Back to all entries
principleMinor

Approach to programmatically building hierarchical GUI components

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
buildingcomponentshierarchicalguiapproachprogrammatically

Problem

At work I am developing an application using hand-coded Swing, and I've found that I have an easier time reading, writing, and maintaining hierarchical component creation using code blocks like:

JPanel mainPanel = new JPanel(new BorderLayout());
    {
        JLabel centerLabel = new JLabel();
        centerLabel.setText("Hello World");
        mainPanel.add(centerLabel, BorderLayout.CENTER);
    }
    {
        JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0,0));
        {
            JLabel label1 = new JLabel();
            label1.setText("Hello");
            southPanel.add(label1);
        }
        {
            JLabel label2 = new JLabel();
            label2.setText("World");
            southPanel.add(label2);
        }
        mainPanel.add(southPanel, BorderLayout.SOUTH);
    }


So I wondered what that would look like using F# and WinForms, and I translated this code example (go to "Browse Code" tab, then click on F# -> editor.fsx in tree view) in two ways and I'd like feedback on which of the following two ways seems better. The first uses code blocks like the approach shown in Swing, and I think it is nice but a bit cluttered with begin ... end everywhere:

open System
open System.Windows.Forms

let form = new Form()
form.Width   form.Close())
            mFile.MenuItems.Add(miQuit) |> ignore
        end
        mMain.MenuItems.Add(mFile) |> ignore
    end
    form.Menu <- mMain
end
begin
    // RichTextView 
    let textB = new RichTextBox()
    textB.Dock <- DockStyle.Fill  
    textB.Text <- "Hello World\n\nOK."
    form.Controls.Add(textB)
end


The second approach is interesting because it takes advantage of the fact that in F# everything is an expression, but it seems a little harder for me to follow and I'm not sure if that's just because I'm used to the code block approach:

```
open System
open System.Windows.Forms

let form = new Form()
form.Width form.Close())
miQuit
) |> ignore

Solution

Here is my take on your code:

open System
open System.Windows.Forms

let form =
    new Form(
        Width = 400,
        Height = 300,
        Visible = true,
        Text = "Hello World Form")

// Menu bar, menus 
let mMain = 
    let miQuit  = new MenuItem("&Quit")
    miQuit.Click.Add(fun _ -> form.Close())

    let mFile = new MenuItem("&File")
    mFile.MenuItems.Add(miQuit) |> ignore

    let mMain = new MainMenu()
    mMain.MenuItems.Add(mFile) |> ignore

    mMain

form.Menu <- mMain

// RichTextView 
let textB = new RichTextBox(Dock = DockStyle.Fill, Text = "Hello World\n\nOK.")

form.Controls.Add(textB)


I tried to improve by assigning properties directly in the constructor call. I also used nested let declarations to reflect the hierarchy. Finally, I used indentation instead of explicit begin/end or parens to delimit blocks.

Note also how I used mMain within the declaration of the top-level mMain. Others might have used tmp, I think using the same name makes the intent clear. It might be a bit confusing for new-comers, though.

Code Snippets

open System
open System.Windows.Forms

let form =
    new Form(
        Width = 400,
        Height = 300,
        Visible = true,
        Text = "Hello World Form")

// Menu bar, menus 
let mMain = 
    let miQuit  = new MenuItem("&Quit")
    miQuit.Click.Add(fun _ -> form.Close())

    let mFile = new MenuItem("&File")
    mFile.MenuItems.Add(miQuit) |> ignore

    let mMain = new MainMenu()
    mMain.MenuItems.Add(mFile) |> ignore

    mMain

form.Menu <- mMain

// RichTextView 
let textB = new RichTextBox(Dock = DockStyle.Fill, Text = "Hello World\n\nOK.")

form.Controls.Add(textB)

Context

StackExchange Code Review Q#1773, answer score: 4

Revisions (0)

No revisions yet.