//---------------------------------------------------------------------------------- // The are several Java options builder packages available. Some popular ones: // Apache Jakarta Commons CLI: http://jakarta.apache.org/commons/cli/ // jopt-simple: http://jopt-simple.sourceforge.net // args4j: https://args4j.dev.java.net/ (requires Java 5 with annotations) // jargs: http://jargs.sourceforge.net/ // te-code: http://te-code.sourceforge.net/article-20041121-cli.html // Most of these can be used from Groovy with some Groovy code benefits. // Groovy also has the CliBuilder built right in. // CliBuilder example def cli = new CliBuilder() cli.v(longOpt: 'verbose', 'verbose mode') cli.D(longOpt: 'Debug', 'display debug info') cli.o(longOpt: 'output', 'use/specify output file') def options = cli.parse(args) if (options.v) // ... if (options.D) println 'Debugging info available' if (options.o) { println 'Output file flag was specified' println "Output file is ${options.o}" } // ... // jopt-simple example 1 (short form) cli = new joptsimple.OptionParser("vDo::") options = cli.parse(args) if (options.wasDetected('o')) { println 'Output file flag was specified.' println "Output file is ${options.argumentsOf('o')}" } // ... // jopt-simple example 2 (declarative form) op = new joptsimple.OptionParser() VERBOSE = 'v'; op.accepts( VERBOSE, "verbose mode" ) DEBUG = 'D'; op.accepts( DEBUG, "display debug info" ) OUTPUT = 'o'; op.accepts( OUTPUT, "use/specify output file" ).withOptionalArg(). describedAs( "file" ).ofType( File.class ) options = op.parse(args) params = options.nonOptionArguments() if (options.wasDetected( DEBUG )) println 'Debugging info available' // ... //---------------------------------------------------------------------------------- |
//----------------------------------------------------------------------------------
// Groovy like Java can be run in a variety of scenarios, not just interactive vs
// non-interative, e.g. within a servlet container. Sometimes InputStreams and other
// mechanisms are used to hide away differences between the different containers
// in which code is run; other times, code needs to be written purpose-built for
// the container in which it is running. In most situations where the latter applies
// the container will have specific lifecycle mechanisms to allow the code to
// access specific needs, e.g. javax.servlet.ServletRequest.getInputStream()
// rather than System.in
//----------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------- // Idiomatically Groovy encourages GUI over text-based applications where a rich // interface is desirable. Libraries for richer text-based interfaces include: // jline: http://jline.sourceforge.net // jcurses: http://sourceforge.net/projects/javacurses/ // java-readline: http://java-readline.sourceforge.net // enigma console: http://sourceforge.net/projects/enigma-shell/ // Note: Run examples using these libraries from command line not inside an IDE. // If you are using a terminal/console that understands ANSI codes // (excludes WinNT derivatives) you can just print the ANSI codes print ((char)27 + '[2J') // jline has constants for ANSI codes import jline.ANSIBuffer print ANSIBuffer.ANSICodes.clrscr() // Also available through ConsoleReader.clearScreen() // Using jcurses import jcurses.system.* bg = CharColor.BLACK fg = CharColor.WHITE screenColors = new CharColor(bg, fg) Toolkit.clearScreen(screenColors) //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Not idiomatic for Groovy to use text-based applications here. // Using jcurses: http://sourceforge.net/projects/javacurses/ // use Toolkit.screenWidth and Toolkit.screenHeight // 'barchart' example import jcurses.system.Toolkit numCols = Toolkit.screenWidth rand = new Random() if (numCols < 20) throw new RuntimeException("You must have at least 20 characters") values = (1..5).collect { rand.nextInt(20) } // generate rand values max = values.max() ratio = (numCols - 12)/max values.each{ i -> printf('%8.1f %s\n', [i as double, "*" * ratio * i]) } // gives, for example: // 15.0 ******************************* // 10.0 ********************* // 5.0 ********** // 14.0 ***************************** // 18.0 ************************************** // Run from command line not inside an IDE which may give false width/height values. //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Idiomatically Groovy encourages GUI over text-based applications where a rich // interface is desirable. See 15.3 for richer text-based interface libraries. // Note: Run examples using these libraries from command line not inside an IDE. // If you are using a terminal/console that understands ANSI codes // (excludes WinNT derivatives) you can just print the ANSI codes ESC = "${(char)27}" redOnBlack = ESC + '[31;40m' reset = ESC + '[0m' println (redOnBlack + 'Danger, Will Robinson!' + reset) // jline has constants for ANSI codes import jline.ANSIBuffer redOnBlack = ANSIBuffer.ANSICodes.attrib(31) + ANSIBuffer.ANSICodes.attrib(40) reset = ANSIBuffer.ANSICodes.attrib(0) println redOnBlack + 'Danger, Will Robinson!' + reset // Using JavaCurses import jcurses.system.* import jcurses.widgets.* whiteOnBlack = new CharColor(CharColor.BLACK, CharColor.WHITE) Toolkit.clearScreen(whiteOnBlack) redOnBlack = new CharColor(CharColor.BLACK, CharColor.RED) Toolkit.printString("Danger, Will Robinson!", 0, 0, redOnBlack) Toolkit.printString("This is just normal text.", 0, 1, whiteOnBlack) // Blink not supported by JavaCurses // Using jline constants for Blink blink = ANSIBuffer.ANSICodes.attrib(5) reset = ANSIBuffer.ANSICodes.attrib(0) println (blink + 'Do you hurt yet?' + reset) // Using jline constants for Coral snake rhyme def ansi(code) { ANSIBuffer.ANSICodes.attrib(code) } redOnBlack = ansi(31) + ansi(40) redOnYellow = ansi(31) + ansi(43) greenOnCyanBlink = ansi(32) + ansi(46) + ansi(5) reset = ansi(0) println redOnBlack + "venom lack" println redOnYellow + "kill that fellow" println greenOnCyanBlink + "garish!" + reset //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Default Java libraries buffer System.in by default. // Using JavaCurses: import jcurses.system.Toolkit print 'Press a key: ' println "\nYou pressed the '${Toolkit.readCharacter().character}' key" // Also works for special keys: import jcurses.system.InputChar print "Press the 'End' key to finish: " ch = Toolkit.readCharacter() assert ch.isSpecialCode() assert ch.code == InputChar.KEY_END // See also jline Terminal#readCharacter() and Terminal#readVirtualKey() //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- print "${(char)7}" // Using jline constant print "${jline.ConsoleOperations.KEYBOARD_BELL}" // Also available through ConsoleReader.beep() // Using JavaCurses (Works only with terminals that support 'beeps') import jcurses.system.Toolkit Toolkit.beep() //---------------------------------------------------------------------------------- |
//----------------------------------------------------------------------------------
// I think you would need to resort to platform specific calls here,
// E.g. on *nix systems call 'stty' using execute().
// Some things can be set through the packages mentioned in 15.3, e.g.
// echo can be turned on and off, but others like setting the kill character
// didn't appear to be supported (presumably because it doesn't make
// sense for a cross-platform toolkit).
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
// Consider using Java's PushbackInputStream or PushbackReader
// Different functionality to original cookbook but can be used
// as an alternative for some scenarios.
//----------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------- // If using Java 6, use Console.readPassword() // Otherwise use jline (use 0 instead of mask character '*' for no echo): password = new jline.ConsoleReader().readLine(new Character('*')) //---------------------------------------------------------------------------------- |
//----------------------------------------------------------------------------------
// In Groovy (like Java) normal input is buffered so you can normally make
// edits before hitting 'Enter'. For more control over editing (including completion
// and history etc.) use one of the packages mentioned in 15.3, e.g. jline.
//----------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------- // Use javacurses or jline (see 15.3) for low level screen management. // Java/Groovy would normally use a GUI for such functionality. // Here is a slight variation to cookbook example. This repeatedly calls // the command feedin on the command line, e.g. "cmd /c dir" on windows // or 'ps -aux' on Linux. Whenever a line changes, the old line is "faded // out" using font colors from white through to black. Then the new line // is faded in using the reverse process. import jcurses.system.* color = new CharColor(CharColor.BLACK, CharColor.WHITE) Toolkit.clearScreen(color) maxcol = Toolkit.screenWidth maxrow = Toolkit.screenHeight colors = [CharColor.WHITE, CharColor.CYAN, CharColor.YELLOW, CharColor.GREEN, CharColor.RED, CharColor.BLUE, CharColor.MAGENTA, CharColor.BLACK] done = false refresh = false waittime = 8000 oldlines = [] def fade(line, row, colorList) { for (i in 0..<colorList.size()) { Toolkit.printString(line, 0, row, new CharColor(CharColor.BLACK, colorList[i])) sleep 10 } } while(!done) { if (waittime > 9999 || refresh) { proc = args[0].execute() lines = proc.text.split('\n') for (r in 0..<maxrow) { if (r >= lines.size() || r > oldlines.size() || lines[r] != oldlines[r]) { if (oldlines != []) fade(r < oldlines.size() ? oldlines[r] : ' ' * maxcol, r, colors) fade(r < lines.size() ? lines[r] : ' ' * maxcol, r, colors.reverse()) } } oldlines = lines refresh = false waittime = 0 } waittime += 200 sleep 200 } // Keyboard handling would be similar to 15.6. // Something like below but need to synchronize as we are in different threads. Thread.start{ while(!done) { ch = Toolkit.readCharacter() if (ch.isSpecialCode() || ch.character == 'q') done = true else refresh = true } } //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // These examples uses expectj, a pure Java Expect-like module. // http://expectj.sourceforge.net/ defaultTimeout = -1 // infinite expect = new expectj.ExpectJ("logfile.log", defaultTimeout) command = expect.spawn("program to run") command.expect('Password', 10) // expectj doesn't support regular expressions, but see readUntil // in recipe 18.6 for how to manually code this command.expect('invalid') command.send('Hello, world\r') // kill spawned process command.stop() // expecting multiple choices // expectj doesn't support multiple choices, but see readUntil // in recipe 18.6 for how to manually code this //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Methods not shown for the edit menu items, they would be the same as for the // file menu items. import groovy.swing.SwingBuilder def print() {} def save() {} frame = new SwingBuilder().frame(title:'Demo') { menuBar { menu(mnemonic:'F', 'File') { menuItem (actionPerformed:this.&print, 'Print') separator() menuItem (actionPerformed:this.&save, 'Save') menuItem (actionPerformed:{System.exit(0)}, 'Quit immediately') } menu(mnemonic:'O', 'Options') { checkBoxMenuItem ('Create Debugging Info', state:true) } menu(mnemonic:'D', 'Debug') { group = buttonGroup() radioButtonMenuItem ('Log Level 1', buttonGroup:group, selected:true) radioButtonMenuItem ('Log Level 2', buttonGroup:group) radioButtonMenuItem ('Log Level 3', buttonGroup:group) } menu(mnemonic:'F', 'Format') { menu('Font') { group = buttonGroup() radioButtonMenuItem ('Times Roman', buttonGroup:group, selected:true) radioButtonMenuItem ('Courier', buttonGroup:group) } } menu(mnemonic:'E', 'Edit') { menuItem (actionPerformed:{}, 'Copy') menuItem (actionPerformed:{}, 'Cut') menuItem (actionPerformed:{}, 'Paste') menuItem (actionPerformed:{}, 'Delete') separator() menu('Object ...') { menuItem (actionPerformed:{}, 'Circle') menuItem (actionPerformed:{}, 'Square') menuItem (actionPerformed:{}, 'Point') } } } } frame.pack() frame.show() //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Registration Example import groovy.swing.SwingBuilder def cancel(event) { println 'Sorry you decided not to register.' dialog.dispose() } def register(event) { if (swing.name?.text) { println "Welcome to the fold $swing.name.text" dialog.dispose() } else println "You didn't give me your name!" } def dialog(event) { dialog = swing.createDialog(title:'Entry') def panel = swing.panel { vbox { hbox { label(text:'Name') textField(columns:20, id:'name') } hbox { button('Register', actionPerformed:this.®ister) button('Cancel', actionPerformed:this.&cancel) } } } dialog.getContentPane().add(panel) dialog.pack() dialog.show() } swing = new SwingBuilder() frame = swing.frame(title:'Registration Example') { panel { button(actionPerformed:this.&dialog, 'Click Here For Registration Form') glue() button(actionPerformed:{System.exit(0)}, 'Quit') } } frame.pack() frame.show() // Error Example, slight variation to original cookbook import groovy.swing.SwingBuilder import javax.swing.WindowConstants as WC import javax.swing.JOptionPane def calculate(event) { try { swing.result.text = evaluate(swing.expr.text) } catch (Exception ex) { JOptionPane.showMessageDialog(frame, ex.message) } } swing = new SwingBuilder() frame = swing.frame(title:'Calculator Example', defaultCloseOperation:WC.EXIT_ON_CLOSE) { panel { vbox { hbox { label(text:'Expression') hstrut() textField(columns:12, id:'expr') } hbox { label(text:'Result') glue() label(id:'result') } hbox { button('Calculate', actionPerformed:this.&calculate) button('Quit', actionPerformed:{System.exit(0)}) } } } } frame.pack() frame.show() //---------------------------------------------------------------------------------- |
//----------------------------------------------------------------------------------
// Resizing in Groovy follows Java rules, i.e. is dependent on the layout manager.
// You can set preferred, minimum and maximum sizes (may be ignored by some layout managers).
// You can setResizable(false) for some components.
// You can specify a weight value for some layout managers, e.g. GridBagLayout
// which control the degree of scaling which occurs during resizing.
// Some layout managers, e.g. GridLayout, automaticaly resize their contained widgets.
// You can capture resize events and do everything manually yourself.
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
// Removing DOS console on Windows:
// If you are using java.exe to start your Groovy script, use javaw.exe instead.
// If you are using groovy.exe to start your Groovy script, use groovyw.exe instead.
//----------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------- // additions to original cookbook: // random starting position // color changes after each bounce import jcurses.system.* color = new CharColor(CharColor.BLACK, CharColor.WHITE) Toolkit.clearScreen(color) rand = new Random() maxrow = Toolkit.screenWidth maxcol = Toolkit.screenHeight rowinc = 1 colinc = 1 row = rand.nextInt(maxrow) col = rand.nextInt(maxcol) chars = '*-/|\\_' colors = [CharColor.RED, CharColor.BLUE, CharColor.YELLOW, CharColor.GREEN, CharColor.CYAN, CharColor.MAGENTA] delay = 20 ch = null def nextChar(){ ch = chars[0] chars = chars[1..-1] + chars[0] color = new CharColor(CharColor.BLACK, colors[0]) colors = colors[1..-1] + colors[0] } nextChar() while(true) { Toolkit.printString(ch, row, col, color) sleep delay row = row + rowinc col = col + colinc if (row in [0, maxrow]) { nextChar(); rowinc = -rowinc } if (col in [0, maxcol]) { nextChar(); colinc = -colinc } } //---------------------------------------------------------------------------------- |
//---------------------------------------------------------------------------------- // Variation to cookbook. Let's you reshuffle lines in a multi-line string // by drag-n-drop. import java.awt.* import java.awt.datatransfer.* import java.awt.dnd.* import javax.swing.* import javax.swing.ScrollPaneConstants as SPC class DragDropList extends JList implements DragSourceListener, DropTargetListener, DragGestureListener { def dragSource def dropTarget def dropTargetCell int draggedIndex = -1 def localDataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType) def supportedFlavors = [localDataFlavor] as DataFlavor[] public DragDropList(model) { super() setModel(model) setCellRenderer(new DragDropCellRenderer(this)) dragSource = new DragSource() dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this) dropTarget = new DropTarget(this, this) } public void dragGestureRecognized(DragGestureEvent dge) { int index = locationToIndex(dge.dragOrigin) if (index == -1 || index == model.size() - 1) return def trans = new CustomTransferable(model.getElementAt(index), this) draggedIndex = index dragSource.startDrag(dge, Cursor.defaultCursor, trans, this) } public void dragDropEnd(DragSourceDropEvent dsde) { dropTargetCell = null draggedIndex = -1 repaint() } public void dragEnter(DragSourceDragEvent dsde) { } public void dragExit(DragSourceEvent dse) { } public void dragOver(DragSourceDragEvent dsde) { } public void dropActionChanged(DragSourceDragEvent dsde) { } public void dropActionChanged(DropTargetDragEvent dtde) { } public void dragExit(DropTargetEvent dte) { } public void dragEnter(DropTargetDragEvent dtde) { if (dtde.source != dropTarget) dtde.rejectDrag() else dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE) } public void dragOver(DropTargetDragEvent dtde) { if (dtde.source != dropTarget) dtde.rejectDrag() int index = locationToIndex(dtde.location) if (index == -1 || index == draggedIndex + 1) dropTargetCell = null else dropTargetCell = model.getElementAt(index) repaint() } public void drop(DropTargetDropEvent dtde) { if (dtde.source != dropTarget) { dtde.rejectDrop() return } int index = locationToIndex(dtde.location) if (index == -1 || index == draggedIndex) { dtde.rejectDrop() return } dtde.acceptDrop(DnDConstants.ACTION_MOVE) def dragged = dtde.transferable.getTransferData(localDataFlavor) boolean sourceBeforeTarget = (draggedIndex < index) model.remove(draggedIndex) model.add((sourceBeforeTarget ? index - 1 : index), dragged) dtde.dropComplete(true) } } class CustomTransferable implements Transferable { def object def ddlist public CustomTransferable(object, ddlist) { this.object = object this.ddlist = ddlist } public Object getTransferData(DataFlavor df) { if (isDataFlavorSupported(df)) return object } public boolean isDataFlavorSupported(DataFlavor df) { return df.equals(ddlist.localDataFlavor) } public DataFlavor[] getTransferDataFlavors() { return ddlist.supportedFlavors } } class DragDropCellRenderer extends DefaultListCellRenderer { boolean isTargetCell def ddlist public DragDropCellRenderer(ddlist) { super() this.ddlist = ddlist } public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean hasFocus) { isTargetCell = (value == ddlist.dropTargetCell) boolean showSelected = isSelected && !isTargetCell return super.getListCellRendererComponent(list, value, index, showSelected, hasFocus) } public void paintComponent(Graphics g) { super.paintComponent(g) if (isTargetCell) { g.setColor(Color.black) g.drawLine(0, 0, size.width.intValue(), 0) } } } lines = ''' This is line 1 This is line 2 This is line 3 This is line 4 '''.trim().split('\n') def listModel = new DefaultListModel() lines.each{ listModel.addElement(it) } listModel.addElement(' ') // dummy def list = new DragDropList(listModel) def sp = new JScrollPane(list, SPC.VERTICAL_SCROLLBAR_ALWAYS, SPC.HORIZONTAL_SCROLLBAR_NEVER) def frame = new JFrame('Line Shuffle Example') frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) frame.contentPane.add(sp) frame.pack() frame.setVisible(true) //---------------------------------------------------------------------------------- |