Java Swing: How to Change Gui Dynamically

Java Swing: How to change GUI dynamically

For reference, here's an sscce that shows the essential method, validate(). This more elaborate example shows both requirements: it changes the layout and adds components dynamically.

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;

/** @see http://stackoverflow.com/questions/5750068 */
public class DynamicLayout extends JPanel {

private static final LayoutManager H = new GridLayout(1, 0);
private static final LayoutManager V = new GridLayout(0, 1);

public DynamicLayout() {
this.setLayout(H);
this.setPreferredSize(new Dimension(320, 240));
for (int i = 0; i < 3; i++) {
this.add(new JLabel("Label " + String.valueOf(i), JLabel.CENTER));
}
}

private void display() {
JFrame f = new JFrame("DynamicLayout");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
JPanel p = new JPanel();
p.add(new JButton(new AbstractAction("Horizontal") {

@Override
public void actionPerformed(ActionEvent e) {
DynamicLayout.this.setLayout(H);
DynamicLayout.this.validate();
}
}));
p.add(new JButton(new AbstractAction("Vertical") {

@Override
public void actionPerformed(ActionEvent e) {
DynamicLayout.this.setLayout(V);
DynamicLayout.this.validate();
}
}));
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new DynamicLayout().display();
}
});
}
}

How to implement dynamic GUI in swing

only example, everything is hardcoded, for good understanding

EDIT:

as kleopatra's noticed, moved JTable#fireTableDataChanged() from ActionListener to the TableModel, amended all ClassNames start with lowerCase

import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.table.*;

public class ComponentTableTest {

private JFrame frame;
private JTable CompTable = null;
private CompTableModel CompModel = null;
private JButton addButton = null;

public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {
new ComponentTableTest().makeUI();
}
});
}

public void makeUI() {
CompTable = CreateCompTable();
JScrollPane CompTableScrollpane = new JScrollPane(CompTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JPanel bottomPanel = CreateBottomPanel();
frame = new JFrame("Comp Table Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(CompTableScrollpane, BorderLayout.CENTER);
frame.add(bottomPanel, BorderLayout.SOUTH);
frame.setPreferredSize(new Dimension(800, 400));
frame.setLocation(150, 150);
frame.pack();
frame.setVisible(true);
}

public JTable CreateCompTable() {
CompModel = new CompTableModel();
CompModel.addRow();
JTable table = new JTable(CompModel);
table.setRowHeight(new CompCellPanel().getPreferredSize().height);
table.setTableHeader(null);
CompCellEditorRenderer compCellEditorRenderer = new CompCellEditorRenderer();
table.setDefaultRenderer(Object.class, compCellEditorRenderer);
table.setDefaultEditor(Object.class, compCellEditorRenderer);
return table;
}

public JPanel CreateBottomPanel() {
addButton = new JButton("Add Comp");
addButton.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();

if (source == addButton) {
CompModel.addRow();
//CompModel.fireTableDataChanged(); // moved to TableModel
}
}
});
JPanel panel = new JPanel(new GridBagLayout());
panel.add(addButton);
return panel;
}
}

class CompCellEditorRenderer extends AbstractCellEditor implements TableCellRenderer, TableCellEditor {

private static final long serialVersionUID = 1L;
private CompCellPanel renderer = new CompCellPanel();
private CompCellPanel editor = new CompCellPanel();

@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
renderer.setComp((Comp) value);
return renderer;
}

@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
editor.setComp((Comp) value);
return editor;
}

@Override
public Object getCellEditorValue() {
return editor.getComp();
}

@Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}

@Override
public boolean shouldSelectCell(EventObject anEvent) {
return false;
}
}

class CompTableModel extends DefaultTableModel {

private static final long serialVersionUID = 1L;

@Override
public int getColumnCount() {
return 1;
}

public void addRow() {
super.addRow(new Object[]{new Comp(0, 0, "", "")});
//super.fireTableDataChanged();
}
}

class Comp {

int type;
int relation;
String lower;
String upper;

public Comp(int type, int relation, String lower, String upper) {
this.type = type;
this.relation = relation;
this.lower = lower;
this.upper = upper;
}
}

class CompCellPanel extends JPanel {

private static final long serialVersionUID = 1L;
private JLabel labelWith = new JLabel("With ");
private JComboBox typeCombo = new JComboBox(new Object[]{"height", "length", "volume"});
private JComboBox relationCombo = new JComboBox(new Object[]{"above", "below", "between"});
private JTextField lowerField = new JTextField();
private JLabel labelAnd = new JLabel(" and ");
private JTextField upperField = new JTextField();
private JButton removeButton = new JButton("remove");

CompCellPanel() {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
relationCombo.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
enableUpper(relationCombo.getSelectedIndex() == 2);
}
});
enableUpper(false);
removeButton.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
JTable table = (JTable) SwingUtilities.getAncestorOfClass(JTable.class, (Component) e.getSource());
int row = table.getEditingRow();
table.getCellEditor().stopCellEditing();
((DefaultTableModel) table.getModel()).removeRow(row);
}
});
add(labelWith);
add(typeCombo);
add(relationCombo);
add(lowerField);
add(labelAnd);
add(upperField);
add(Box.createHorizontalStrut(100));
add(removeButton);
}

private void enableUpper(boolean enable) {
labelAnd.setEnabled(enable);
upperField.setEnabled(enable);
}

public void setComp(Comp Comp) {
typeCombo.setSelectedIndex(Comp.type);
relationCombo.setSelectedIndex(Comp.relation);
lowerField.setText(Comp.lower);
upperField.setText(Comp.upper);
enableUpper(Comp.relation == 2);
}

public Comp getComp() {
return new Comp(typeCombo.getSelectedIndex(), relationCombo.getSelectedIndex(), lowerField.getText(), upperField.getText());
}
}

java - How would I dynamically add swing component to gui on click?

Sample code to add Buttons on the fly dynamically.

panel.add(new JButton("Button"));
validate();

Full code:

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.FlowLayout;
import java.awt.BorderLayout;

public class AddComponentOnJFrameAtRuntime extends JFrame implements ActionListener {

JPanel panel;

public AddComponentOnJFrameAtRuntime() {
super("Add component on JFrame at runtime");
setLayout(new BorderLayout());
this.panel = new JPanel();
this.panel.setLayout(new FlowLayout());
add(panel, BorderLayout.CENTER);
JButton button = new JButton("CLICK HERE");
add(button, BorderLayout.SOUTH);
button.addActionListener(this);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 500);
setVisible(true);
}

public void actionPerformed(ActionEvent evt) {
this.panel.add(new JButton("Button"));
this.panel.revalidate();
validate();
}

public static void main(String[] args) {
AddComponentOnJFrameAtRuntime acojfar = new AddComponentOnJFrameAtRuntime();
}
}
  • Resource

Dynamic changing of layouts in swing

OK -- so it looks like what you want to do (and please correct me if I'm wrong) is to add a new component to a JPanel that is displayed within a JScrollPane. If so, then you do not want to change or swap layouts, and you certainly don't want to keep adding new JScrollPanes. Instead consider doing:

  • Create one JScrollPane and add to your GUI. Don't re-add this as you'll only need one.
  • add a JPanel to the JScrollPane's viewport that uses a layout that allows multiple components to be easily added to it. Perhaps a GridLayout or a BoxLayout, depending on what you need.
  • Also consider not adding the above JPanel directly to the viewport but rather adding it to another JPanel, one that uses BorderLayout, adding the first JPanel to the BorderLayout-using JPanel's BorderLayout.PAGE_START position, and then add this to the JScrollPane's viewport. This way the first JPanel won't stretch to fill the viewport initially.
  • Then in your button's ActionListener, add your components to the first JPanel by calling .add(...) on it, and then call revalidate() and repaint() on that first JPanel to layout the newly added components and repaint the JPanel and its contents.

Java Swing GUI creation - How to get dynamically created buttons to update properly

Again, the issue is creating a model and somehow tying it to your view (the GUI). Best is to create and maintain good separation between these two classes or groups of classes, but to keep things simpler in this instance, we can combine them in the GUI. To show you what I mean, consider this simplification of your code, one that uses very simple Car and ParkingSlot classes:

public class Car {
private String name;

public Car(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public String toString() {
return "Car: " + name;
}
}

public class ParkingSlot {
private Car car;
private String name;

public ParkingSlot(String name) {
this.name = name;
}

public void setCar(Car car) {
this.car = car;
}

public Car getCar() {
return car;
}

public void clear() {
car = null;
}

public String getName() {
return name;
}

@Override
public String toString() {
String value = "Slot: " + name + "; ";
if (car == null) {
value += "empty";
} else {
value += car.toString();
}
return value;
}
}

I want a model that ties a String to a ParkingSlot, and for this, best is to use a Map<String, ParkingSlot>. This is a collection that holds ParkingSlot objects and makes them accessable by the slot's "name", the String. I would often initialize this as a new HashMap<String, ParkingSlot>(), but I also want to maintain insertion order in the Map so that if I iterate through it, it is not in some random order (as HashMaps tend to be), and so, I'd initialize this using a LinkedHashMap<String, ParkingSlot>, since this is just like a HashMap but retains insertion order:

private Map<String, ParkingSlot> slotMap = new LinkedHashMap<>();

And so, if later I want to iterate through the collection, display the status of the ParkingSlot objects, I could simply use a for loop:

for (Entry<String, ParkingSlot> entry : slotMap.entrySet()) {
System.out.printf("%s%n", entry.getValue());
}

So, now when creating your JButton grid, associate it with the collection of ParkingSlot objects, using the String that defines the slot. This can be the key for the Map and also can be associated with the JButton by using it to set the button's actionCommand, a String that every button carries with it:

JPanel gridPanel = new JPanel(new GridLayout(0, 1));
for (int i = 0; i < slotCount; i++) {
String slotName = String.format("V%03d", i);
ParkingSlot slot = new ParkingSlot(slotName);
slotMap.put(slotName, slot);

JButton button = new JButton(slotName + ": Empty");
button.setActionCommand(slotName);
button.addActionListener(e -> parkingSlotButtonAction(e));
gridPanel.add(button);
}

When any of the buttons are pressed, the parkingSlotButtonAction(ActionEvent e) method is called, and it can get the source JButton by calling e.getSource() on the parameter, and can get the button's actionCommand by calling e.getActionCommand() on the same parameter. It can get the associated ParkingSlot object by using the slotMap:

private void parkingSlotButtonAction(ActionEvent e) {
String slotName = e.getActionCommand();
JButton source = (JButton) e.getSource();
ParkingSlot slot = slotMap.get(slotName);

// .....
}

A complete simple example could look like this:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.*;
import javax.swing.event.ChangeListener;

public class SimpleLotMain {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
LotGui gui = new LotGui(20);

JFrame frame = new JFrame("Lot");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(gui);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}

@SuppressWarnings("serial")
class LotGui extends JPanel {
private Map<String, ParkingSlot> slotMap = new LinkedHashMap<>();

public LotGui(int slotCount) {
JPanel gridPanel = new JPanel(new GridLayout(0, 1));
for (int i = 0; i < slotCount; i++) {
String slotName = String.format("V%03d", i);
ParkingSlot slot = new ParkingSlot(slotName);
slotMap.put(slotName, slot);

JButton button = new JButton(slotName + ": Empty");
button.setActionCommand(slotName);
button.addActionListener(e -> parkingSlotButtonAction(e));
gridPanel.add(button);
}

JScrollPane scrollPane = new JScrollPane(gridPanel);
scrollPane.getViewport().setPreferredSize(new Dimension(400, 400));

JButton displaySlotsBtn = new JButton("Display Parking Spots");
displaySlotsBtn.addActionListener(e -> displaySlots());

JPanel bottomPanel = new JPanel();
bottomPanel.add(displaySlotsBtn);

setLayout(new BorderLayout());
add(scrollPane);
add(bottomPanel, BorderLayout.PAGE_END);
}

private void parkingSlotButtonAction(ActionEvent e) {
String slotName = e.getActionCommand();
JButton source = (JButton) e.getSource();
ParkingSlot slot = slotMap.get(slotName);

// JOptionPane to query whether to add/remove car

String carName = JOptionPane.showInputDialog("Enter Name of Car to Add");

// if the user cancels the dialog or enters only white-space text: exit
if (carName == null || carName.trim().isEmpty()) {
return;
}

// else, use the name
Car car = new Car(carName);
slot.setCar(car);

String text = slotName + ": " + carName;
source.setText(text);
}

private void displaySlots() {
for (Entry<String, ParkingSlot> entry : slotMap.entrySet()) {
System.out.printf("%s%n", entry.getValue());
}
}

}

//class SLot {
// List<ParkingSlot> slots = new ArrayList<>();
//
// public SLot(int carCount) {
// for (int i = 0; i < carCount; i++) {
// String name = String.format("S%03d", i);
// slots.add(new ParkingSlot(name));
// }
// }
//
// @Override
// public String toString() {
// return "SLot [slots=" + slots + "]";
// }
//
// public void addChangeListener(ChangeListener l) {
//
// }
//}

class Car {
private String name;

public Car(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public String toString() {
return "Car: " + name;
}
}

class ParkingSlot {
private Car car;
private String name;

public ParkingSlot(String name) {
this.name = name;
}

public void setCar(Car car) {
this.car = car;
}

public Car getCar() {
return car;
}

public void clear() {
car = null;
}

public String getName() {
return name;
}

@Override
public String toString() {
String value = "Slot: " + name + "; ";
if (car == null) {
value += "empty";
} else {
value += car.toString();
}
return value;
}
}

How to dynamically control auto-resize components in Java Swing

Setting the max/min/preferred size of the Green panel can keep that panel the same size under the first condition. To check for resizes, you can use a ComponentListener on one of the other JPanel's - if the size gets below a particular width then change the max/min/preferred size of the Green panel.

Below is a hacked together example of doing this - it resizes the Green panel when the Blue is < 600, and the resize is a weighted resize (30% of total width). To get the true L&F and that you desire you may have to play with the layout/sizes.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;

public class GridTest extends JPanel{

private boolean changeAllowed = false;
//keep reference to cyan for the height dimension
final JPanel cyan = new JPanel();

public GridTest(){
cyan.setPreferredSize(new Dimension(600, 300));//provide sizing hint
}

private Dimension getCustomDimensions(){
if ( changeAllowed ){
return new Dimension((int)(super.getParent().getBounds().width * 0.3), cyan.getBounds().height);
}else{
return new Dimension(200, cyan.getBounds().height);
}
}
@Override
public Dimension getMaximumSize(){
return getCustomDimensions();
}
@Override
public Dimension getMinimumSize(){
return getCustomDimensions();
}
@Override
public Dimension getPreferredSize(){
return getCustomDimensions();
}

public static void main(String[] args) throws Exception{
SwingUtilities.invokeAndWait(new Runnable(){

@Override
public void run() {
final int MINIMUM = 600;
JFrame frame = new JFrame();
frame.add(new JToolBar(), BorderLayout.NORTH);
final JPanel blue = new JPanel();

final GridTest green = new GridTest();
green.setBackground(Color.green);
green.setOpaque(true);

green.cyan.setBackground(Color.cyan);
green.cyan.setOpaque(true);
blue.setOpaque(true);
blue.setBackground(Color.blue);
blue.setPreferredSize(new Dimension(900, 300));//hint at size
blue.setMinimumSize(new Dimension(100, 200));//hint at size
//Nest Box Layouts
Box top = Box.createHorizontalBox();
top.add(blue);
Box bottom = Box.createHorizontalBox();
bottom.add(green);
bottom.add(green.cyan);
Box vert = Box.createVerticalBox();
vert.add(top);
vert.add(bottom);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(vert);
//listen for resizes
blue.addComponentListener(new ComponentAdapter(){

@Override
public void componentResized(ComponentEvent e) {
if ( blue.getBounds().width < MINIMUM ){//set flag
green.changeAllowed = true;
}else{
green.changeAllowed = false;
}
}
});

frame.pack();
frame.setSize(800, 600);
frame.setVisible(true);

}

});
}
}

Dynamic JFrame - Changing JFrame contents

Use this as your code.....

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Demo {
JFrame frame;
JButton nextButton = new JButton ("Next Screen");
PanelOne p = new PanelOne();
public void setup() {
frame = new JFrame();
frame.setVisible(true);

frame.add(p);
frame.pack();
}

public class PanelOne extends JPanel { {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(new JLabel("Label One"));
this.add(new JLabel("Label Two"));
this.add(new JLabel("Label Three"));
this.add(new JLabel("Label Four"));
this.add(new JLabel("Label Five"));
JButton button = new JButton("Next Screen");
button.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
swapPanel();
}
});
this.add(button);
} }
public class PanelTwo extends JPanel {{
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(new JButton("Button One"));
this.add(new JButton("Button Two"));
this.add(new JButton("Button Three"));
this.add(new JButton("Button Four"));
this.add(new JButton("Button Five"));
}}

protected void swapPanel() {
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {

frame.remove(p);
frame.add(new PanelTwo());
frame.invalidate();
frame.revalidate();

}

});

}

public static void main (String[] args) {
Demo demo = new Demo();
demo.setup();
}
}

hoping it helped....



Related Topics



Leave a reply



Submit