1

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: APP

My app has a JFrame that has a main JPanel, this main JPanel has many other JPanels 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.

ContenedorSwtBtn

My SwitchToggleBtn consists of a JPanel, JLabel for the name, and JToggleButton.

SwitchToggleBtn

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 :

Final

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.

David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • 1
    Please consider simplifying the code and the problem to its bare essentials, without any code/components that are unrelated to the *problem at hand*. This will involve considerable work, but would be well worth it for you and for us. Please have a look at the [mre] link for more on this topic. – Hovercraft Full Of Eels Dec 06 '20 at 02:27
  • Also note that all Java classes that inherit from `java.awt.Component`, meaning *all* AWT and Swing components/containers/frames, and whatnot, have property change support wired into the class automatically. All you need to do is create your listeners and attach them to your components any way you see fit. – Hovercraft Full Of Eels Dec 06 '20 at 02:58
  • This is the very essential, just I have a composite component and I want to handle the event in the parents component or in the other hands get data from the Child to the parents – ADAN MENDEZ Dec 06 '20 at 02:59
  • Thats is my problem i dont Know how to do it the way I want in order to achive the behavior thet i looking for – ADAN MENDEZ Dec 06 '20 at 03:01
  • TL;DR; you are more likely to get help by posting mre as suggested. Post a short code that demonstrates the problem and not the entire app. – c0der Dec 06 '20 at 05:00
  • This is a short code, how to handle the event of the child inner component in a parents component? – ADAN MENDEZ Dec 06 '20 at 05:23
  • Yes, your code is short, but is also code that we cannot compile, that has no main method and so code that we cannot run, test, etc... Please *read* the [mre] link to better understand what we're requesting. – Hovercraft Full Of Eels Dec 06 '20 at 12:52

1 Answers1

1

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:

  1. ButtonPanel is its own "component" (it doesnt extend JPanel as I dont think thats necessary, instead has a getter getPanel() for the component it creates).
  2. ButtonPanel also implements an ActionListener for the buttons events it creates
  3. ButtonPanel has the ability to add an ActionListener via addActionListener so others may register for ActionEvents sent from the ButtonPanel.

enter image description here

TestApp.java:

import java.awt.event.ActionEvent;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

public class TestApp {

    public TestApp() {
        createAndShowGUI();

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(TestApp::new);
    }

    private void createAndShowGUI() {
        JFrame frame = new JFrame("TestApp");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setBorder(new EmptyBorder(20, 20, 20, 20));
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        ButtonPanel buttonPanel = new ButtonPanel();
       // here we register for events created from the button panel as buttons are pressed
        buttonPanel.addActionListener((ActionEvent e) -> {
            JToggleButton button = (JToggleButton) e.getSource();
            switch (e.getActionCommand()) { // which button was pressed?
                case "button1":
                    JOptionPane.showMessageDialog(panel, "Button 1 pressed and isSelected is: " + button.isSelected());
                    break;
                case "button2":
                    JOptionPane.showMessageDialog(panel, "Button 2 pressed and isSelected is:" + button.isSelected());
                    break;
            }
        });
        panel.add(buttonPanel.getPanel());

        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }
}

ButtonPanel.java:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.JToggleButton;

public class ButtonPanel implements ActionListener {

    private JPanel panel;
    private JToggleButton button1;
    private JToggleButton button2;
    private ActionListener actionListener;

    public ButtonPanel() {
        initView();
    }

    private void initView() {
        panel = new JPanel();
        button1 = new JToggleButton("Button 1 (OFF)");
        button2 = new JToggleButton("Button 2 (OFF)");
        button1.addActionListener(this);
        button2.addActionListener(this);
        panel.add(button1);
        panel.add(button2);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JToggleButton button = ((JToggleButton) e.getSource());
        button.setText(button.getText().substring(0, button.getText().indexOf("(")) + "(" + (button.isSelected() ? "ON" : "OFF") + ")");

        if (e.getSource() == button1) {
            if (actionListener != null) {
                actionListener.actionPerformed(new ActionEvent(e.getSource(), ActionEvent.ACTION_PERFORMED, "button1"));// we send button1 as a command so we know what button was pressed
            }
        } else if (e.getSource() == button2) {
            if (actionListener != null) {
                actionListener.actionPerformed(new ActionEvent(e.getSource(), ActionEvent.ACTION_PERFORMED, "button2"));// we send button2 as a command so we know what button was pressed
            }
        }
    }

    public JPanel getPanel() {
        return panel;
    }

    void addActionListener(ActionListener actionListener) {
        this.actionListener = actionListener;
    }
}
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138