The EntityEditPanel manages the input components (text fields, combo boxes and such) for editing an entity instance.
When extending an EntityEditPanel you must implement the initializeUI() method, which initializes the edit panel UI. The EntityEditPanel class exposes methods for creating input components and binding them with the underlying EntityEditModel instance.
public class CustomerEditPanel extends EntityEditPanel {
public CustomerEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
//the firstName field should receive the focus whenever the panel is initialized
focus().initial().set(Customer.FIRST_NAME);
createTextField(Customer.FIRST_NAME);
createTextField(Customer.LAST_NAME);
createTextField(Customer.EMAIL);
createCheckBox(Customer.ACTIVE);
setLayout(new GridLayout(4, 1));
//the addInputPanel method creates and adds a panel containing the
//component associated with the attribute as well as a JLabel with the
//property caption as defined in the domain model
addInputPanel(Customer.FIRST_NAME);
addInputPanel(Customer.LAST_NAME);
addInputPanel(Customer.EMAIL);
addInputPanel(Customer.ACTIVE);
}
}
public class AddressEditPanel extends EntityEditPanel {
public AddressEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
focus().initial().set(Address.STREET);
createTextField(Address.STREET).columns(25);
createTextField(Address.CITY).columns(25);
createCheckBox(Address.VALID);
setLayout(new GridLayout(3, 1, 5, 5));
addInputPanel(Address.STREET);
addInputPanel(Address.CITY);
addInputPanel(Address.VALID);
}
}
public class CustomerAddressEditPanel extends EntityEditPanel {
public CustomerAddressEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
focus().initial().set(CustomerAddress.ADDRESS_FK);
createComboBoxPanel(CustomerAddress.ADDRESS_FK, this::createAddressEditPanel)
.preferredWidth(280)
.includeAddButton(true);
setLayout(borderLayout());
addInputPanel(CustomerAddress.ADDRESS_FK);
}
private AddressEditPanel createAddressEditPanel() {
return new AddressEditPanel(new SwingEntityEditModel(Address.TYPE, editModel().connectionProvider()));
}
}
1. Detailed example
Here’s how a text field is created and added to the edit panel.
createTextField(Customer.FIRST_NAME)
.columns(12);
setLayout(gridLayout(1, 1));
addInputPanel(Customer.FIRST_NAME);
And here’s the equivilent code, showing what’s going on behind the scenes.
ColumnDefinition<String> firstNameDefinition =
editModel().entityDefinition().columns().definition(Customer.FIRST_NAME);
//create the text field
JTextField firstNameField = new JTextField();
firstNameField.setColumns(12);
firstNameDefinition.description()
.ifPresent(firstNameField::setToolTipText);
//associate the text field with the first name attribute
component(Customer.FIRST_NAME).set(firstNameField);
//wrap the text field in a ComponentValue
ComponentValue<String, JTextField> firstNameFieldValue =
new AbstractTextComponentValue<String, JTextField>(firstNameField) {
@Override
protected String getComponentValue() {
return component().getText();
}
@Override
protected void setComponentValue(String text) {
component().setText(text);
}
};
//link the component value to the attribute value in the editor
firstNameFieldValue.link(editModel().editor().value(Customer.FIRST_NAME));
//create the first name label
JLabel firstNameLabel = new JLabel(firstNameDefinition.caption());
//associate the label with the text field
firstNameLabel.setLabelFor(firstNameField);
//create an input panel, with the label and text field
JPanel firstNamePanel = new JPanel(borderLayout());
firstNamePanel.add(firstNameLabel, BorderLayout.NORTH);
firstNamePanel.add(firstNameField, BorderLayout.CENTER);
setLayout(gridLayout(1, 1));
add(firstNamePanel);
2. Input controls
2.1. Boolean
JCheckBox checkBox =
createCheckBox(Demo.BOOLEAN)
.build();
NullableCheckBox nullableCheckBox =
(NullableCheckBox) createCheckBox(Demo.BOOLEAN)
.nullable(true)
.build();
JComboBox<Item<Boolean>> comboBox =
createBooleanComboBox(Demo.BOOLEAN)
.build();
2.2. Foreign key
EntityComboBox comboBox =
createComboBox(Demo.FOREIGN_KEY)
.build();
EntitySearchField searchField =
createSearchField(Demo.FOREIGN_KEY)
.build();
//readOnly
JTextField textField =
createTextField(Demo.FOREIGN_KEY)
.build();
2.3. Temporal
TemporalField<LocalDateTime> textField =
(TemporalField<LocalDateTime>) createTextField(Demo.LOCAL_DATE)
.build();
TemporalField<LocalDate> localDateField =
createTemporalField(Demo.LOCAL_DATE)
.build();
TemporalFieldPanel<LocalDate> temporalPanel =
createTemporalFieldPanel(Demo.LOCAL_DATE)
.build();
2.4. Numerical
NumberField<Integer> integerField =
(NumberField<Integer>) createTextField(Demo.INTEGER)
.build();
integerField =
createIntegerField(Demo.INTEGER)
.build();
NumberField<Long> longField =
(NumberField<Long>) createTextField(Demo.LONG)
.build();
longField =
createLongField(Demo.LONG)
.build();
NumberField<Double> doubleField =
(NumberField<Double>) createTextField(Demo.DOUBLE)
.build();
doubleField =
createDoubleField(Demo.DOUBLE)
.build();
NumberField<BigDecimal> bigDecimalField =
(NumberField<BigDecimal>) createTextField(Demo.BIG_DECIMAL)
.build();
bigDecimalField =
createBigDecimalField(Demo.BIG_DECIMAL)
.build();
2.5. Text
JTextField textField =
createTextField(Demo.TEXT)
.build();
JFormattedTextField maskedField =
createMaskedTextField(Demo.FORMATTED_TEXT)
.mask("###:###")
.valueContainsLiteralCharacters(true)
.build();
JTextArea textArea =
createTextArea(Demo.LONG_TEXT)
.rowsColumns(5, 20)
.build();
TextFieldPanel inputPanel =
createTextFieldPanel(Demo.LONG_TEXT)
.build();
2.6. Selection
DefaultComboBoxModel<String> comboBoxModel =
new DefaultComboBoxModel<>(new String[] {"One", "Two"});
JComboBox<String> comboBox =
createComboBox(Demo.TEXT, comboBoxModel)
.editable(true)
.build();
3. Panels & labels
JLabel label = createLabel(Demo.TEXT)
.build();
JPanel inputPanel = createInputPanel(Demo.TEXT)
.label(new JLabel("Label"))
.build();
4. Advanced Patterns
4.1. Configuration Options
EntityEditPanel supports configuration via a lambda in the constructor:
class InvoiceEditPanel extends EntityEditPanel {
public InvoiceEditPanel(SwingEntityEditModel editModel) {
super(editModel, config ->
// Keep displaying newly inserted invoice since we'll continue
// working with it by adding invoice lines
config.clearAfterInsert(false));
}
@Override
protected void initializeUI() {
// UI setup
}
}
4.2. Focus Management
Configure the focus behaviour:
class CustomerEditPanel extends EntityEditPanel {
public CustomerEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
focus().initial().set(Customer.FIRSTNAME);
focus().afterInsert().set(Customer.ADDRESS);
// Create your input components...
}
}
4.3. Inline Edit Panels with ComboBoxPanel
Create combo boxes with inline add/edit capabilities:
class TrackEditPanel extends EntityEditPanel {
public TrackEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
createComboBoxPanel(Track.MEDIATYPE_FK, this::createMediaTypeEditPanel)
.preferredWidth(160)
.includeAddButton(true)
.includeEditButton(true);
createSearchFieldPanel(Track.MEDIATYPE_FK, this::createMediaTypeEditPanel)
.preferredWidth(160)
.includeAddButton(true)
.includeEditButton(true);
}
private EntityEditPanel createMediaTypeEditPanel() {
return new MediaTypeEditPanel(new SwingEntityEditModel(Chinook.MediaType.TYPE, editModel().connectionProvider()));
}
}
4.4. Custom Component Integration
Replace default components with custom ones:
class TrackEditPanel extends EntityEditPanel {
public TrackEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
// Create a custom component
DurationComponentValue durationValue = createDurationComponent();
// Link it to the attribute value
editModel().editor().value(Track.MILLISECONDS).link(durationValue);
// And set the component it as the attribute component
component(Track.MILLISECONDS).set(durationValue.component());
}
private DurationComponentValue createDurationComponent() {
// Custom implementation
return new DurationComponentValue();
}
}
4.5. Keyboard Shortcuts and Actions
Add custom keyboard shortcuts for enhanced productivity:
class CustomerEditPanel extends EntityEditPanel {
public CustomerEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
createTextField(Customer.STATE)
.keyEvent(KeyEvents.builder()
.keyCode(VK_SPACE)
.modifiers(CTRL_DOWN_MASK)
.action(Control.action(this::selectStateFromExistingValues)));
}
private void selectStateFromExistingValues(ActionEvent event) {
JTextField stateField = (JTextField) event.getSource();
Dialogs.select()
.list(editModel().connection().select(Customer.STATE))
.owner(stateField)
.select()
.single()
.ifPresent(stateField::setText);
}
}
4.6. Detail Panel Integration
EntityEditPanel can include detail panels for master-detail relationships:
class InvoiceEditPanel extends EntityEditPanel {
private final EntityPanel invoiceLinePanel;
public InvoiceEditPanel(SwingEntityEditModel editModel, SwingEntityModel invoiceLineModel) {
super(editModel, config -> config.clearAfterInsert(false));
this.invoiceLinePanel = createInvoiceLinePanel(invoiceLineModel);
}
@Override
protected void initializeUI() {
// Initialize main edit controls...
// Add detail panel
add(invoiceLinePanel, BorderLayout.SOUTH);
}
private EntityPanel createInvoiceLinePanel(SwingEntityModel invoiceLineModel) {
// Create and return invoice line panel
return new EntityPanel(invoiceLineModel);
}
}