
Person Form
Introduction (Updated 2)
NOTE: If you’ve been here before and found this blog entry useful please note that I have updated it again (for good reason). Let me explain why and what I’ve updated. Since I have found that I was becoming quite productive generating forms, I wanted a more decoupled approach, so I re-factored the source code to be more reusable and easily up-datable. To use the form designer for your applications you can skip down to the section called “Using the Form Designer” to help you create your own forms in no time at all! (I also had a crack at making the form a little more attractive too).
What is a Form Designer?
Software developers who build form based applications will often struggle with positioning controls dynamically while a window resizes. This is better known as “Layout Management”. Many developers will rely on GUI builders that provide a “WYSIWYG” ability allowing a designer to drag and drop components onto a canvas area. On the other hand some developers prefer to hand code GUI form screens. There are pros and cons to using both strategies; however in this article I will strike a balance by building a form designer to allow a developer to assist them in hand coding GUI form screens (sound strange, just read on). While the JavaFX community has anticipated for GUI designer tools, I couldn’t wait. So, I decided to create the “Poor Man’s Form Designer”. This simple designer tool uses the popular MigLayout by Mikael Grev and was ported over to the JavaFX platform by Dean Iverson (an author of the book “Pro JavaFX Platform”) into the JFXtras project. The PMFD‘s source code consists of one file Main.fx and just at around 370 lines of code including comments. After the Conclusion section of this article you will see the full source code to the demo and form designer. Simply click on the source code links to expand and your on your way to developing beautiful looking forms!

Poor Man's Form Designer Constraints Window
Note: You will notice I forgot to add column constraints. The designer now has the ability to adjust the column constraints.
Demo

Demo
Instructions:
- Click Launch button above
- Go to the MigLayout cheat sheet at http://migcalendar.com/miglayout/cheatsheet.html to keep handy when tweaking the “Form Design Constraint Editor” window.
- Go to the “Form Design Constraint Editor” and click the dump button. Here it will dump all the current constraints for the following areas: Layout, Column/Row and Components constraints.
- Go to the “Form Design Constraint Editor” window under the Component Constraint area is a combo box please select firstNameLabel, then tab to the constraint text field (just right of combo box) and type “align left“. Click Apply button to update changes.
- Be sure to observe the Form View window and you’ll notice the “First Name:” label is left justified beside the first name text field.
- Play around with other constraint areas. Cut and paste from the cheat sheet. The cheat sheet is divided in three sections: Layout Constraints, Column & Row Constraints and Component constraints. Don’t forget to hit the apply button.
- You’ll notice in the component constraint area when selecting a control in the combo box the previous constraint is preserved and displayed in the constraint text box.
- Go to the “Form Design Constraint Editor” and click the dump button. Here it will dump all the current constraints for the following areas: Layout, Column/Row and Components constraints.
- Copy and paste those dumped constraints to assist in your hand coded GUI Form. (See below “Using the Form Designer” section, Steps 3 & 4)
Disclaimer: While the coding details below seem strange, you may want to visit Dean’s Pleasing Software blog entry “MigLayout for JavaFX Reloaded” regarding how to Get started with MigLayout and JavaFX. http://pleasingsoftware.blogspot.com/search?q=layout
Using the Form Designer
Step 1: Create a new JavaFX project / setup to include JFXtras libraries and MigLayout jar files
Step 2: Copy Source code poormans_form_designer.fx expand put into your project. (check package statement)
Step 3: Create a form (class) which extends MigLayout from the JFXtras project. Simply add two attributes:
- componentsConstraints – Sequence of String objects
- nodesToLayout – Sequence of Node objects
Although this seems odd, I plan to possibly create a Mixin class or a derived MigLayout class to carry these attributes. Internally each Node contains a layoutInfo which contains a MigNodeLayoutInfo object (see http://jfxtras.org/portal/core/-/wiki/JFXtras/MigLayout for details). You should notice that the nameform.fx does not have dependencies to the designer library code, thus allowing the form developer to use CustomNode if they choose.
Create a Form (see nameform.fx for full source code)
public class NameForm extends MigLayout {
public var componentsConstraints:String[] = [];
public var nodesToLayout:Node[] = [];
init {
// ... other controls
var firstNameLabel:Label = Label {
id: "firstNameLabel"
text: "First Name"
font : Font {
size: 18
}
};
var firstNameField:TextBox = TextBox {
id:"firstNameField"
};
// ... other controls
nodesToLayout = [
sectionFullName, // 0
instructionsText, // 1
firstNameLabel, // 2
firstNameField, // 3
// ... all controls
];
// +---------------------------------------------------
// ! Poor Man's designer constraints info goes below
// +---------------------------------------------------
// [BEGIN]
constraints = "";
columns = "[pref]10[fill]";
rows = "[pref]10[pref]";
componentsConstraints = [
"span, growx, wrap", // fullNameTitle 0
"span, wrap 15px", // instructionsText 1
"align right", // firstNameLabel 2
"span, w min:100:300, wrap", // firstNameField 3
"align right", // middleNameLabel 4
"growx, w min:100:300, wrap", // middleNameField 5
"align right", // lastNameLabel 6
"growx, w min:100:300, wrap", // lastNameField 7
"align right", // suffixNameLabel 8
" w min:100:300, wrap 15", // suffixNameField 9
"span, wrap", // dobTitle 10
"align right", // dobLabel 11
" w min:100:pref, wrap 15", // dobField 12
"span, wrap", // pobTitle 13
"align right", // pobCityLabel 14
"span, growx, w min:100:300, wrap", // pobCityField 15
"align right", // pobCountyLabel 16
"span, growx, w min:100:300, wrap", // pobCountyField 17
"align right", // pobStateLabel 18
"span, w pref:100:pref + 10, wrap", // pobStateField 19
];
// [END]
// +---------------------------------------------------
// ! Poor Man's designer constraints info goes above
// +---------------------------------------------------
}
// IMPORTANT - This will generate mig nodes to be put
// into your content to be displayed in the scene.
postinit {
content = for (i in [0.. sizeof nodesToLayout -1]) {
migNode(nodesToLayout[i], componentsConstraints[i]);
}
}
}
Note: Next, will be Step 3, Launching your newly created MigLayout form into the designer. Once you are happy with the constraints you may press the “Dump” button to output the code that you will cut and paste into your form above. Place code between your [BEGIN] and [END] comment tags (Between lines 32 & 60)
Step 3: Launching your newly created MigLayout form into the designer (see Main.fx for full source code below conclusion)
Create a Main.fx to launch form into the Poor Man’s Form Designer tool. (see poormans_form_designer.fx for full source code below conclusion )
// http://pleasingsoftware.blogspot.com/search?q=layout
// Create name form
def nameForm:nameform.NameForm = NameForm{
};
// Remove content, due to nodes placed in the migNameForm later
delete nameForm.content;
// Create a miglayout designer object
def designer:MigLayoutDesigner = MigLayoutDesigner{
layoutConstraint: nameForm.constraints
columnsConstraint: nameForm.columns
rowsConstraint: nameForm.rows
componentsConstraints: nameForm.componentsConstraints
nodesToLayout: nameForm.nodesToLayout
};
// launch designer
poormans_form_designer.launch(designer, null, null);
Troubleshooting
- Missing imports or resolving – NetBeans: Control-Shift-I . Eclipse: Control-Shift-O . In NetBeans when using script level functions or classes inside a script file just use the ‘*’ wild card. ie: import poormans_form_designer.*;
- Script file does not contain correct package name. ie: package xyz;
- Form does not have two attributes called nodesToLayout and componentsConstraints.
- If Form is extending from MigLayout it should set its content using the two known attributes. ie: content = for (i in [0.. sizeof nodesToLayout -1]) {
migNode(nodesToLayout[i], componentsConstraints[i]);
}
Enhancements
Above you will see hand coded controls that eventually get displayed onto the Form View window (Person Form). Since the the GUI control code elements are simply sequential, I believe it would be quite easy to add, insert and remove controls dynamically onto the Form View window area. Also, possibly a property sheet window for controls, skins and behavior swapping.
Conclusion
The main goal is to properly lay out components in order to create a nice looking forms and also to learn the popular layout framework library MigLayout with it’s constraints language syntax. Using JavaFX‘s binding allows the form designer tool to enable the user to easily tweak constraints on the fly without having to rerun an application GUI for every adjustment made during the layout process in a form view. Another interesting thing to note is that since we are in the JavaFX world we can layout shapes, custom nodes and graphics (not just regular form controls). As a reminder regarding the use of JFXtras MigLayout, users should read about the known issues, please go to JFXtras MigLayout wiki at: http://jfxtras.org/portal/core/-/wiki/JFXtras/MigLayout . Well, by the time you read this blog entry I’m sure a nice GUI form designer/builder tool will be available.
The source code is listed below (click source code link to expand):
Note: I am in the process of putting the zipped up project onto the JFXtras.org for easy downloading.
Requirements:
- Java 6 JDK or greater
- JavaFX 1.2.1 SDK
- JFXtras version 0.5 jars
- latest Miglayout jar
Main.fx –
/*
* Main.fx
* @author Carl Dea
* Created on Jan 9, 2010, 9:06:36 PM
*/
package migtest3;
import javafx.stage.Stage;
import migtest3.nameform.*;
import javafx.scene.Scene;
import org.jfxtras.scene.ResizableScene;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.paint.Color;
import migtest3.poormans_form_designer.*;
function run(__ARGS__ : String[]) {
// Create name form
def nameForm:nameform.NameForm = NameForm{
};
// Remove content, due to nodes placed in the migNameForm later
delete nameForm.content;
// Create a miglayout designer object
def designer:MigLayoutDesigner = MigLayoutDesigner{
layoutConstraint: nameForm.constraints
columnsConstraint: nameForm.columns
rowsConstraint: nameForm.rows
componentsConstraints: nameForm.componentsConstraints
nodesToLayout: nameForm.nodesToLayout
};
// Create a custom scene. Note: this overrides default
// scene inside launch PMFD script function.
var newDesignerViewScene:Scene = ResizableScene {
fill: LinearGradient {
startX : 0.0
startY : 0.0
endX : 1.0
endY : 0.0
stops: [
Stop {
color : Color.rgb(251, 251, 251)
offset: 0.0
},
Stop {
color : Color.rgb(240, 240, 240)
offset: 1.0
},
]
}
content: [designer.dynamicMigLayout] // use the dynamicMigLayout
}; // scene
// create a custom Stage. Note: this overrides default
// Stage inside launch PMFD script function.
var newDesignerStageView = Stage {
y:150
x:100
width: 490
height: 600
scene:newDesignerViewScene
visible:true
};
// launch designer
poormans_form_designer.launch(designer, newDesignerViewScene, newDesignerStageView);
}
nameform.fx –
/*
* nameform.fx
*
* @author Carl Dea
* Created on Jan 9, 2010, 11:03:57 AM
*/
package migtest3;
import javafx.ext.swing.SwingComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.Node;
import javafx.scene.CustomNode;
import javafx.ext.swing.SwingComboBoxItem;
import javafx.scene.Group;
import javafx.scene.shape.Rectangle;
import org.jfxtras.scene.layout.MigLayout;
public var US_STATES = [
"AL","AK","AS","AZ","AR","CA","CO", "CT","DE","DC","FM","FL","GA","GU","HI","ID","IL","IN","IA","KS",
"KY","LA","ME","MH","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","MP",
"OH","OK","OR","PW","PA","PR","RI","SC","SD","TN","TX","UT","VT","VI","VA","WA","WV","WI","WY"
];
public function comboItemSeqCreator(names:String[]):SwingComboBoxItem[]{
for( n in names) SwingComboBoxItem{ text:n };
}
public class SectionTitleHeader extends CustomNode {
public-init var text:String;
public var height;
public var width;
public var rectangleColor:Color on replace {
if (not FX.isInitialized(rectangleColor)){
rectangleColor = Color.rgb(0,130,171);
}
};
public override function create():Node{
var title = Group {
content: [
Rectangle {
x: 10,
y: height - 85,
arcHeight: 5,
arcWidth: 5,
width: bind width - 30,
height: 30,
stroke:Color.BLACK
fill: rectangleColor
opacity: .5
},
Text {
x: 15,
y: height - 65,
content: text
fill: Color.WHITE
font: Font {
name: "Arial Bold"
letterSpacing: .20
size: 20
}
}
]
}; // title
return title;
}
}
public class NameForm extends MigLayout {
public var componentsConstraints:String[] = [];
public var nodesToLayout:Node[] = [];
init {
var sectionFullName:SectionTitleHeader = SectionTitleHeader {
id:"fullNameTitle"
text:"1 Full Name"
width:bind sectionFullName.scene.stage.width
height:100
rectangleColor:Color.BLUE
}
def instructions:String =
"- If you have only initials in your name, use them "
"and enter (I/O) after the initial(s). \n"
"- If you have no middle name, enter \"NMN\".\n"
"- If you are \"Jr.,\" \"Sr.,\" etc. enter this in the box after your middle name.\n";
var instructionsText:Text = Text {
id: "instructionsText"
content: instructions
fill:Color.BLACK
font : Font {
embolden:true
size: 14
}
};
var firstNameLabel:Label = Label {
id: "firstNameLabel"
text: "First Name"
font : Font {
size: 18
}
};
var firstNameField:TextBox = TextBox {
id:"firstNameField"
};
var middleNameLabel:Label = Label {
id: "middleNameLabel"
text: "Middle Name"
font : Font {
size: 18
}
};
var middleNameField:TextBox = TextBox {
id:"middleNameField"
};
var lastNameLabel:Label = Label {
id: "lastNameLabel"
text: "Last Name"
font : Font {
size: 18
}
};
var lastNameField:TextBox = TextBox {
id:"lastNameField"
};
var suffixNameLabel:Label = Label {
id: "suffixNameLabel"
text: "Suffix"
font : Font {
size: 18
}
};
var suffixNameField:TextBox = TextBox {
id:"suffixNameField"
};
var sectionDob:SectionTitleHeader = SectionTitleHeader {
id:"dobTitle"
text:"2 Date of Birth"
width: bind sectionDob.scene.stage.width
height:100
rectangleColor:Color.BLUE
}
var dobLabel:Label = Label {
id: "dobLabel"
text: "DOB"
font : Font {
size: 18
}
};
var dobField:TextBox = TextBox {
id:"dobField"
};
var sectionPlaceOfBirth:SectionTitleHeader = SectionTitleHeader {
id: "pobTitle"
text: "3 Place of Birth"
width: bind sectionPlaceOfBirth.scene.stage.width
height:100
rectangleColor:Color.BLUE
}
var pobCityLabel:Label = Label {
id: "pobCityLabel"
text: "City"
font : Font {
size: 18
}
};
var pobCityField:TextBox = TextBox {
id:"pobCityField"
};
var pobCountyLabel:Label = Label {
id: "pobCountyLabel"
text: "County"
font : Font {
size: 18
}
};
var pobCountyField:TextBox = TextBox {
id:"pobCountyField"
};
var pobStateLabel:Label = Label {
id: "pobStateLabel"
text: "State"
font : Font {
size: 18
}
};
var statesComboItems = comboItemSeqCreator(US_STATES);
var pobStateField:SwingComboBox = SwingComboBox {
id: "pobStateField"
items: [statesComboItems]
visible: true
}
var changeFieldsOpacity:Node[] = [
firstNameField,
middleNameField,
lastNameField,
suffixNameField,
dobField,
pobCityField,
pobCountyField,
pobStateField,
];
changeOpacity(changeFieldsOpacity, .80);
nodesToLayout = [
sectionFullName, // 0
instructionsText, // 1
firstNameLabel, // 2
firstNameField, // 3
middleNameLabel, // 4
middleNameField, // 5
lastNameLabel, // 6
lastNameField, // 7
suffixNameLabel, // 8
suffixNameField, // 9
sectionDob, // 10
dobLabel, // 11
dobField, // 12
sectionPlaceOfBirth,// 13
pobCityLabel, // 14
pobCityField, // 15
pobCountyLabel, // 16
pobCountyField, // 17
pobStateLabel, // 18
pobStateField, // 19
];
// +---------------------------------------------------
// ! Poor Man's designer constraints info goes below
// +---------------------------------------------------
// [BEGIN]
constraints = "";
columns = "[pref]10[fill]";
rows = "[pref]10[pref]";
componentsConstraints = [
"span, growx, wrap", // fullNameTitle 0
"span, wrap 15px", // instructionsText 1
"align right", // firstNameLabel 2
"span, w min:100:300, wrap", // firstNameField 3
"align right", // middleNameLabel 4
"growx, w min:100:300, wrap", // middleNameField 5
"align right", // lastNameLabel 6
"growx, w min:100:300, wrap", // lastNameField 7
"align right", // suffixNameLabel 8
" w min:100:300, wrap 15", // suffixNameField 9
"span, wrap", // dobTitle 10
"align right", // dobLabel 11
" w min:100:pref, wrap 15", // dobField 12
"span, wrap", // pobTitle 13
"align right", // pobCityLabel 14
"span, growx, w min:100:300, wrap", // pobCityField 15
"align right", // pobCountyLabel 16
"span, growx, w min:100:300, wrap", // pobCountyField 17
"align right", // pobStateLabel 18
"span, w pref:100:pref + 10, wrap", // pobStateField 19
];
// [END]
// +---------------------------------------------------
// ! Poor Man's designer constraints info goes above
// +---------------------------------------------------
}
// IMPORTANT - This will generate mig nodes to be put
// into your content to be displayed in the scene.
postinit {
content = for (i in [0.. sizeof nodesToLayout -1]) {
migNode(nodesToLayout[i], componentsConstraints[i]);
}
}
}
public function changeOpacity(nodes:Node[], opacityLevel:Float):Void {
for (n in nodes) {
n.opacity = opacityLevel;
}
}
poormans_form_designer.fx –
/*
* poormans_form_designer.fx
*
* @author Carl Dea
* Created on Jan 2, 2010, 8:05:06 PM
*/
package migtest3;
import javafx.ext.swing.SwingComboBox;
import javafx.ext.swing.SwingComboBoxItem;
import javafx.ext.swing.SwingComponent;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Sequences;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import org.jfxtras.scene.ResizableScene;
import org.jfxtras.scene.layout.MigLayout;
import org.jfxtras.scene.layout.MigLayout.*;
import org.jfxtras.stage.JFXDialog;
/** Title of the designer */
var designViewTitle:String = "Poor Man's Form Designer ver 0.2";
/**
* This makes a node MigLayout capable.
*
*/
public class MigLayoutDesigner {
public var layoutConstraint:String = "";
public var columnsConstraint:String = "";
public var rowsConstraint:String = "";
public var componentsConstraints:String[] = [];
public var nodesToLayout:Node[];
public var migNodesToLayout:Node[] = bind generateMigNodes(nodesToLayout, componentsConstraints);
protected var dynamicMigLayout:MigLayout;
postinit {
dynamicMigLayout = createBindableMigLayout();
}
// public abstract function createMigLayoutNode():Void;
/**
* Creates a bound MigLayout.
*/
bound public function createBindableMigLayout() {
MigLayout {
constraints: bind layoutConstraint
columns: bind columnsConstraint
rows: bind rowsConstraint
content: bind migNodesToLayout
}
}
}
/**
* Generates a sequence of Nodes wrapped with migNode function.
*/
bound public function generateMigNodes(nodes:Node[], componentConstraintStrings:String[]){
for (i in [0.. sizeof nodes -1]) {
migNode(nodes[i], componentConstraintStrings[i]);
}
}
/**
* @param migForm - a MigLayoutCapable form. Inherits from the mixin MigLayoutCapable.
* @param designerViewScene - The designer View of the Scene. If null one will be created.
* @param designerViewStage - The designer View of the Stage (Window). If null one will be created.
*/
public function launch(migForm:MigLayoutDesigner, designerViewScene:Scene, designerViewStage:Stage) {
// List Comprehensions - Strings representing nodes' id
var listIds = for( n in migForm.nodesToLayout) n.id;
// List comprehensions - SwingComboBoxItems
var comboboxItems = for( n in listIds) SwingComboBoxItem{ text:n };
// Combo Box control with ids of each widget on form.
var idListBox:SwingComboBox = SwingComboBox {
text : bind componentIdSelection with inverse;
items: [comboboxItems]
}
// select first one as default
idListBox.selectedIndex = 0;
////////////////////////////////////////////////////
// Layout constraints section
////////////////////////////////////////////////////
var layoutConstraintLabel:Label = Label {
text: "Layout Constraint"
font: Font {
embolden:true
size: 20
}
}
var layoutConstraintTextBox:TextBox = TextBox {
text: migForm.layoutConstraint
selectOnFocus: true
}
// Updates the layout constraint when pressed
var layoutConstraintApplyButton:Button = Button {
text: "Apply"
action: function() {
migForm.layoutConstraint = layoutConstraintTextBox.text;
}
}
////////////////////////////////////////////////////
// Column constraints section
////////////////////////////////////////////////////
var columnsConstraintLabel:Label = Label {
text: "Columns Constraint"
font: Font {
embolden:true
size: 20
}
}
// Constraint textbox
var columnsConstraintTextBox:TextBox = TextBox {
text: migForm.columnsConstraint
columns: 30
};
// Updates the columns constraint when pressed
var columnsConstraintApplyButton:Button = Button {
text: "Apply"
action: function() {
migForm.columnsConstraint = columnsConstraintTextBox.text;
}
};
////////////////////////////////////////////////////
// Row constraints section
////////////////////////////////////////////////////
var rowsConstraintLabel:Label = Label {
text: "Rows Constraint"
font: Font {
embolden:true
size: 20
}
}
// Constraint textbox
var rowsConstraintTextBox:TextBox = TextBox {
text: migForm.rowsConstraint
columns: 30
};
// Updates the rows constraint when pressed
var rowsConstrainApplyButton:Button = Button {
text: "Apply"
action: function() {
migForm.rowsConstraint = rowsConstraintTextBox.text;
}
};
////////////////////////////////////////////////////
// Component constraints section
////////////////////////////////////////////////////
var componentsConstraintLabel:Label = Label {
text: "Nodes Constraints"
font: Font {
embolden:true
size: 20
}
};
// Constraint textbox
var componentConstraintTextBox:TextBox = TextBox {
columns: 30
};
var componentIdSelection: String on replace {
componentConstraintTextBox.text = migForm.componentsConstraints [
Sequences.indexByIdentity(listIds, componentIdSelection)
];
};
var componentConstraintApplyButton:Button = Button {
text: "Apply"
action: function() {
for (i in [0.. sizeof migForm.nodesToLayout -1]) {
if (migForm.nodesToLayout[i].id.equalsIgnoreCase(componentIdSelection)) {
migForm.componentsConstraints[i] = componentConstraintTextBox.text;
break;
}
}
} // action
};
////////////////////////////////////////////////////
// MigLayout Dump constraints section
////////////////////////////////////////////////////
var miglayoutDumpLabel:Label = Label {
text: "MigLayout Constraints Dump"
font: Font {
embolden:true
size: 20
}
};
var constraintsDumpButton:Button = Button {
text: "Dump"
action: function() {
//var miglayout:MigLayout = personFormScene.content[0] as MigLayout;
var buffer:String;
var migStructure:String;
buffer = "constraints = \"{migForm.layoutConstraint}\";\n"
"columns = \"{migForm.columnsConstraint}\"; \n"
"rows = \"{migForm.rowsConstraint}\";\n"
"componentsConstraints = [\n";
for (i in [0.. sizeof listIds -1]) {
//buffer2 = "{buffer2}\" id: {listIds[i]} - {migForm.componentsConstraints[i]}\n";
var strElement = "\"{migForm.componentsConstraints[i]}\", // {listIds[i]} {i} \n";
var spaces = generateSpaces(55 - strElement.length());
buffer = "{buffer} \"{migForm.componentsConstraints[i]}\", {spaces} // {listIds[i]} {i} \n";
}
buffer = "{buffer}];\n";
constraintsDumpTextArea.setText("{buffer}");
}
};
// set up a swing wrapped text area box to hold dumped constraints.
var constraintsDumpTextArea:JTextArea = new JTextArea();
constraintsDumpTextArea.setColumns(40);
constraintsDumpTextArea.setRows(20);
constraintsDumpTextArea.setAutoscrolls(true);
var sp = new JScrollPane(constraintsDumpTextArea);
var constraintsDumpTextAreaJfx = SwingComponent.wrap(sp);
// constrains for the constraint configure window.
var editorComponentsConstraints = [
"wrap",
"growx",
"wrap",
"span, newline 15px, wrap",
"growx",
"wrap",
"span, newline 15px, wrap",
"growx",
"wrap",
"span, newline 15px, wrap",
"growx",
"grow",
"",
"newline 20px",
"span, align right, wrap",
"span, growx"
];
var inputPanelToLayout = [
layoutConstraintLabel, // 0
layoutConstraintTextBox, // 1
layoutConstraintApplyButton,// 2
columnsConstraintLabel, // 3
columnsConstraintTextBox, // 4
columnsConstraintApplyButton,// 5
rowsConstraintLabel, // 6
rowsConstraintTextBox, // 7
rowsConstrainApplyButton, // 8
componentsConstraintLabel,// 9
idListBox, // 10
componentConstraintTextBox,// 11
componentConstraintApplyButton, // 12
miglayoutDumpLabel, // 13
constraintsDumpButton, // 14
constraintsDumpTextAreaJfx,// 15
];
// convert to miglayout type nodes wrapped.
var editorMigNodesToLayout:Node[] = bind generateMigNodes(inputPanelToLayout, editorComponentsConstraints);
// check if user of the api sent in a Scene or not.
var newDesignerViewScene:Scene = designerViewScene;
if (designerViewScene == null) {
newDesignerViewScene = ResizableScene {
fill: LinearGradient {
startX : 0.0
startY : 0.0
endX : 1.0
endY : 0.0
stops: [
Stop {
color : Color.DARKTURQUOISE
offset: 0.0
},
Stop {
color : Color.WHITE
offset: 1.0
},
] // stops
} // fill
content: [migForm.dynamicMigLayout] // content
}; // scene
}
// check if user of the api sent in a Stage or not.
var newDesignerStageView:Stage = designerViewStage;
if (designerViewStage == null) {
// Form View (Person Form)
newDesignerStageView = Stage {
y:150
x:100
width: 500
height: 500
title: designViewTitle
scene: newDesignerViewScene
visible:true
opacity: .94
}
} else {
newDesignerStageView.scene = newDesignerViewScene;
if ("".equals(newDesignerStageView.title.trim())) {
newDesignerStageView.title = designViewTitle;
}
}
// Generate Scene for design view if one doesn't exist
var constraintInputWindowScene:Scene = ResizableScene {
fill: Color.GRAY
content: [
MigLayout {
content:bind inputPanelToLayout
},
] // content
};
// Form Design Constraint Editor.
var constraintInputWindow:JFXDialog = JFXDialog{
title: "Form Design Constraints Editor"
owner:newDesignerStageView
x: newDesignerStageView.x + newDesignerStageView.width
y: 150
modal:false
visible:true
scene:constraintInputWindowScene
height:500
width: 600
}
}
/** Assisting dump button to display constraints nicely
* to ease cut and paste in to Form for the user.
* @param numSpaces
*/
function generateSpaces(numSpaces:Integer):String {
var spaces:String = "";
for (i in [1..numSpaces]) {
spaces = "{spaces} ";
}
return spaces;
}
References
MigLayout by Dean Iverson – Pleasing Software – http://pleasingsoftware.blogspot.com/search?q=layout
JavaFX and Layouts by Amy Fowler – http://weblogs.java.net/blog/aim/archive/2009/09/10/javafx12-layout
JFXtras & MigLayout – http://jfxtras.googlecode.com/svn/site/javadoc/release-0.5/org.jfxtras.scene.layout/org.jfxtras.scene.layout.MigLayout.html
MigLayout Cheatsheet – http://migcalendar.com/miglayout/cheatsheet.html
JFXtras – Miglayout wiki – http://jfxtras.org/portal/core/-/wiki/JFXtras/MigLayout
Swing GUI Builder (formerly Project Matisse) – http://netbeans.org/features/java/swing.html
Abeille Form Designer – https://abeille.dev.java.net/
JForm Designer – http://www.formdev.com/
WindowBuilder – http://www.instantiations.com/windowbuilder/
Swing tutorial – http://java.sun.com/docs/books/tutorial/uiswing/
SWT – http://www.eclipse.org/swt/
Swing layout – http://java.sun.com/docs/books/tutorial/uiswing/layout/using.html
Swing GUI Builder (formerly Project Matisse)