Click here to Skip to main content
15,887,585 members
Articles / Multimedia / GDI+
Tip/Trick

Flag Design With F# And GDI+

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
28 Sep 2015CPOL4 min read 10.3K   120   3  
This tip describes the use of GDI+ with F# language through Flag design.

Image 1

Introduction

This is my first article on F# programming language and I decided to start with graphics programming, since graphics programming has always been interesting to me.

In this article, I will show you how to use GDI+ in F# programming language to design country flag.

Using the Code

First of all, we will create the main window of our application. We will need the following .NET namespaces for that purpose:

F#
open System;
open System.Windows;
open System.Windows.Forms;

And the following namespaces are also required for using the GDI+:

F#
open System.Drawing;
open System.Drawing.Drawing2D;

Don't forget to add all the references for those namespaces through the Reference Manager of Visual Studio.
Since form designer is not available for F# in Visual Studio, we have to manually write codes for our application Graphical User Interface.

This MainWindow class represents our application main window:

F#
type MainWindow() = 
    inherit Form()

    // Our constructor
    member this.Init =
        this.Text <- "Flag Design With GDI+"
        this.Size <- new System.Drawing.Size(600, 560)
        this.BackColor <- System.Drawing.Color.DeepSkyBlue

The MainWindow class inherits the System.Windows.Forms.Form class. The Init member function initializes some basic property of the window. Our entry point function will call this function.

This is the entry point of our application which creates object of the MainWindow class, initializes it and runs it:

F#
[<STAThread>]
let START = 

    let mainWindow = new MainWindow()

    // Here we initialize our main window through calling this member function.
    mainWindow.Init

    // Lets run our application
    Application.Run(mainWindow)

By calling the MainWindow.Init method, we initialize the basic properties of our MainWindow.
The Application.Run method will make our main window visible and run standard application message loop on the current thread.

Compiling and running the application at this stage, you will see a Window filled with DeepSkyBlue color. The color was specified inside the Init member function of MainWindow class.

Image 2

Remember that a default F# application is always a Console Application, you have to manually set the application type to Windows Application in the project properties. Otherwise, you will see a black DOS/Command window behind your main window.

Now, we will write codes for drawing our flags. To draw anything using the GDI+ in our main window, we will need to create a Paint Event Handler.

So let's do it.

Create a member function called Event_Paint inside the MainWindow class.

F#
// Our paint event
member this.Event_Paint(sender : System.Object, e : PaintEventArgs) = 
    ........
    ........ .. .

This is our Paint event handler function. That means this function will handle paint event for our main window.
Inside the Init member function of the MainWindow class, write the following line:

F#
this.Paint.AddHandler(new Windows.Forms.PaintEventHandler(fun s pe ->this.Event_Paint(s, pe)))

Here the fun keyword is used for defining an anonymous function. Which is also called lambda expression.

Syntax of fun keyword is:

fun parameter-list -> expression

According to MSDN:

The parameter-list typically consists of names and, optionally, types of parameters. The expression is the body of the function.

As a valid lambda expression, we use the Event_Paint function which is our Paint event handler. So when our main window needs to be painted, it will call our Event_Paint function and anything we draw using GDI+ inside the function, will be showing in our main window.

In the Event_Paint function, we set the Smoothing and Compositing property of Graphics class to HighQuality for getting better image quality.

F#
e.Graphics.SmoothingMode <- SmoothingMode.HighQuality
e.Graphics.CompositingQuality <- CompositingQuality.HighQuality

Now, we can call our flag drawing function inside the Event_Paint function to draw it inside our main window. I have implemented six country flag drawing function. Which are Bangladesh, Canada, United States Of America, United Kingdom and Germany.

Here is the source code of Bangladesh flag drawing function:

F#
// Our Bangladesh flag drawing function
member this.Draw_BangladeshFlag(x :float32, y :float32, g : System.Drawing.Graphics) =

    // Oh! The easiest one.

    // Draw the green background
    g.FillRectangle(Brushes.Green, x, y, 260.0f, 156.0f)
    // Draw the center red circle
    g.FillEllipse(Brushes.Red, x + 70.0f, y + 30.0f, 100.0f, 100.0f)

In this function, we use the Graphics.FillRectangle and Graphics.FillEllipse method to draw the green background and red center circle of the flag.
We can call this function inside the Event_Paint member function thus:

F#
this.Draw_BangladeshFlag(20.0f, 10.0f, e.Graphics)

USA flag has star symbol. So, we need a star drawing function for that purpose.

The following member function is for drawing star:

F#
// Our star drawing function

member this.Draw_Star(x :float32, y :float32, r: float32, g : System.Drawing.Graphics) = 
    let radian72 = (float) ( (float) System.Math.PI * (float) 4.0 ) / (float) 5.0
    let pts : PointF array = Array.zeroCreate 5

    for i in 0 .. pts.Length - 1 do
        Array.set pts i ( new PointF(x + r * (float32)(Math.Sin((float)i * radian72)), 
                                         y - r * (float32)(Math.Cos( (float)i * radian72 )) ))

    g.FillPolygon( Brushes.White, pts, FillMode.Winding)

This function takes x and y parameter value as the center of the star and r parameter value for the star radius. Then it creates a PointF typed array and fills it with necessary values through the for ... in loop. And finally, it passes the point array to the Graphics.FillPolygon method parameter to draw the star. The Graphics.FillPolygon method fills the interior of a polygon defined by an array of points.

Default color of the star is white. But you might want to change the color to use it for other purposes.

I have used the GraphicsPath class of GDI+ and AddLine method of the class to draw the Canada flag center leaf:

F#
let path = new GraphicsPath()

path.StartFigure()

path.AddLine(leafX + 133.f, leafY + 150.0f, leafX + 134.f, leafY + 120.0f)
path.AddLine(leafX + 134.f, leafY + 120.0f, leafX + 110.f, leafY + 123.0f)

.........
.................

path.CloseFigure()

g.DrawPath(Pens.Red, path)
g.FillPath(redBrush, path)

The Graphics class represents a series of connected lines and curves. Using the Graphics.DrawPath method, we draw the path to our window and we fill the path with red color through the Graphics.FillPath method.

Here is other country flag drawing functions prototype:

F#
member MainWindow.Draw_UsaFlag : flagX :float32, flagY :float32, g : System.Drawing.Graphics ->uint

member MainWindow.Draw_GermanyFlag : x :float32, y :float32, g : System.Drawing.Graphics -> uint

member MainWindow.Draw_UkFlag : x :float32, y :float32, g : System.Drawing.Graphics -> uint

member MainWindow.Draw_CanadaFlag : x :float32, y :float32, g : System.Drawing.Graphics -> uint

Finally, we draw all our flags inside the Event_Paint member function in this way:

F#
this.Draw_BangladeshFlag(20.0f, 10.0f, e.Graphics)
e.Graphics.DrawString("Bangladesh", font, clrText, new PointF(18.0f, 9.0f))

this.Draw_CanadaFlag(300.0f, 10.0f, e.Graphics)
e.Graphics.DrawString("Canada", font, clrText, new PointF(300.0f, 9.0f))

this.Draw_UsaFlag(20.0f, 186.0f, e.Graphics)
e.Graphics.DrawString("United States Of America", font, clrText, new PointF(18.0f, 168.0f))

this.Draw_UkFlag(300.0f, 186.0f, e.Graphics)
e.Graphics.DrawString("United Kingdom", font, clrText, new PointF(300.0f, 168.0f))

this.Draw_GermanyFlag(180.0f, 350.0f, e.Graphics)
e.Graphics.DrawString("Germany", font, clrText, new PointF(18.0f, 352.0f))

Here, we use the Graphics.DrawString method of GDI+ to draw all the country's name at the top left corner of their flag. 12 sized Arial is used as font of the country name.

Conclusion

F# is a strongly typed functional programming language. Though it is a functional programming language, object-oriented is also supported as well. And it is fully capable to use the power of .NET. So using the F# language and GDI+ library, you can create various great graphics design since GDI+ is also a powerful graphics library.

Although I have only added six country flag drawing functions, I hope this tip will help you to learn graphics programming with the F# programming language.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Bangladesh Bangladesh
Hi, I'm Shah Farhad Reza. I'm a desktop and web software developer.

Recently I've developed an web based ERP (Enterprise Resource Planning) Software for a manufacturing company. The software is in use and working effectively fulfilling its goal (Alhamdulillah) - [February 10, 2023]

The areas of my expertise are the followings:

- OS Kernel developing.
- Programming language's compiler design and implement.
- Expert in C, C++ and Visual Basic and have basic knowledge on C#, D, Java.
- A few times used the Microsoft's new language F#.
- SQL Database programming.
- I've basic knowledge on lowest level programming language like assembly.
- Learning Mozilla’s Rust & Google’s GO programming language for software development.
- Code optimization for performance.
- Multi-threaded programming in C/C++ and Java.
- Know various advanced computer algorithm and have used them to develop graphics and simulation programs. Also working with Linear Algebra and keen to learn Quadratic Algebra in future.
- Graphics and Game programming (Both 2D and 3D).

Currently, I'm doing research on programming language and its compiler development. I've made various kind of software and now I want to share my experiences with people.


Comments and Discussions

 
-- There are no messages in this forum --