Code class: Creating a simple user interface from a script

news · 5 years ago
by Tim Dudgeon

In an earlier post we created a script that called out to a RESTful web service that performs a structure search against the ChEMBL database and pulls back results into IJC. It concentrated on how to call a web service, and other parts of the script were left pretty basic, and we said we would come back and improve them later.

The part that we cover here is how to create a simple user interface. In the original script we hard coded the query structure and the similarity score in the script, meaning we would have to edit the script if we ever wanted to use different values. Not very friendly!

[groovy firstline="18"] // Query params are hard coded. We'll change this in the next version String query = 'COC(=O)[C@@H]1[C@H]2CC[C@@H](C[C@@H]1OC(=O)C1=CC=CC=C1)N2C' String similarity = '90' // similarity as a percent. Should be between 70 and 100 [/groovy]

So let’s look at how to provide a simple user interface to allow these to be specified more easily.
Groovy, because its built on Java, can do everything that Java can, so we can use Swing to build our user interface. But Groovy’s SwingBuilder makes using Swing much easier than it is in Java. It uses a builder approach to defining the UI, and can also handle things like event handling and other things. But let’s keep it relatively simple. We create a simple user interface that will look like this:

OK, so we’re having to type or paste smiles, so its not perfect yet, but we’ll talk about doing this with a sketcher later. This is the key part of the code:

[groovy firstline="84"] def getSearchParams() { // For more on Groovy's SwingBuilder see: // def swing = new SwingBuilder() def vars = swing.variables //Define the popup panel contents def panel = swing.panel () { //Use the gridBagLayout to lay out the frame gridBagLayout() // ChEMBL say they support smiles. // Not clear whether this extends to smarts. // ChEBML search does not use JChem :-) label(text:"Smiles:", constraints:gbc(gridx:0, gridy:0, insets:[10,10,5,10])) textField(id:'smilesField', text:"COC(=O)[C@@H]1[C@H]2CC[C@@H](C[C@@H]1OC(=O)C1=CC=CC=C1)N2C", name:"smiles", constraints:gbc(gridx:1, gridy:0, weightx: 1.0d, fill:GridBagConstraints.HORIZONTAL, insets:[10,10,5,10])) label(text:"Similarity:", constraints:gbc( gridx:0, gridy:1, insets:[5,10,10,10])) textField(id:'similarityField', text:"90", name:"similarity", constraints:gbc( gridx:1, gridy:1, weightx: 1.0d, fill:GridBagConstraints.HORIZONTAL, insets:[5,10,10,10])) } // uses the NetBeans dialogs API so the dialog looks like a normal IJC dialog def dd = new DialogDescriptor(panel, 'Search parameters') def ok = DialogDisplayer.default.notify(dd) // result is a Map of values def result = null if (ok == DialogDescriptor.OK_OPTION) { // which button was pressed result = [smiles: vars.smilesField.text, similarity: vars.similarityField.text] } return result } [/groovy]

The key parts are creating two JLabels and two JTextFields using the label() and textField() builder methods and adding them to a JPanel. The JTextFields are pre-populated with default values. The GridBagLayout layout manager is used. We won’t go over exact details here. See the SwingBuilder docs for full details:

Once we have our JPanel we display it using the Netbeans DialogDisplayer, so that it looks like other dialogs in IJC.
We find out if the user clicked the OK or Cancel buttons and then act accordingly.
The rest is much the same as the previous version of the script.

Before we finish, lets touch on how to use a sketcher instead of typing smiles. You can use the Marvin Swing components. There’s a trick you need to do as SwingBuilder doesn’t know about the Marvin classes, so there are no builder methods for them like there are for the standard Swing. The trick is to wrap it in a container. Here is an example of a minimal working script that pops up a sketcher.:

[groovy firstline="1"] import chemaxon.marvin.beans.MSketchPane import groovy.swing.SwingBuilder import org.openide.DialogDescriptor import org.openide.DialogDisplayer def sketcher = new MSketchPane() def swing = new SwingBuilder() def panel = swing.panel () { container(sketcher) } def dd = new DialogDescriptor(panel, 'Sketch structure') def ok = DialogDisplayer.default.notify(dd) def mol = sketcher.mol println "molecule is $mol [/groovy]

We’ll leave it to you for now to work out how to integrate this into our dialog.

The full script (without the sketcher) can be found here: Full script
To run it follow the instructions at the top of the script.