I made a desktop application to handle the configuration of some web services, it works but the code is hard to maintain because all de logic view is in the same class (main class), so I decided to redo it and apply the MVC architecture and the React philosophy to split the complex app into simple and reusable components. I end up whit this:
My app has a JFrame
that has a main JPanel
, this main JPanel
has many other JPanel
s but the mains ones are centerJPanel
and SaveJPanel
for demonstration purposes. The centerJPanel has my Composite Component (blue rectangle), ContenedorSwtBtn.
My ContenedorSwtBtn consists of JPanel
, JLabel
for the title, and SwitchToggleBtn component, and I can have as many SwitchToggleBtn as I want because the idea is to add them dynamically.
My SwitchToggleBtn consists of a JPanel
, JLabel
for the name, and JToggleButton
.
The code (Sorry for the Spanish word) for MyComponent: SwitchToggleBtn:
public class SwitchToggleBtn extends JPanel
{
private JToggleButton SwtBtn;
private JLabel nombLogs;
private String Name;
public SwitchToggleBtn(String Nombre, boolean bandera)
{
super(new BorderLayout(10,10));
this.Name = Nombre;
this.setBackground(new java.awt.Color(255, 255, 255));
this.setBorder( new EmptyBorder( 5, 5, 5, 12));
this.setBorder(javax.swing.BorderFactory.createMatteBorder(1, 1, 1, 1, new java.awt.Color(153, 153, 153)));
this.nombLogs = new JLabel(Nombre);
this.nombLogs.setFont(new java.awt.Font("Segoe UI Symbol", 0, 14));
this.add(nombLogs, BorderLayout.WEST);
this.SwtBtn = new JToggleButton();
this.SwtBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/principal/icon/btnToggleOff.png"))); // NOI18N
this.SwtBtn.setBorder(null);
this.SwtBtn.setBorderPainted(false);
this.SwtBtn.setContentAreaFilled(false);
this.SwtBtn.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
this.SwtBtn.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/principal/icon/btnToggleOffDisabled.png"))); // NOI18N
this.SwtBtn.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/principal/icon/btnToggleOnDisable.png"))); // NOI18N
this.SwtBtn.setFocusPainted(false);
this.SwtBtn.setMaximumSize(new java.awt.Dimension(70, 34));
this.SwtBtn.setMinimumSize(new java.awt.Dimension(70, 34));
this.SwtBtn.setPreferredSize(new java.awt.Dimension(70, 34));
this.SwtBtn.setSelected(bandera);
this.SwtBtn.setName(Nombre);
IsSelected();
this.SwtBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
IsSelected();
}
});
this.add(SwtBtn, BorderLayout.EAST);
this.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
mouseclicked(evt);
}
});
}
private void IsSelected()
{
if (this.SwtBtn.isSelected())
this.SwtBtn.setIcon(new ImageIcon(getClass().getResource("/principal/icon/btnToggleOn.png")));
else
this.SwtBtn.setIcon(new ImageIcon(getClass().getResource("/principal/icon/btnToggleOff.png")));
}
}
The code (Sorry for the Spanish word) for ContenedorSwtBtn:
public class ContenedorSwtBtn extends JPanel
{
public ContenedorSwtBtn(String Nombre)
{
super();
this.setBackground(new java.awt.Color(255, 255, 255));
this.setBorder(javax.swing.BorderFactory.createMatteBorder(1, 1, 1, 1, new java.awt.Color(153, 153, 153)));
this.setToolTipText("");
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JLabel titulo = new JLabel();
titulo.setBackground(new java.awt.Color(0, 0, 0));
titulo.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
titulo.setForeground(new java.awt.Color(0, 51, 51));
titulo.setText(Nombre);
titulo.setAlignmentX(Component.CENTER_ALIGNMENT);
this.add(titulo);
}
public void AddComponent(String nombreLog, boolean bandera)
{
SwitchToggleBtn log = new SwitchToggleBtn(nombreLog, bandera);
this.add(log);
}
}
This is the final result :
when I clicked the JToggleButton inside of my SwichToggleBtn component it changes his state and changes the icon from off to on or vice versa.
And finally is matter of create the new component and add it into the main JPanel like this:
JPanel MainPanel= new JPanel();
MainPanel.setBackground(new java.awt.Color(255, 255, 255));
MainPanel.setEnabled(true);
MainPanel.setMaximumSize(new java.awt.Dimension(300, 280));
MainPanel.setMinimumSize(new java.awt.Dimension(300, 280));
MainPanel.setPreferredSize(new java.awt.Dimension(300, 280));
MainPanel.setVisible(true);
ContenedorSwtBtn myComponent= new ContenedorSwtBtn("SETTINGS");
myComponent.AddComponent("ONE", true);
myComponent.AddComponent("TWO", false);
myComponent.AddComponent("THREE",true);
MainPanel.add(myComponent);
When I clicked the JToggleButton and changes its state I want the exact component and its current state but from the main Jpanel or the center panel so that way I can "Save change" (red button from SaveJpanel) and implement some logic to save the configuration. How I pass the event from the child component to the parent's components or how from the parent's components can know when a child component changes its state. I read about creating a class that implements the actionlistener interface or implements the PropertyChangesListener interface but I don understand. thanks a lot for your help.
I am not sure what you are wanting to do given your question has anything to do with MVC (For an example of an MVC Swing app please look here), as far as I can tell all you really need is to bubble up events from your custom control so that you can register to receive these events in your main panel.
This can easily be done. Check my below example.
Essentially:
ButtonPanel
is its own "component" (it doesnt extendJPanel
as I dont think thats necessary, instead has a gettergetPanel()
for the component it creates).ButtonPanel
also implements anActionListener
for the buttons events it createsButtonPanel
has the ability to add anActionListener
viaaddActionListener
so others may register forActionEvent
s sent from theButtonPanel
.TestApp.java:
ButtonPanel.java: