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 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.
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 extend JPanel as I dont think thats necessary, instead has a getter getPanel() for the component it creates).
ButtonPanel also implements an ActionListener for the buttons events it creates
ButtonPanel has the ability to add an ActionListener via addActionListener so others may register for ActionEvents sent from the ButtonPanel.
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;
}
}
Related
I have a gui that has:
a label at the top
a JFrame at the bottom with 2 Buttons called left and right
a panel in center that is gridlayout with 2 JLabel to either display an image or change the back ground color. (currently the background color is set to black for both jLabels).
*what I would like to happen.
When you click on button "left" the image appears on lblPicture1 and lblPicture2 has a black background and no image. and vise versa for the right button. and when you click on the left again, it repeats this cycle.
I accomplish that however, when i click the left and right button I just have two images and neither one has a black background.
I belive this is due to the image not resetting.
Can you direct me to the right place on how I can get this to work?
Thank you
package gui;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import javax.swing.JButton;
import java.awt.GridLayout;
import javax.swing.ImageIcon;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ExampleGUI extends JFrame {
private JPanel contentPane;
private JLabel lblPicture1;
private JLabel lblPicture2;
private int change;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ExampleGUI frame = new ExampleGUI();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ExampleGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JLabel lblExampleGui = new JLabel("Example GUI");
lblExampleGui.setBorder(new EmptyBorder(8, 0, 8, 0));
lblExampleGui.setFont(new Font("Lucida Grande", Font.PLAIN, 24));
lblExampleGui.setHorizontalAlignment(SwingConstants.CENTER);
contentPane.add(lblExampleGui, BorderLayout.NORTH);
JPanel panelButton = createPanelButton();
contentPane.add(panelButton, BorderLayout.SOUTH);
JButton btnLeft = createBtnLeft();
panelButton.add(btnLeft);
JButton btnRight = createBtnRight();
panelButton.add(btnRight);
JPanel panelCenter = createPanelCenter();
contentPane.add(panelCenter, BorderLayout.CENTER);
JLabel lblPicture1 = createLblPicture1();
panelCenter.add(lblPicture1);
JLabel lblPicture2 = createPicture2();
panelCenter.add(lblPicture2);
}
public JLabel createPicture2() {
lblPicture2 = new JLabel();
lblPicture2.setOpaque(true);
lblPicture2.setBackground(Color.BLACK);
return lblPicture2;
}
public JLabel createLblPicture1() {
lblPicture1 = new JLabel();
lblPicture1.setOpaque(true);
lblPicture1.setBackground(Color.BLACK);
//lblPicture1.setIcon(new ImageIcon(ExampleGUI.class.getResource("/gui/schlange.gif")));
return lblPicture1;
}
public JPanel createPanelCenter() {
JPanel panelCenter = new JPanel();
panelCenter.setLayout(new GridLayout(0, 2, 8, 0));
return panelCenter;
}
public JButton createBtnRight() {
JButton btnRight = new JButton("right");
btnRight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//TODO
lblPicture1.setBackground(Color.BLACK);
lblPicture2.setIcon(new ImageIcon(ExampleGUI.class.getResource("/gui/schlange.gif")));
}
});
btnRight.setFont(new Font("Lucida Grande", Font.PLAIN, 14));
return btnRight;
}
public JButton createBtnLeft() {
JButton btnLeft = new JButton("left");
btnLeft.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//TODO
lblPicture2.setBackground(Color.BLACK);
lblPicture1.setIcon(new ImageIcon(ExampleGUI.class.getResource("/gui/schlange.gif")));
}
});
btnLeft.setFont(new Font("Lucida Grande", Font.PLAIN, 14));
return btnLeft;
}
public JPanel createPanelButton() {
JPanel panelButton = new JPanel();
return panelButton;
}
}
The background is painted beneath the icon, so if the icon is not reset, then it will continue to be displayed.
You can simply set the icon property by passing it null, for example
public JButton createBtnLeft() {
JButton btnLeft = new JButton("left");
btnLeft.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//TODO
lblPicture2.setIcon(null);
lblPicture2.setBackground(Color.BLACK);
lblPicture1.setIcon(new ImageIcon(ExampleGUI.class.getResource("/gui/schlange.gif")));
}
});
btnLeft.setFont(new Font("Lucida Grande", Font.PLAIN, 14));
return btnLeft;
}
So I started to go into OOP and also started to learn about swing library but I have trouble. When I try to remove all of the JFrame components it doesnt work. What I want to do is when the user clicks a button I have to remove all the JFrame components and add new ones but it doesn't work despite that I used removeAll() repait(), revalidate() etc. Here is my code for the BankApp class:
import javax.swing.*;
public class BankApp{
public static void main(String[] args) {
BankGUI object1;
object1 = new BankGUI();
object1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
object1.setSize(700, 500);
object1.setLocationRelativeTo(null);
object1.setResizable(false);
object1.setVisible(true);
}
}
Here is the BankGUI:
import javax.swing.*;
import java.awt.*;
public class BankGUI extends JFrame{
private JButton CreateAccount;
private JButton LoginAccount;
private JButton Exit;
private JButton AboutButton;
private JButton ExitButton;
private JLabel IntroText;
public BankGUI(){
super("Banking App");
createMainMenu();
}
public void createMainMenu(){
add(Box.createRigidArea(new Dimension(0,40)));
IntroText = new JLabel("Banking Application");
IntroText.setMaximumSize(new Dimension(280,60));
IntroText.setFont(new Font("Serif", Font.PLAIN, 34));
IntroText.setAlignmentX(CENTER_ALIGNMENT);
add(IntroText);
add(Box.createRigidArea(new Dimension(0,40)));
setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
CreateAccount = new JButton("Register");
CreateAccount.setMaximumSize(new Dimension(200,50));
CreateAccount.setFont(new Font("Serif", Font.PLAIN, 24));
CreateAccount.setAlignmentX(CENTER_ALIGNMENT);
CreateAccount.setFocusable(false);
add(CreateAccount);
add(Box.createRigidArea(new Dimension(0,20)));
LoginAccount = new JButton("Login");
LoginAccount.setMaximumSize(new Dimension(200,50));
LoginAccount.setFont(new Font("Serif", Font.PLAIN, 24));
LoginAccount.setAlignmentX(CENTER_ALIGNMENT);
LoginAccount.setFocusable(false);
add(LoginAccount);
add(Box.createRigidArea(new Dimension(0,20)));
AboutButton = new JButton("About");
AboutButton.setMaximumSize(new Dimension(200,50));
AboutButton.setFont(new Font("Serif", Font.PLAIN, 24));
AboutButton.setAlignmentX(CENTER_ALIGNMENT);
AboutButton.setFocusable(false);
add(AboutButton);
add(Box.createRigidArea(new Dimension(0,20)));
ExitButton = new JButton("Exit");
ExitButton.setMaximumSize(new Dimension(200,50));
ExitButton.setFont(new Font("Serif", Font.PLAIN, 24));
ExitButton.setAlignmentX(CENTER_ALIGNMENT);
ExitButton.setFocusable(false);
add(ExitButton);
ButtonListener actionListener = new ButtonListener(CreateAccount, LoginAccount, AboutButton, ExitButton);
CreateAccount.addActionListener(actionListener);
LoginAccount.addActionListener(actionListener);
AboutButton.addActionListener(actionListener);
ExitButton.addActionListener(actionListener);
}
}
And here is my ButtonListener Class:
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ButtonListener implements ActionListener{
private JButton CreateAccount;
private JButton LoginAccount;
private JButton AboutButton;
private JButton ExitButton;
public ButtonListener(JButton button1,JButton button2,JButton button3,JButton button4){
CreateAccount = button1;
LoginAccount = button2;
AboutButton = button3;
ExitButton = button4;
}
#Override
public void actionPerformed(ActionEvent e) {
BankGUI bankgui = new BankGUI();
if(e.getSource() == CreateAccount){
System.out.println("This prints out");
}else if(e.getSource() == ExitButton){
bankgui.getContentPane().removeAll();
bankgui.removeAll();
bankgui.validate();
bankgui.repaint();
System.out.println("Code reaches here but it doesnt clear the screen");
}
}
}
When I try to do it nothing happens despite that I revalidate and repaint I'm not sure why.I just want to clear the JFrame. I'm 100% sure that the code reaches the methods but for some reason they don't work.
Maybe its obvious mistake but I'm not seeing it.
Any help would be appreciated.
In your actionPerformed method, you are creating another instance of BankGUI, this is, in no way, connected to the instance which is been displayed to the user...
#Override
public void actionPerformed(ActionEvent e) {
BankGUI bankgui = new BankGUI();
//...
}
There are a few ways you "might" correct this, most of them aren't pretty.
You could pass a reference of BankGUI to the ButtonListener along with the buttons. I don't like this idea, as it provides the means for ButtonListener to start doing things to BankGUI it really has no responsibility for doing.
You could use SwingUtilities.getWindowAncestor, passing a reference of the button which was triggered, to get a reference to the window. This has the sam problem as the previous idea, but it also makes assumptions about the structure of the UI, which, ButtonListener shouldn't care about.
In both cases, this couples ButtonListener to BankGUI.
A better solution would be to provide some kind of "navigation manager". The ButtonListener would take a reference of it and when one of the buttons is actioned, would notify the "navigation manager", asking it to perform the actual task.
This de-couples the ButtonListener from the implementation of the UI.
This is all about concepts of "isolation of responsibility", "code reusability" and "model-view-controller"
Overall, a simpler and more practical solution would be to use a CardLayout, which will further de-couple the UI and make it easier to isolate functionality to their own classes/components and allow the primary UI to switch between them
import java.awt.CardLayout;
import static java.awt.Component.CENTER_ALIGNMENT;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
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 JavaApplication101 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
BankGUI object1;
object1 = new BankGUI();
object1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
object1.pack();
object1.setLocationRelativeTo(null);
object1.setVisible(true);
}
});
}
public interface BankNavigationController {
public void setView(String command);
}
public static class CardLayoutBankNavigationController implements BankNavigationController {
private Container parent;
private CardLayout layout;
public CardLayoutBankNavigationController(Container parent, CardLayout layout) {
this.parent = parent;
this.layout = layout;
}
#Override
public void setView(String command) {
layout.show(parent, command);
}
}
public static class BankGUI extends JFrame {
private CardLayoutBankNavigationController controller;
public BankGUI() {
super("Banking App");
CardLayout layout = new CardLayout();
setLayout(layout);
controller = new CardLayoutBankNavigationController(getContentPane(), layout);
add("Main Menu", createMainMenu());
add("Register", otherView("Register"));
add("Login", otherView("Login"));
add("About", otherView("About"));
add("Exit", otherView("Exit"));
controller.setView("Main Menu");
}
public JPanel otherView(String named) {
JPanel view = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
view.add(new JLabel(named), gbc);
JButton mainMenu = new JButton("Main Menu");
view.add(mainMenu, gbc);
ButtonListener actionListener = new ButtonListener(controller);
mainMenu.addActionListener(actionListener);
return view;
}
public JPanel createMainMenu() {
JPanel menu = new JPanel();
menu.setLayout(new BoxLayout(menu, BoxLayout.PAGE_AXIS));
menu.add(Box.createRigidArea(new Dimension(0, 40)));
JLabel IntroText = new JLabel("Banking Application");
IntroText.setMaximumSize(new Dimension(280, 60));
IntroText.setFont(new Font("Serif", Font.PLAIN, 34));
IntroText.setAlignmentX(CENTER_ALIGNMENT);
menu.add(IntroText);
menu.add(Box.createRigidArea(new Dimension(0, 40)));
JButton CreateAccount = new JButton("Register");
CreateAccount.setMaximumSize(new Dimension(200, 50));
CreateAccount.setFont(new Font("Serif", Font.PLAIN, 24));
CreateAccount.setAlignmentX(CENTER_ALIGNMENT);
CreateAccount.setFocusable(false);
menu.add(CreateAccount);
menu.add(Box.createRigidArea(new Dimension(0, 20)));
JButton LoginAccount = new JButton("Login");
LoginAccount.setMaximumSize(new Dimension(200, 50));
LoginAccount.setFont(new Font("Serif", Font.PLAIN, 24));
LoginAccount.setAlignmentX(CENTER_ALIGNMENT);
LoginAccount.setFocusable(false);
menu.add(LoginAccount);
menu.add(Box.createRigidArea(new Dimension(0, 20)));
JButton AboutButton = new JButton("About");
AboutButton.setMaximumSize(new Dimension(200, 50));
AboutButton.setFont(new Font("Serif", Font.PLAIN, 24));
AboutButton.setAlignmentX(CENTER_ALIGNMENT);
AboutButton.setFocusable(false);
menu.add(AboutButton);
menu.add(Box.createRigidArea(new Dimension(0, 20)));
JButton ExitButton = new JButton("Exit");
ExitButton.setMaximumSize(new Dimension(200, 50));
ExitButton.setFont(new Font("Serif", Font.PLAIN, 24));
ExitButton.setAlignmentX(CENTER_ALIGNMENT);
ExitButton.setFocusable(false);
menu.add(ExitButton);
ButtonListener actionListener = new ButtonListener(controller);
CreateAccount.addActionListener(actionListener);
LoginAccount.addActionListener(actionListener);
AboutButton.addActionListener(actionListener);
ExitButton.addActionListener(actionListener);
return menu;
}
}
public static class ButtonListener implements ActionListener {
private BankNavigationController controller;
public ButtonListener(BankNavigationController controller) {
this.controller = controller;
}
#Override
public void actionPerformed(ActionEvent e) {
controller.setView(e.getActionCommand());
}
}
}
I am having problems with figuring how to use event handlers in order to remove and repaint between 2 panels.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PanelSwitcherView extends JFrame {
private JPanel panel1, panel2;
public PanelSwitcherView() {
super("Panel Switching Test");
Font font = new Font("SansSerif", Font.BOLD, 30);
panel1 = new JPanel();
panel1.setLayout(new GridLayout(2, 2, 5, 5));
font = new Font("Serif", Font.ITALIC, 30);
panel2 = new JPanel();
panel2.setLayout(new BorderLayout());
Here I decided to add a test ActionListener but am unsure if correctly used
font = new Font("Monospaced", Font.BOLD + Font.ITALIC, 30);
JButton button = new JButton("Switch Panels");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.print("Test");
PanelSwitcherModel.switchPanel(); // used to make value of whichpanel 1 or 2
}
});
button.setFont(font);
add(button, BorderLayout.NORTH);
add(panel1, BorderLayout.CENTER);
}
Not completely sure how to use this either
public void displayPanel(int whichPanel) {
remove(panel1);
remove(panel2);
if (whichPanel == 1) {
System.out.println("Should display panel1");
add(panel1, BorderLayout.CENTER);
} else {
System.out.println("Should display panel2");
add(panel2, BorderLayout.CENTER);
}
validate();
repaint();
}
My Controller (class below)
public void register(PanelSwitcherController controller) {
}
Problem lies mainly here, I am a newbie here, do I move my ActionListener here somehow? How do I access other classes in order to change the number from 1 to 2 for my panel options?
import java.awt.event.*;
public class PanelSwitcherController implements ActionListener{
public PanelSwitcherController(PanelSwitcherView view,
PanelSwitcherModel model) {
}
public void actionPerformed(ActionEvent e) {
}
}
I am currently trying to make a little app using a jframe that has multiple jpanels. I have a couple questions about this.
There has to be a cleaner way of making an app with 16 different panels than having it all inside one class. What are some other options.
Currently I only have 3 panels. I haven't gone any further because 2 of the panels aren't reflecting my changes. They are the two panels I call using
removeAll();
add();
revalidate();
repaint();
What would be causing the other panels I am calling to be blank?
Here is a look at what I have, any advice would be great. Thanks
public class Jframetest extends JFrame {
private JPanel Home;
private JPanel masslog;
private JPanel DEH;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Jframetest frame = new Jframetest();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Jframetest() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setBounds(100, 100, 618, 373);
Home = new JPanel();
masslog = new JPanel();
DEH = new JPanel();
Home.setBackground(new Color(255, 250, 250));
Home.setBorder(new LineBorder(Color.DARK_GRAY, 1, true));
DEH.setBackground(new Color(255, 250, 250));
DEH.setBorder(new LineBorder(Color.DARK_GRAY, 1, true));
masslog.setBackground(new Color(255, 250, 250));
masslog.setBorder(new LineBorder(Color.DARK_GRAY, 1, true));
setContentPane(Home);
Home.setLayout(null);
JButton dehbutton = new JButton("Sign in");
dehbutton.setFont(new Font("Tahoma", Font.PLAIN, 14));
dehbutton.setForeground(new Color(0, 0, 0));
dehbutton.setBackground(UIManager.getColor("Menu.selectionBackground"));
DEH.add(dehbutton);
JButton btnNewButton = new JButton("Data Entry login");
btnNewButton.setFont(new Font("Tahoma", Font.PLAIN, 14));
btnNewButton.setForeground(new Color(0, 0, 0));
btnNewButton.setBackground(UIManager.getColor("Menu.selectionBackground"));
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Home.removeAll();
Home.add(DEH);
Home.revalidate();
Home.repaint();
// JOptionPane.showMessageDialog(null, "Username/Password incorrect");
}
});
btnNewButton.setBounds(44, 214, 204, 61);
Home.add(btnNewButton);
final JButton button = new JButton("Manager and Associate login");
button.setFont(new Font("Tahoma", Font.PLAIN, 14));
button.setBackground(UIManager.getColor("EditorPane.selectionBackground"));
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Home.removeAll();
Home.add(masslog);
Home.revalidate();
Home.repaint();
}
});
button.setBounds(340, 214, 204, 61);
Home.add(button);
JTextPane txtpnEmployeeLogin = new JTextPane();
txtpnEmployeeLogin.setForeground(Color.DARK_GRAY);
txtpnEmployeeLogin.setBackground(Color.WHITE);
txtpnEmployeeLogin.setFont(new Font("Tahoma", Font.PLAIN, 34));
txtpnEmployeeLogin.setText("Employee Login");
txtpnEmployeeLogin.setBounds(181, 123, 260, 52);
Home.add(txtpnEmployeeLogin);
JLabel lblNewLabel = new JLabel("New label");
lblNewLabel.setIcon(new ImageIcon("C:\\Users\\Will and April\\Downloads\\your-logo-here.jpg"));
lblNewLabel.setBounds(427, 11, 165, 67);
Home.add(lblNewLabel);
}
}
Your mistake is using a null layout, revalidate, invalidate and validate will no longer have any significant meaning, because they are related to supporting the layout management API.
Because you've removed the layout manager, you panels no longer have anything to tell them what size or location that they should appear at, meaning when you add a new component, it has a size of 0x0 and position of 0x0
Update with example
There are many reasons why you should take advantage of the layout manager API, including automatic handling of differences between how fonts are rendered on different systems, dynamic and resizable layouts, differences in screen resolution and DPI to name a few.
It will also encourage you to separate your UI into areas of responsibility instead of trying to dump your entire UI code into a single class (yes, I've seen this done, yes, I've spent most of my career cleaning up after people who do this...)
This example makes use of CardLayout and GridBagLayout, but you should take the time to become farmiluar with the some of the others avaiable in the default JDK
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class FrameTest extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
FrameTest frame = new FrameTest();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public FrameTest() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final CardLayout layout = new CardLayout();
setLayout(layout);
LoginPane loginPane = new LoginPane();
add(loginPane, "login");
add(new NewLoginPane(), "newLogin");
add(new ManagerLoginPane(), "managerLogin");
loginPane.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
System.out.println(command);
if ("new".equals(command)) {
layout.show(getContentPane(), "newLogin");
} else if ("manager".equals(command)) {
layout.show(getContentPane(), "managerLogin");
}
}
});
layout.show(getContentPane(), "layout");
pack();
setLocationRelativeTo(null);
}
public class LoginPane extends JPanel {
private JTextField userName;
private JButton newButton;
private JButton managerButton;
public LoginPane() {
setBorder(new EmptyBorder(20, 20, 20, 20));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 2;
gbc.weightx = 1;
gbc.insets = new Insets(10, 10, 10, 10);
userName = new JTextField(10);
userName.setFont(new Font("Tahoma", Font.PLAIN, 34));
add(userName, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.weightx = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
newButton = new JButton("Sign in");
newButton.setActionCommand("new");
managerButton = new JButton("Manager and Associate login");
managerButton.setActionCommand("manager");
add(newButton, gbc);
gbc.gridx++;
add(managerButton, gbc);
}
public void addActionListener(ActionListener listener) {
newButton.addActionListener(listener);
managerButton.addActionListener(listener);
}
public void remveActionListener(ActionListener listener) {
newButton.removeActionListener(listener);
managerButton.removeActionListener(listener);
}
public String getUserName() {
return userName.getText();
}
}
public class NewLoginPane extends JPanel {
public NewLoginPane() {
setLayout(new GridBagLayout());
add(new JLabel("New Login"));
}
}
public class ManagerLoginPane extends JPanel {
public ManagerLoginPane() {
setLayout(new GridBagLayout());
add(new JLabel("Welcome overlord"));
}
}
}
There has to be a cleaner way of making an app with 16 different panels than having it all inside one class. What are some other options.
You are free to create and use as many classes as need be. So if a JPanel holds a complex bit of GUI that you may wish to re-use elsewhere, or that has its own specific and separate functionality, by all means put the code in its own class.
Currently I only have 3 panels. I haven't gone any further because 2 of the panels aren't reflecting my changes. They are the two panels I call using
removeAll();
add();
revalidate();
repaint();
Smells like you're trying to re-invent the CardLayout. Why re-invent it when you can just use it?
And yes, everything MadProgrammer says about null layout is true. You should avoid using it.
Oh, the CardLayout may work for you. I thought about using a JTabbedPane. Here are my thoughts in a code example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class TabbedPaneDemo extends JFrame {
public TabbedPaneDemo() {
// set the layout of the frame to all the addition of all components
setLayout(new FlowLayout());
// create a tabbed pane
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.setPreferredSize(new Dimension(500,500));
add(tabbedPane);
// create three panels to be added to this frame
JPanel redPanel = new JPanel();
JPanel greenPanel = new JPanel();
JPanel bluePanel = new JPanel();
// set the colors of the panels
redPanel.setBackground(Color.RED);
greenPanel.setBackground(Color.GREEN);
bluePanel.setBackground(Color.BLUE);
// set the preferred size of each panel
redPanel.setPreferredSize(new Dimension(150,150));
greenPanel.setPreferredSize(new Dimension(150,150));
bluePanel.setPreferredSize(new Dimension(150,150));
// add the panels to the tabbed pane
tabbedPane.addTab("Red Panel", redPanel);
tabbedPane.addTab("Green Panel", greenPanel);
tabbedPane.addTab("Blue Panel", bluePanel);
// finish initializing this window
setSize(500,500); // size the window to fit its components (i.e. panels in this case)
setLocationRelativeTo(null); // center this window
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // exit application when this window is closed
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TabbedPaneDemo().setVisible(true);
}
});
}
}
And for your other question about having 16 panels in one class:
You can have panels within panel to organize things.
You can subclass JPanel and put the subclasses in their own .java files.
You can send me an email if I can be of further assistance. kaydell#yahoo.com (I like helping people with their programming and I learn from it too.)
this is the first time I've had a look at JFrames and JPannels and I've come a little stuck.
What I am trying to do is this, I wish to have an starting screen then based on the users button choice it swaps to another screen. To start I have only 2 screens, however once I've moved on there will be multiple screens. I've looked at CardLayout and while that is good it's not the way I wish to go I want to be able to do this first. Here is what I have.
Main.java
import java.awt.BorderLayout;
public class Main extends JFrame {
private JPanel contentPane;
protected boolean someCondition = false;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
if( someCondition == false ){
showTest();
someCondition = test.needToReg();
}else{
showTest2();
}
}
private void showTest(){
contentPane.removeAll();
contentPane.add(new test());
setContentPane(contentPane);
revalidate();
repaint();
}
private void showTest2(){
contentPane.removeAll();
contentPane.add(new test2());
setContentPane(contentPane);
revalidate();
repaint();
}
}
test.java
import javax.swing.JPanel;
public class test extends JPanel {
private JTextField textField;
protected static boolean toReg = false;
/**
* Create the panel.
*/
public test() {
setLayout(null);
JButton btnNewButton = new JButton("New button");
btnNewButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse Clicked");
System.out.println("Before " + toReg);
toReg = true;
System.out.println("After " + toReg);
}
});
btnNewButton.setBounds(188, 166, 89, 23);
add(btnNewButton);
textField = new JTextField();
textField.setBounds(150, 135, 86, 20);
add(textField);
textField.setColumns(10);
JRadioButton rdbtnNewRadioButton = new JRadioButton("New radio button");
rdbtnNewRadioButton.setBounds(6, 166, 109, 23);
add(rdbtnNewRadioButton);
}
public static boolean needToReg(){
return toReg;
}
}
test2.java
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
public class test2 extends JPanel {
/**
* Create the panel.
*/
public test2() {
setLayout(null);
JButton btnNewButton = new JButton("New button");
btnNewButton.setBounds(56, 59, 89, 23);
add(btnNewButton);
JLabel lblNewLabel = new JLabel("New label");
lblNewLabel.setBounds(122, 165, 46, 14);
add(lblNewLabel);
}
}
Running the program with the outputs I included I get this.
Mouse Clicked
Before false
After true
Mouse Clicked
Before true
After true
Mouse Clicked
Before true
After true
Mouse Clicked
Before true
After true
Mouse Clicked
Before true
After true
I hope it's clear what I am trying to do and I hope you can lend a hand with this. Thanks
Try this out
On clicking the screenSwapper button in the main frame a new Panel is added to the main frame that can have multiple components I have added one button only
On second click this panel is removed and second panel is added to the main frame and previous one is removed.
The swapping is carried as you click the button continuously
You may use two singletons if you want to preserve once created panel in case of MyPanel1 and MyPanel2
You may add more components on each panel and test.
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test extends JFrame {
public boolean switcher;
public JPanel currentPanel;
public JPanel panel1;
public JPanel panel2;
public Test() {
this.switcher = false;
this.currentPanel = null;
this.setSize(200, 200);
panel1 = new JPanel();
JButton screenSwapper = new JButton("Screen Swapper");
panel1.add(screenSwapper);
panel2 = new JPanel();
this.getContentPane().setLayout(new GridLayout(2, 2));
this.getContentPane().add(panel1);
this.getContentPane().add(panel2);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
screenSwapper.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if (switcher == false) {
currentPanel = new MyPanel1();
switcher = true;
if (panel2.getComponentCount() != 0) {
panel2.removeAll();
}
} else {
switcher = false;
currentPanel = new MyPanel2();
if (panel2.getComponentCount() != 0) {
panel2.removeAll();
}
}
panel2.add(currentPanel);
panel2.repaint();
panel2.revalidate();
}
});
}
public static void main(String[] args) {
Test t = new Test();
}
}
This is the first panel
import java.awt.BorderLayout;
import java.awt.Button;
import javax.swing.JPanel;
public class MyPanel1 extends JPanel{
public MyPanel1() {
// TODO Auto-generated constructor stub
this.setLayout(new BorderLayout());
this.add(new Button("Button1"));
}
}
This is the second Panel
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
public class MyPanel2 extends JPanel {
public MyPanel2() {
this.setLayout(new BorderLayout());
this.add(new JButton("button2"));
}
}