Creating GUIs with groovy is pretty easy once you learn to use the SwingBuilder. Builders in groovy allow you to work in a declarative way similar to say, HTML. This has the benefit of making your code more readable and easier to maintain. In this short tutorial we’re going to create a basic calculator using the SwingBuilder. We’ll also touch on laying out components with layout managers and how to handle events. Please note this tutorial would also work for regular groovy outside of Xappworks.
To get started create a new project called “CalcTutorial”. (If you need a reminder for this have a look in the Hello World Tutorial).
In our new project we want to create a new class called Calc (File>New> Module). Your new file should look like this:
1 2 3 4 | public class Calc{ public Calc(){ } } |
The first thing we want to do is tell the compiler that we want access to some extra libraries, this is done by using the import statement at the top of your class file like so:
1 2 3 4 5 6 7 8 | import java.awt.*; import javax.swing.*; import groovy.swing.*; public class Calc{ public Calc(){ } } |
These 3 are important as they provide access to Swing, the GUI toolkit we’ll be using;AWT, upon which Swing is built; and Groovy’s SwingBuilder. You find out more about these by following the links at the bottom.
Now that we have our imports in place, we want to create a SwingBuilder object that we can use to create our form. Create a varible called sb at the class level (between lines 5 and 6) like so:
6 7 8 9 10 | public class Calc{ def sb = new SwingBuilder(); public Calc(){ } } |
Now we can make use of the SwingBuilder within our constructor. If you’re new to Groovy or Java a constructor is the first piece of code called in a class when it is instantiated (when the “new” keyword is used). The first thing we want to do with our SwingBuilder is create a new window; in swing this is called a JFrame. Most swing components class names actually start with the letter J but the SwingBuilder has removed the need for that since we know we’re working with swing.
7 8 9 10 11 | def sb = new SwingBuilder(); public Calc(){ sb.frame(id:"calcFrame",title:"XCalc",size:[300,200], visible:true){ } } |
You’ll notice that we are setting several properties in the new line we added such as an id, a title, a size and that the form should be visible. We want to be able to run this to see how it looks so open up Main.mod and make it look like the following:
1 2 3 4 5 | class Main{ public static void main(String [] args){ new Calc(); } } |
Press the save all button, then press the run button. You should see a blank form appear:
When designing a gui, it helps to split it up into smaller areas that can have different layout, for example a calculator has a display area and an input area and so we’ll use something called the BorderLayout which we can use to specify these two areas. BorderLayout actually lets you position components in compass directions: North, South, East, West and Center. In our case we want to split our form up like the picture below:
So how do we create these areas? Well we do it by firstly telling the SwingBuilder what sort of layout we want and then using the constraints poperites of our components to tell them where to go:
9 10 11 12 13 14 15 | sb.frame(id:"calcFrame",title:"XCalc",size:[300,200], visible:true){ borderLayout() textField(id:"display",editable:false,horizontalAlignment: JTextField.RIGHT,constraints:BorderLayout.NORTH); panel(id:"buttons", constraints:BorderLayout.CENTER){ } } sb.calcFrame.pack(); |
You can see we’ve added two components now: a textfield for displaying our numbers and a panel for holding all of our buttons. We also added a line that tells the frame to pack. This means that it’ll shrink to fit the components within it. One thing you might be thinking is that there are more buttons on a calculator than compass directions, so how are we going to lay them out in a grid? Well this is where we make use of another layout called GridLayout. When you create a gridlayout you can set how many rows and columns you want to use, and the gaps between the grid cells. We want 4 columns and 5 rows for our calculator so we do the following:
panel(id:"buttons", constraints:BorderLayout.CENTER){ gridLayout(cols:4, rows:5, hgap:1, vgap:1) }
Once you’ve done that it’s time to add the buttons:
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | panel(id:"buttons", constraints:BorderLayout.CENTER){ gridLayout(cols:4, rows:5, hgap:1, vgap:1) button(text:"Bksp", actionPerformed:{backSpace()}) button(text:"Clr", actionPerformed:{clear()}) label("") label("") button(text:"7") button(text:"8") button(text:"9") button(text:"/") button(text:"4") button(text:"5") button(text:"6") button(text:"*") button(text:"1") button(text:"2") button(text:"3") button(text:"-") button(text:"0") button(text:".") button(text:"=") button(text:"+") } |
If you run this you should see something that looks like the calculator picture at the start. But a calulator that doens’t do anything isn’t very interesting so we’re going to need to add some event handlers and something to process the calculator. Before we go on you’re code should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import java.awt.*; import javax.swing.*; import groovy.swing.*; public class Calc{ def sb = new SwingBuilder(); public Calc(){ sb.frame(id:"calcFrame",title:"XCalc", visible:true){ borderLayout() textField(id:"display", editable:false,horizontalAlignment: JTextField.RIGHT,constraints:BorderLayout.NORTH); panel(id:"buttons", constraints:BorderLayout.CENTER){ gridLayout(cols:4, rows:5, hgap:1, vgap:1) button(text:"Bksp", actionPerformed:{backSpace()}) button(text:"Clr", actionPerformed:{clear()}) label("") label("") button(text:"7") button(text:"8") button(text:"9") button(text:"/") button(text:"4") button(text:"5") button(text:"6") button(text:"*") button(text:"1") button(text:"2") button(text:"3") button(text:"-") button(text:"0") button(text:".") button(text:"=") button(text:"+") } } sb.calcFrame.pack(); } } |
First things first we want to create a method to handle our button presses, this will be called by all the buttons except “=”, “Bksp” and “Clr”. We’ll call this method insertText since it’ll be adding text to the display area, add it below the constructor at around line 47.
46 47 48 | public void insertText(text){ sb.display.text =sb.display.text + text } |
As you can see the method takes a parameter called text, this will be the text from our button (the number or the operator we want to add to the display). We get a hold of our display textfield using it’s id from the swing builder sb.display and we want to set its text property equal to what it currently is plus the text parameter the method takes. Now that we have our handler we can tell the buttons to use it:
21 22 23 24 | button(text:"7",actionPerformed:{insertText(it.source.text)}) button(text:"8",actionPerformed:{insertText(it.source.text)}) button(text:"9",actionPerformed:{insertText(it.source.text)}) button(text:"/",actionPerformed:{insertText(it.source.text)}) |
You see that we use actionPerformed to call our method passing it the text of the button: it.source.text. Add this for all the buttons except “=”, “Bksp” and “Clr” since they do very different things. We’ll handle the clear button next:
51 52 53 | public void clear(){ sb.display.text=""; } |
16 | button(text:"Clr", actionPerformed:{clear()}) |
Now for backspace:
55 56 57 | public void backspace(){ sb.display.text=sb.display.text[0..sb.display.text.length()-2] } |
16 | button(text:"Bksp", actionPerformed:{backspace()}) |
And last but not least the method to perform our calculation:
59 60 61 62 | public void doEquals(){ GroovyShell shell = new GroovyShell(); sb.display.text=shell.evaluate(sb.display.text); } |
38 | button(text:"=",actionPerformed:{doEquals()}) |
Press save all and then run the application. You should now have a fully working calculator!
You’re finished code should look like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import groovy.swing.*; import java.awt.*; import javax.swing.*; public class Calc{ def sb = new SwingBuilder(); public Calc(){ sb.frame(id:"calcFrame",title:"XCalc",size:[300,200], visible:true){ borderLayout() textField(id:"display", editable:false,horizontalAlignment: JTextField.RIGHT,constraints:BorderLayout.NORTH); panel(constraints:BorderLayout.CENTER){ gridLayout(cols:4, rows:5, hgap:1, vgap:1) button(text:"Bksp", actionPerformed:{backSpace()}) button(text:"Clr", actionPerformed:{clear()}) label("") label("") button(text:"7",actionPerformed:{insertText(it.source.text)}) button(text:"8",actionPerformed:{insertText(it.source.text)}) button(text:"9", actionPerformed:{insertText(it.source.text)}) button(text:"/",actionPerformed:{insertText(it.source.text)}) button(text:"4",actionPerformed:{insertText(it.source.text)}) button(text:"5",actionPerformed:{insertText(it.source.text)}) button(text:"6",actionPerformed:{insertText(it.source.text)}) button(text:"*",actionPerformed:{insertText(it.source.text)}) button(text:"1",actionPerformed:{insertText(it.source.text)}) button(text:"2",actionPerformed:{insertText(it.source.text)}) button(text:"3",actionPerformed:{insertText(it.source.text)}) button(text:"-",actionPerformed:{insertText(it.source.text)}) button(text:"0",actionPerformed:{insertText(it.source.text)}) button(text:".",actionPerformed:{insertText(it.source.text)}) button(text:"=",actionPerformed:{doEquals()}) button(text:"+",actionPerformed:{insertText(it.source.text)}) } } sb.calcFrame.pack(); } public void insertText(text){ sb.display.text =sb.display.text + text } public void clear(){ sb.display.text=""; } public void backSpace(){ sb.display.text=sb.display.text[0..sb.display.text.length()-2] } public void doEquals(){ GroovyShell shell = new GroovyShell(); sb.display.text=shell.evaluate(sb.display.text); } } |



Trackback…
[...]below you’ll find the link to some sites that we think you should visit[...]…