The Programmers Guide To Kotlin - Using Swing |
Written by Mike James | |||||
Monday, 26 February 2024 | |||||
Page 3 of 4
Swing EventsNow that we know how lambda's are converted to SAMs we can rewrite our Swing example so that works properly. The system provides the invokeLater method which accepts a Runnable and runs it on the Event Dispatch Thread, EDT. Of course, we can use the same technique introduced in the previous section to avoid having to explicitly create a runnable instance: SwingUtilities.invokeLater { This looks as if the SwingUtilities.invokeLater method is simply something you write your Swing code in, and in Kotlin that is how you can treat it. When the invokeLater call comes to an end, the code in our lambda is in the event queue waiting to be executed. At this point the main thread comes to an end, but our program doesn't come to an end because the event handling thread is still running, processing events and the code that you have just given it. The only problem with this code is that when the user closes the JFrame, the EDT keeps running waiting for something to happen. We can change this behavior using the setDefaultCloseOperation method which Kotlin can use as a property: SwingUtilities.invokeLater { val myFrame=JFrame("Hello World") Now when you run the program it does exit when the JFrame is closed. Notice also that we have used a static property JFrame.EXIT_ON_CLOSE. This just looks like a Kotlin companion object or a Java static property depending on how you choose to look at it. As well as displaying an empty JFrame we can also add other components such as textboxes, buttons and so on. To demonstrate how all this works, and in particular how events are handled, let's add a JButton object. The first thing to say is that a JFrame positions components that it displays using a layout manager and the default layout manager is a border layout. This allows you to position components in fixed locations such at top left and center. If you don't want a layout manager to do the job, you can position components absolutely by giving an x,y position. This is the easiest way to start, so first we remove the default layout manager: myFrame.layout=null Again, this is a property converted by Kotlin from a pair of getter/setter methods. Now we can create the JButton: val myButton=JButton("Click Me") and position and size it by setting its bounds rectangle by specifying the x,y pixel coordinates of the top left corner and its width and height: myButton.bounds= Rectangle(15,50,150,50) This is another property converted from a set/get pair, but notice that in this case the property is set to another object – a Rectangle. Finally we can add the JButton and display the result: myFrame.add(myButton) myFrame.isVisible=true The complete program is: SwingUtilities.invokeLater { val myFrame=JFrame("Hello World") myFrame.setSize(300,200) myFrame.defaultCloseOperation=JFrame.EXIT_ON_CLOSE Now we have a button, but nothing happens when you click it. To make it respond to a click we have to define an ActionListener and add it to the JButton: myButton.addActionListener { myButton.text="You did!" Notice that the use of myButton within the event handler is only possible because of the closure formed when the lambda is defined and exists after the function setting up the GUI is complete. Now when you run the program and click on the JButton, the lambda changes its text: You can also make use of the ActionEvent object passed to the event handler to find out about the event. For example: myButton.addActionListener { e-> myButton.text= e.source.toString() } This prints the full Java name of the component that triggered the event. |
|||||
Last Updated ( Monday, 26 February 2024 ) |