I am looking for a way to change the text of a button in Groovy when it is clicked. I can't find any documentation on it. I'm using Swingbuilder to lay the buttons out (it is for a Battleship game). I'm fairly new at using this lang.
What I'm using is:
import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.BorderLayout
class FrontEnd {
FrontEnd() {
def builder = new SwingBuilder()
builder.edt {
frame(title: 'Battleship', size: [500, 350], show: true, locationRelativeTo: null, resizable: false,
defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE) {
borderLayout(vgap: 5)
panel(constraints: BorderLayout.CENTER) {
tableLayout {
tr {...
}
tr {
td {
label '1'
}
td {
button(id: 'a1', text: ' ', actionPerformed:)
}
td {
button(id: 'b1', text: ' ', actionPerformed:)
}
I don't know if it is even possible with this setup, so if there is another way I'd be glad to know about it.
Thank you.
The following example assigns a button to the variable myButton which is then used for reference. Clicking on the button will set the text to hello 0, hello 1, etc:
import groovy.swing.SwingBuilder
import groovy.beans.Bindable
import static javax.swing.JFrame.EXIT_ON_CLOSE
import java.awt.*
class Example {
static def count = 0
static void main(String[] args) {
def swingBuilder = new SwingBuilder()
swingBuilder.edt {
frame(title: 'Example', size: [140, 80],
show: true, locationRelativeTo: null,
defaultCloseOperation: EXIT_ON_CLOSE) {
borderLayout(vgap: 5)
panel(constraints: BorderLayout.SOUTH) {
myButton = button text: 'Save', actionPerformed: {
myButton.setText("hello ${count++}")
}
}
}
}
}
}
Related
Is there anyway to avoid the stateChange event being fired more than one time when the toggleButton is clicked? Or am I using the wrong event handler? It gets called 5 times for every toggle.
#!/usr/bin/env groovy
import groovy.swing.SwingBuilder
import static javax.swing.JFrame.EXIT_ON_CLOSE
def swing = new SwingBuilder()
swing.edt {
lookAndFeel 'nimbus'
frame(title : "Throttle",
pack : true,
show : true,
defaultCloseOperation: EXIT_ON_CLOSE,
id : "frame" ) {
boxLayout()
toggleButton(text: 'fl',
selected : false,
rolloverEnabled: false,
toolTipText : 'f1',
stateChanged : { e ->
println e.source
})
}
}
swing.doLater { frame.size = [128, 320] }
I switched to from stateChanged to actionPerformed then it worked as what I expected. Not sure why I used stateChanged in the first place!
import groovy.beans.Bindable;
import groovy.swing.SwingBuilder
import java.awt.BorderLayout
import javax.swing.JFrame
#Bindable def people = [[name:"Mary", age:18],
[name:"Tom", age:25]]
def swingBuilder = new SwingBuilder()
swingBuilder.edt { // edt method makes sure UI is build on Event Dispatch Thread.
lookAndFeel 'system' // Simple change in look and feel.
frame( title: 'Display a table',
size: [400,300],
show: true,
locationRelativeTo: null,
defaultCloseOperation: JFrame.EXIT_ON_CLOSE)
{
menuBar() {
menu(text: "File", mnemonic: 'F'){
menuItem(text: "Add",
actionPerformed: {
people << [name:"Harry", age:17]
println people
}
)}
}
panel(layout: new BorderLayout()) {
scrollPane(constraints: BorderLayout.CENTER) {
table() {
def listTeacher
tableModel(list: people) {
propertyColumn(header: 'Name', propertyName: 'name')
propertyColumn(header: 'Age', propertyName: 'age')
}
}
}
}
}
}
When click "Add" one entry is added to the list people but the JTable is not updated. How can I fix it?
You can make it an ObservableList, and then refresh the table model when the list changes in some way:
import groovy.beans.Bindable;
import groovy.swing.SwingBuilder
import java.awt.BorderLayout
import javax.swing.JFrame
import java.beans.PropertyChangeListener
#Bindable ObservableList people = [ [name:"Mary", age:18],
[name:"Tom", age:25] ]
def swingBuilder = new SwingBuilder()
swingBuilder.edt { // edt method makes sure UI is build on Event Dispatch Thread.
lookAndFeel 'system' // Simple change in look and feel.
frame( title: 'Display a table',
size: [400,300],
show: true,
locationRelativeTo: null,
defaultCloseOperation: JFrame.HIDE_ON_CLOSE) {
menuBar() {
menu(text: "File", mnemonic: 'F'){
menuItem(text: "Add", actionPerformed: {
people << [name:"Harry", age:17]
println people
}
) }
}
panel(layout: new BorderLayout()) {
scrollPane(constraints: BorderLayout.CENTER) {
table {
def listTeacher
tableModel( id:'model', list: people) { m ->
propertyColumn(header: 'Name', propertyName: 'name')
propertyColumn(header: 'Age', propertyName: 'age')
}
}
}
people.addPropertyChangeListener( { e -> model.fireTableDataChanged() } as PropertyChangeListener )
}
}
}
Why does this code fail ?
I want to change the color of one panel in a series of several panels, dynamically constructed (total number of panels not known beforehand).
For some reason, this code works when referencing the name of a particular panel (for example 'panel2'), but not when I refer to it dynamically ('panelID').
import groovy.swing.SwingBuilder
import javax.swing.WindowConstants as WC
import javax.swing.JOptionPane
import javax.swing.BoxLayout as BXL
swing = new SwingBuilder()
frame = swing.frame(title:'test',
defaultCloseOperation:WC.DISPOSE_ON_CLOSE) {
panel(id:'mainPanel'){
def panelID
(1..6).each {
panelID = 'panel' + it
panel(alignmentX: 0f, id: panelID , opaque:true ,background : java.awt.Color.GREEN){
label('description')
textField(id: "description$it", text: panelID, columns: 70 )
button(id: "button$panelID", text: panelID, actionPerformed : {
panelID.background = java.awt.Color.RED
panelID.repaint()
})
}
}
boxLayout(axis: BXL.Y_AXIS)
panel(id:'secondPanel' , alignmentX: 0f){
button('Quit', actionPerformed:{
dispose()
})
}
}
}
frame.pack()
frame.show()
To get the element based on it's ID, you need to access the ID as a parameter of the SwingBuilder, like so:
import groovy.swing.SwingBuilder
import javax.swing.WindowConstants as WC
import javax.swing.JOptionPane
import javax.swing.BoxLayout as BXL
swing = new SwingBuilder()
frame = swing.frame(title:'test', pack:true, visible:true, defaultCloseOperation:WC.DISPOSE_ON_CLOSE) {
panel(id:'mainPanel'){
(1..6).each { num ->
def panelID = "panel$num"
def pane = panel( alignmentX:0f, id:panelID, background:java.awt.Color.GREEN ) {
label('description')
textField(id: "description$num", text:panelID, columns: 70 )
button(id: "buttonpanel$num", text:panelID, actionPerformed : {
swing."$panelID".background = java.awt.Color.RED
})
}
}
boxLayout(axis: BXL.Y_AXIS)
panel(id:'secondPanel' , alignmentX: 0f){
button('Quit', actionPerformed:{
frame.visible = false
})
}
}
}
How do I add a header to the table defined below?
import groovy.swing.SwingBuilder
data = [[first:'qwer', last:'asdf'],
[first:'zxcv', last:'tyui'],
[first:'ghjk', last:'bnm']]
swing = new SwingBuilder()
frame = swing.frame(title:'table test'){
table {
tableModel( list : data ) {
propertyColumn(header:'First Name', propertyName:'first')
propertyColumn(header:'last Name', propertyName:'last')
}
}
}
frame.pack()
frame.show()
If you put the table in a scrollPane, the headers appear:
import groovy.swing.SwingBuilder
data = [[first:'qwer', last:'asdf'],
[first:'zxcv', last:'tyui'],
[first:'ghjk', last:'bnm']]
swing = new SwingBuilder()
frame = swing.frame(title:'table test'){
scrollPane {
table {
tableModel( list : data ) {
propertyColumn(header:'First Name', propertyName:'first')
propertyColumn(header:'last Name', propertyName:'last')
}
}
}
}
frame.pack()
frame.show()
See item one on this page for an explanation why
Table header is a separate widget that must be added explicitly.
import groovy.swing.SwingBuilder
import java.awt.BorderLayout
data = [[first:'qwer', last:'asdf'],
[first:'zxcv', last:'tyui'],
[first:'ghjk', last:'bnm']]
swing = new SwingBuilder()
frame = swing.frame(title:'table test'){
def tab = table(constraints:BorderLayout.CENTER) {
tableModel( list : data ) {
propertyColumn(header:'First Name', propertyName:'first')
propertyColumn(header:'Last Name', propertyName:'last')
}
}
widget(constraints:BorderLayout.NORTH, tab.tableHeader)
}
frame.pack()
frame.show()
Is there some kind of built-in method or a simple function that will convert Duration into a string in the hh:mm:ss format? For example, I am looking for something that would convert a Duration of 123402 ms into a String of "2:03".
Alternatively, you can use the flags from java.util.Formatter.
action: function() {
txt = "{%tM dur}.{%tS dur}"
}
This will result in a leading 0, as in "02.03", for dur = "123402ms".
You can convert a Duration to a String using String.valueOf(dur). You can then use the Java formatting classes to reformat the String. You have to chop the end of String because of the way JavaFX formats durations as strings (eg '123402.0ms'). If JavaFX had a Long.valueOf(dur) function then this would be easier.
See sample below:
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.control.Button;
import java.text.SimpleDateFormat;
import java.util.Date;
var fmt = new SimpleDateFormat("m:ss");
var dur: Duration = 123402ms;
var txt: String = String.valueOf(dur);
Stage {
title : "Duration Switch"
scene: Scene {
width: 400
height: 200
content: [
Text {
font : Font {
size: 24
}
x: 10, y: 30
content: bind "Duration={txt}"
},
Button {
translateY: 140
text: "Switch"
action: function() {
var durStr = String.valueOf(dur);
durStr = durStr.substring(0, durStr.indexOf("."));
var date = new Date(Long.parseLong(durStr));
txt = fmt.format(date);
}
}
]
}
}