From 8189116ea4b5db4675e31dfd04a5687d55e29262 Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Tue, 6 May 2014 14:29:37 +0100 Subject: Added javadocs, made minor changes to the comments --- src/jcgp/gui/GUI.java | 4 ++ src/jcgp/gui/console/GUIConsole.java | 21 ++++++++- src/jcgp/gui/dragresize/HorizontalDragResize.java | 51 +++++++++++++++++++--- src/jcgp/gui/dragresize/VerticalDragResize.java | 46 ++++++++++++++++++- src/jcgp/gui/population/ChromosomePane.java | 41 ++++++++--------- src/jcgp/gui/population/GUIGene.java | 6 --- src/jcgp/gui/population/GUIInput.java | 3 +- src/jcgp/gui/population/GUINode.java | 18 ++++---- src/jcgp/gui/population/GUIOutput.java | 15 +++---- src/jcgp/gui/population/PopulationPane.java | 6 +-- src/jcgp/gui/settings/SettingsPane.java | 9 ++-- src/jcgp/gui/settings/parameters/GUIParameter.java | 2 +- src/jcgp/gui/settings/testcase/TestCaseTable.java | 33 ++++++++++++-- 13 files changed, 190 insertions(+), 65 deletions(-) (limited to 'src/jcgp/gui') diff --git a/src/jcgp/gui/GUI.java b/src/jcgp/gui/GUI.java index cd4778f..437a739 100644 --- a/src/jcgp/gui/GUI.java +++ b/src/jcgp/gui/GUI.java @@ -257,4 +257,8 @@ public class GUI extends Application { public void flushConsole() { console.flush(); } + + public int getChromosomeIndex() { + return populationPane.getSelectionModel().getSelectedIndex(); + } } diff --git a/src/jcgp/gui/console/GUIConsole.java b/src/jcgp/gui/console/GUIConsole.java index de4b378..b3d037c 100644 --- a/src/jcgp/gui/console/GUIConsole.java +++ b/src/jcgp/gui/console/GUIConsole.java @@ -15,12 +15,25 @@ import javafx.scene.layout.AnchorPane; import jcgp.backend.resources.Console; import jcgp.gui.GUI; +/** + * Console pane used by the GUI to display CGP output messages. + * This class realises {@code Console}. It consists of a JavaFX + * {@code TextArea} and a {@code StringBuffer}. The buffer is filled + * as print messages are queued. Calling {@code flush()} writes the + * contents of the buffer to the {@code TextArea} and empties the buffer. + * + * @see Console + * @author Eduardo Pedroni + * + */ public class GUIConsole extends AnchorPane implements Console { private TextArea textArea = new TextArea("Welcome to JCGP!\n"); - private StringBuffer printBuffer = new StringBuffer(); + /** + * Creates a new instance of this class. + */ public GUIConsole() { super(); textArea.setEditable(false); @@ -31,7 +44,10 @@ public class GUIConsole extends AnchorPane implements Console { * This has not been fixed as of 8/4/2014. * * The following code modifies the EventDispatcher to consume the right mouse - * button click, preventing the default menu from appearing. + * button click, preventing the default menu from appearing. It propagates the mouse + * click further so other elements will respond appropriately. + * + * TODO this should be refactored once the API is updated. */ final EventDispatcher initial = textArea.getEventDispatcher(); textArea.setEventDispatcher(new EventDispatcher() { @@ -76,6 +92,7 @@ public class GUIConsole extends AnchorPane implements Console { new SeparatorMenuItem(), clearConsole)); + // anchor the text area so it resizes automatically AnchorPane.setTopAnchor(textArea, GUI.RESIZE_MARGIN); AnchorPane.setBottomAnchor(textArea, 0.0); AnchorPane.setRightAnchor(textArea, 0.0); diff --git a/src/jcgp/gui/dragresize/HorizontalDragResize.java b/src/jcgp/gui/dragresize/HorizontalDragResize.java index 84c322f..b618b74 100644 --- a/src/jcgp/gui/dragresize/HorizontalDragResize.java +++ b/src/jcgp/gui/dragresize/HorizontalDragResize.java @@ -7,9 +7,11 @@ import javafx.scene.layout.Region; import jcgp.gui.GUI; /** - * - * Decorator pattern. - * + * This class adds horizontal drag resize functionality to any + * arbitrary region provided. This is done by using the static + * method {@code makeDragResizable()}. + *

+ * This is based on a class by Andrew Till found on: * http://andrewtill.blogspot.co.uk/2012/12/dragging-to-resize-javafx-region.html * */ @@ -18,13 +20,29 @@ public class HorizontalDragResize { private boolean dragging = false; private final Region region; + /** + * For internal use only, creates an instance of the actual + * resizer used. + * + * @param region the region to make resizable. + */ private HorizontalDragResize(Region region) { this.region = region; } + /** + * Makes the specified region drag resizable. + * This particular implementation only creates a resize + * click-and-drag area on the left side of the region. + * The resize area is defined by {@code GUI.RESIZE_MARGIN}. + * + * @param region the region to make resizable. + */ public static void makeDragResizable(final Region region) { + // make the instance, this actually performs the resizing final HorizontalDragResize dr = new HorizontalDragResize(region); + // set mouse listeners region.setOnMousePressed(new EventHandler() { @Override public void handle(MouseEvent event) { @@ -52,12 +70,22 @@ public class HorizontalDragResize { } + /** + * If the press happened in the resize area, raise the drag flag. + * + * @param event the associated mouse event. + */ private void mousePressed(MouseEvent event) { if(isInDraggableZone(event)) { dragging = true; } } + /** + * If drag flag is high, resize the region to match the mouse position. + * + * @param event the associated mouse event. + */ private void mouseDragged(MouseEvent event) { if(dragging) { double newWidth = region.getWidth() - event.getX(); @@ -69,20 +97,33 @@ public class HorizontalDragResize { } } + /** + * Change the cursor if the mouse position overlaps with the resize area. + * + * @param event the associated mouse event. + */ private void mouseMoved(MouseEvent event) { if(isInDraggableZone(event) || dragging) { region.setCursor(Cursor.H_RESIZE); - } - else { + } else { region.setCursor(Cursor.DEFAULT); } } + /** + * Finish resizing. + */ private void mouseReleased() { dragging = false; region.setCursor(Cursor.DEFAULT); } + /** + * Assert whether the mouse cursor is in the draggable area defined by {@code GUI.RESIZE_MARGIN}. + * + * @param event the associated mouse event. + * @return true if the mouse position is in the draggable area. + */ private boolean isInDraggableZone(MouseEvent event) { return event.getX() < (GUI.RESIZE_MARGIN); } diff --git a/src/jcgp/gui/dragresize/VerticalDragResize.java b/src/jcgp/gui/dragresize/VerticalDragResize.java index 9397e5d..06186c6 100644 --- a/src/jcgp/gui/dragresize/VerticalDragResize.java +++ b/src/jcgp/gui/dragresize/VerticalDragResize.java @@ -7,7 +7,11 @@ import javafx.scene.layout.Region; import jcgp.gui.GUI; /** - * + * This class adds vertical drag resize functionality to any + * arbitrary region provided. This is done by using the static + * method {@code makeDragResizable()}. + *

+ * This is based on a class by Andrew Till found on: * http://andrewtill.blogspot.co.uk/2012/12/dragging-to-resize-javafx-region.html * */ @@ -16,13 +20,29 @@ public class VerticalDragResize { private boolean dragging = false; private final Region region; + /** + * For internal use only, creates an instance of the actual + * resizer used. + * + * @param region the region to make resizable. + */ private VerticalDragResize(Region region) { this.region = region; } + /** + * Makes the specified region drag resizable. + * This particular implementation only creates a resize + * click-and-drag area on the top side of the region. + * The resize area is defined by {@code GUI.RESIZE_MARGIN}. + * + * @param region the region to make resizable. + */ public static void makeDragResizable(final Region region) { + // make the instance, this actually performs the resizing final VerticalDragResize dr = new VerticalDragResize(region); + // set mouse listeners region.setOnMousePressed(new EventHandler() { @Override public void handle(MouseEvent event) { @@ -50,12 +70,22 @@ public class VerticalDragResize { } + /** + * If the press happened in the resize area, raise the drag flag. + * + * @param event the associated mouse event. + */ private void mousePressed(MouseEvent event) { if(isInDraggableZone(event)) { dragging = true; } } + /** + * If drag flag is high, resize the region to match the mouse position. + * + * @param event the associated mouse event. + */ private void mouseDragged(MouseEvent event) { if(dragging) { double newHeight = region.getHeight() - event.getY(); @@ -67,6 +97,11 @@ public class VerticalDragResize { } } + /** + * Change the cursor if the mouse position overlaps with the resize area. + * + * @param event the associated mouse event. + */ private void mouseMoved(MouseEvent event) { if(isInDraggableZone(event) || dragging) { region.setCursor(Cursor.V_RESIZE); @@ -76,11 +111,20 @@ public class VerticalDragResize { } } + /** + * Finish resizing. + */ private void mouseReleased() { dragging = false; region.setCursor(Cursor.DEFAULT); } + /** + * Assert whether the mouse cursor is in the draggable area defined by {@code GUI.RESIZE_MARGIN}. + * + * @param event the associated mouse event. + * @return true if the mouse position is in the draggable area. + */ private boolean isInDraggableZone(MouseEvent event) { return event.getY() < (GUI.RESIZE_MARGIN); } diff --git a/src/jcgp/gui/population/ChromosomePane.java b/src/jcgp/gui/population/ChromosomePane.java index 4a47f34..d40de2e 100644 --- a/src/jcgp/gui/population/ChromosomePane.java +++ b/src/jcgp/gui/population/ChromosomePane.java @@ -25,6 +25,8 @@ public class ChromosomePane extends ScrollPane { private int rows, columns; + private Object[] testInputs; + private boolean target = false; private PopulationPane parent; @@ -111,20 +113,21 @@ public class ChromosomePane extends ScrollPane { target = newValue; } - public void updateGenes() { + public void updateGenes(Chromosome chr) { for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { + guiNodes[r][c].setNode(chr.getNode(r, c)); guiNodes[r][c].updateLines(); guiNodes[r][c].updateText(); } } for (int i = 0; i < guiOutputs.length; i++) { + guiOutputs[i].setOutput(chr.getOutput(i)); guiOutputs[i].updateLines(); } if (isEvaluating()) { - evaluate(0); + setInputs(testInputs); } - } public void unlockOutputs() { @@ -144,29 +147,27 @@ public class ChromosomePane extends ScrollPane { } public void setInputs(Object[] values) { + testInputs = values; for (int i = 0; i < guiInputs.length; i++) { guiInputs[i].setValue(values[i]); - guiInputs[i].updateText(); } - evaluate(0); + updateValues(); } - public void evaluate(int start) { - if (start >= 0 || start < columns) { - for (int c = start; c < columns; c++) { - for (int r = 0; r < rows; r++) { - guiNodes[r][c].calculate(); - guiNodes[r][c].updateText(); - } - } - for (int o = 0; o < guiOutputs.length; o++) { - guiOutputs[o].calculate(); - guiOutputs[o].updateText(); - } - } - } +// public void evaluate(int start) { +// if (start >= 0 || start < columns) { +// for (int c = 0; c < columns; c++) { +// for (int r = 0; r < rows; r++) { +// guiNodes[r][c].updateText(); +// } +// } +// for (int o = 0; o < guiOutputs.length; o++) { +// guiOutputs[o].updateText(); +// } +// } +// } - public void hideValues() { + public void updateValues() { for (int i = 0; i < guiInputs.length; i++) { guiInputs[i].updateText(); } diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java index 3ace150..0eea045 100644 --- a/src/jcgp/gui/population/GUIGene.java +++ b/src/jcgp/gui/population/GUIGene.java @@ -39,8 +39,6 @@ public abstract class GUIGene extends Group { protected ChromosomePane parent; protected int locked = 0; - - protected Object value; public GUIGene() { text.setFont(Font.font("Arial", 12)); @@ -92,9 +90,5 @@ public abstract class GUIGene extends Group { public abstract void setConnectionLine(GUIGene gene); - public Object getValue() { - return value; - } - public abstract void updateText(); } diff --git a/src/jcgp/gui/population/GUIInput.java b/src/jcgp/gui/population/GUIInput.java index 05372c4..fd66ab4 100644 --- a/src/jcgp/gui/population/GUIInput.java +++ b/src/jcgp/gui/population/GUIInput.java @@ -219,14 +219,13 @@ public class GUIInput extends GUIGene { } public void setValue(Object newValue) { - value = newValue; input.setValue(newValue); } @Override public void updateText() { if (parent.isEvaluating()) { - text.setText("I: " + input.getIndex() + "\n" + value.toString()); + text.setText("I: " + input.getIndex() + "\n" + input.getValue().toString()); } else { text.setText("I: " + input.getIndex()); } diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java index 6dfeaa4..d3ae27f 100644 --- a/src/jcgp/gui/population/GUINode.java +++ b/src/jcgp/gui/population/GUINode.java @@ -398,7 +398,8 @@ public class GUINode extends GUIGene { public void setChangingConnection(Connection newConnection) { node.setConnection(connectionIndex, newConnection); if (parent.isEvaluating()) { - parent.evaluate(node.getColumn()); + parent.updateValues(); +// parent.evaluate(node.getColumn()); } } @@ -452,24 +453,23 @@ public class GUINode extends GUIGene { public void updateText() { if (parent.isEvaluating()) { - text.setText(node.getFunction() + "\n" + value.toString()); + text.setText(node.getFunction() + "\n" + node.getValue().toString()); } else { text.setText(node.getFunction().toString()); } } - - public void calculate() { - value = node.getValue(); - } public void setFunction(Function function) { node.setFunction(function); if (parent.isEvaluating()) { - calculate(); - parent.evaluate(node.getColumn()); +// parent.evaluate(node.getColumn()); + parent.updateValues(); } else { updateText(); } - + } + + public void setNode(Node newNode) { + node = newNode; } } diff --git a/src/jcgp/gui/population/GUIOutput.java b/src/jcgp/gui/population/GUIOutput.java index 29752cd..5a76298 100644 --- a/src/jcgp/gui/population/GUIOutput.java +++ b/src/jcgp/gui/population/GUIOutput.java @@ -267,10 +267,7 @@ public class GUIOutput extends GUIGene { @Override public void setChangingConnection(Connection newConnection) { output.setConnection(0, newConnection); - if (parent.isEvaluating()) { - calculate(); - updateText(); - } + updateText(); } @Override @@ -308,19 +305,19 @@ public class GUIOutput extends GUIGene { setLocked(true); } } - - public void calculate() { - value = output.getSource().getValue(); - } @Override public void updateText() { if (parent.isEvaluating()) { - text.setText("O: " + output.getIndex() + "\n" + value.toString()); + text.setText("O: " + output.getIndex() + "\n" + output.getSource().getValue().toString()); } else { text.setText("O: " + output.getIndex()); } } + public void setOutput(Output newOutput) { + output = newOutput; + } + } diff --git a/src/jcgp/gui/population/PopulationPane.java b/src/jcgp/gui/population/PopulationPane.java index 5fa6067..4b1b7f8 100644 --- a/src/jcgp/gui/population/PopulationPane.java +++ b/src/jcgp/gui/population/PopulationPane.java @@ -27,7 +27,7 @@ public class PopulationPane extends TabPane { Tab tab; ChromosomePane cp; for (int i = 0; i < jcgp.getResources().populationSize(); i++) { - cp = new ChromosomePane(jcgp.getPopulation().getChromosome(i), gui, this); + cp = new ChromosomePane(jcgp.getPopulation().get(i), gui, this); tab = new Tab("Chr " + i); tab.setContent(cp); getTabs().add(tab); @@ -39,7 +39,7 @@ public class PopulationPane extends TabPane { evaluateTestCase(currentTestCase); } for (int i = 0; i < getTabs().size(); i++) { - ((ChromosomePane) getTabs().get(i).getContent()).updateGenes(); + ((ChromosomePane) getTabs().get(i).getContent()).updateGenes(gui.getExperiment().getPopulation().get(i)); } } @@ -73,7 +73,7 @@ public class PopulationPane extends TabPane { public void hideValues() { evaluating = false; for (int i = 0; i < getTabs().size(); i++) { - ((ChromosomePane) getTabs().get(i).getContent()).hideValues(); + ((ChromosomePane) getTabs().get(i).getContent()).updateValues(); } } diff --git a/src/jcgp/gui/settings/SettingsPane.java b/src/jcgp/gui/settings/SettingsPane.java index 802c1f1..2898dc3 100644 --- a/src/jcgp/gui/settings/SettingsPane.java +++ b/src/jcgp/gui/settings/SettingsPane.java @@ -255,7 +255,7 @@ public class SettingsPane extends AnchorPane { } private Button makeTestCaseButton() { - Button b = new Button("Show data1"); + Button b = new Button("Show data"); b.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { @@ -331,7 +331,7 @@ public class SettingsPane extends AnchorPane { fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*")); File chrFile = fc.showOpenDialog(gui.getStage()); if (chrFile != null) { - gui.getExperiment().loadChromosome(chrFile, 0); + gui.getExperiment().loadChromosome(chrFile, gui.getChromosomeIndex()); gui.reDraw(); } gui.flushConsole(); @@ -346,7 +346,7 @@ public class SettingsPane extends AnchorPane { fc.getExtensionFilters().add(new ExtensionFilter("All files", "*.*")); File chrFile = fc.showSaveDialog(gui.getStage()); if (chrFile != null) { - gui.getExperiment().saveChromosome(chrFile, 0); + gui.getExperiment().saveChromosome(chrFile, gui.getChromosomeIndex()); } gui.flushConsole(); } @@ -474,6 +474,9 @@ public class SettingsPane extends AnchorPane { parameter.applyValue(); } updateArity(); + if (testCaseTable != null) { + testCaseTable.close(); + } } /** diff --git a/src/jcgp/gui/settings/parameters/GUIParameter.java b/src/jcgp/gui/settings/parameters/GUIParameter.java index 3009340..f896fa3 100644 --- a/src/jcgp/gui/settings/parameters/GUIParameter.java +++ b/src/jcgp/gui/settings/parameters/GUIParameter.java @@ -23,7 +23,7 @@ import jcgp.gui.settings.SettingsPane; * This is the base class for all @code{GUIParameter}s. Using the factory method @code{GUIParameter.create()} * generates an appropriate instance of this class for the specified parameter. *

- * @code{GUIParameter} is an @code{HBox} containing a @code{Text} for the parameter name + * A @code{GUIParameter} is an @code{HBox} containing a @code{Text} for the parameter name * and a @code{Control} for interaction. * It stores an instance of its associated @code{Parameter} object and also contains a @code{Tooltip} for * displaying status information. diff --git a/src/jcgp/gui/settings/testcase/TestCaseTable.java b/src/jcgp/gui/settings/testcase/TestCaseTable.java index d4c1ff9..d4f789c 100644 --- a/src/jcgp/gui/settings/testcase/TestCaseTable.java +++ b/src/jcgp/gui/settings/testcase/TestCaseTable.java @@ -20,7 +20,10 @@ import jcgp.backend.resources.Resources; import jcgp.gui.GUI; /** - * + * This is a test case table. For problems that have test cases, + * this table shows the test case inputs and outputs. Clicking on + * a test case (one is shown per row) applies the values to all + * chromosome inputs shows the calculated values throughout the chromosome. * * @author Eduardo Pedroni * @@ -29,17 +32,27 @@ public class TestCaseTable extends Stage { private TableView> table; + /** + * Make a new instance of {@code TestCaseTable}. + * + * @param testCaseProblem the {@code TestCaseProblem} whose data must be displayed. + * @param gui a reference to the GUI. + */ public TestCaseTable(final TestCaseProblem testCaseProblem, final GUI gui) { super(); Resources resources = gui.getExperiment().getResources(); + // create the actual table view table = new TableView>(); + // get test cases from problem ObservableList> testCaseList = testCaseProblem.getTestCases(); + // prepare input and output columns ArrayList, String>> inputs = new ArrayList, String>>(resources.inputs()); ArrayList, String>> outputs = new ArrayList, String>>(resources.outputs()); + // create input columns TableColumn, String> tc; for (int i = 0; i < resources.inputs(); i++) { tc = new TableColumn, String>("I: " + i); @@ -48,13 +61,16 @@ public class TestCaseTable extends Stage { tc.setCellValueFactory(new Callback,String>, ObservableValue>() { @Override public ObservableValue call(CellDataFeatures, String> param) { + // create a new string property and give it the test case value, no need for dynamic binding - this wont change often return new SimpleStringProperty(param.getValue().getInput(index).toString()); } }); tc.setSortable(false); + // set column width so all columns are distributed across the width of the stage tc.prefWidthProperty().bind(table.widthProperty().divide(resources.inputs() + resources.outputs())); } + // create output columns for (int o = 0; o < resources.outputs(); o++) { tc = new TableColumn, String>("O: " + o); outputs.add(tc); @@ -62,37 +78,46 @@ public class TestCaseTable extends Stage { tc.setCellValueFactory(new Callback,String>, ObservableValue>() { @Override public ObservableValue call(CellDataFeatures, String> param) { + // create a new string property and give it the test case value, no need for dynamic binding - this wont change often return new SimpleStringProperty(param.getValue().getOutput(index).toString()); } }); tc.setSortable(false); + // set column width so all columns are distributed across the width of the stage tc.prefWidthProperty().bind(table.widthProperty().divide(resources.inputs() + resources.outputs())); } + // add created columns table.getColumns().addAll(inputs); table.getColumns().addAll(outputs); + // populate table with actual data table.setItems(testCaseList); + // apply test case values when a new test case is selected table.getSelectionModel().selectedItemProperty().addListener(new ChangeListener>() { @Override - public void changed( - ObservableValue> observable, TestCase oldValue, TestCase newValue) { + public void changed(ObservableValue> observable, TestCase oldValue, TestCase newValue) { gui.evaluateTestCase(newValue); } }); + // when the stage is closed, clear the selection + // this doesn't work if the stage is closed by the program for some reason... setOnCloseRequest(new EventHandler() { @Override public void handle(WindowEvent event) { gui.hideGeneValues(); - table.getSelectionModel().select(null); + table.getSelectionModel().clearSelection(); } }); setScene(new Scene(table)); } + /** + * @return a reference to the actual table of test cases. + */ public TableView> getTable() { return table; } -- cgit v1.2.3