I've got class 'Frame' which extends JFrame and separetad JPanels: MainMenu and SinglePanel
I am using CardLayout, but I've got problem when switching back to panels using buttonSingle and powrot buttons. So my question is how can I change/swap between cards using these buttons?
My Frame class:
public class Frame extends JFrame{
CardLayout cl = new CardLayout();
final MainMenu menuPanel = new MainMenu();
final SinglePanel singlePanel = new SinglePanel();
public Frame(){
setLayout(cl);
add(menuPanel,"menu");
add(singlePanel,"single");
setSize(200, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
setEnabled(true);
swapView("menu");
}
public void swapView(String view){
cl.show(getContentPane(),view);
}
}
my MainMenu class:
public class MainMenu extends JPanel{
public MainMenu(){
setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
add(Box.createVerticalGlue());
JButton buttonSingle = new JButton("Single");
buttonSingle.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonSingle.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
}
});
add(buttonSingle);
add(Box.createVerticalGlue());
JButton buttonMulti = new JButton("Multiplayer");
buttonMulti.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonMulti.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
});
add(buttonMulti);
add(Box.createVerticalGlue());
JButton buttonExit = new JButton("Wyjście");
buttonExit.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonExit.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
add(buttonExit);
add(Box.createVerticalGlue());
}
}
my SinglePanel class
public class SinglePanel extends JPanel{
SinglePanel(){
setLayout(new FlowLayout());
JButton powrot = new JButton("Wróć do menu");
powrot.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
}
});
add(powrot);
}
}
Main class:
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
/*MainMenu mM = new MainMenu();*/
Frame f = new Frame();
}
}
You need a reference to the CardLayout of the JFrame inside your panel classes. What you can do is pass the Frame to the JPanel classes as reference, then you can use the CardLayout of the Frame in those classes to show or next etc. Something like
public class MainMenu {
private CardLayout layout;
private Frame frame;
public MainMenu(final Frame frame) {
this.frame = frame;
this.layout = (CardLayout)frame.getLayout();
JButton buttonSingle = new JButton("Single");
buttonSingle.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonSingle.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
layout.show(frame, "single");
}
});
}
}
When you create the MainPanel, you need to pass Frame.this to it, referencing the current Frame
MainMenu menuPanel = new MainMenu(Frame.this);
EDIT
I just noticed your swapView method. So instead of use the CardLayout directly in the panel class, you can actually just call swapView in the actionPerformed
frame.swapView("single");
Or better yet, as to not expose the Frame class, you can have the Frame class implement an interface say SwapInterface that has a method swapView you need to override. And pass the SwapInterface to the panel classes. Something like
public interface SwapInterface {
public void swapView(String view);
}
public Frame extends JFrame implements SwapInterface {
MainMenu mainPanel = new MainMenu(Frame.this);
....
#Override
public void swapView(String view) {
cl.show(getContentPane(), view);
}
}
public class MainMenu extends JPanel {
private SwapInterface swap;
public MainMenu(SwapInterface swap) {
this.swap = swap;
...
public void actionPerfomed(ActionEvent e) {
swap.swapView("single");
}
}
}
Side Note
As HovercraftFullOfEels pointed out in his comment, you should make use of String contants for the String card values so there's no mistakes. Something like
private static final String SINGLE_CARD = "single";
Then in places where you use "single", use SINGLE_CARD instead
Related
I'm trying to change button action in a subclass because the form is pretty much exactly the except one asks for an ID. What I i tried doing was making a ActionListener object and instantiating it to an object of an anonymous class like so:
class ParentClass extends JPanel{
JButton button;
ActionListener buttonAction;
ParentClass{
button = new JButton("Parent Action");
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the parent class");
}
};
button.add(buttonAction);
add(button);
}
}
class ChildClass extends ParentClass{
JButton button;
ActionListener buttonAction;
ChildClass{
super();
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the child class");
}
};
}
}
public static void main(String[] args){
JFrame frame = new JFrame;
frame.add(new ChildClass());
frame.setSize(600, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
I was trying to use this method but the actionPerformed of buttonAction is never called. How can I make the button action different for the parent class and the subclass?
You can let parent class implement ActionListener, then use button.addActionListener(this) in order to add the action to button. Then in the subclass #Override actionPerformed method:
class ParentClass extends JPanel implements ActionListener
{
ParentClass()
{
JButton button = new JButton("something");
button.addActionListener(this);
add(button);
}
#Override
public void actionPerformed(ActionEvent event)
{
System.out.println("I am the parent.");
}
}
class SubClass extends ParentClass
{
SubClass()
{
super();//initialize button
}
#Override
public void actionPerformed(ActionEvent event)
{
System.out.println("I am the child.");
}
}
Another way is to add the ActionListener and inside it, only call a method. Something like buttonPressed. Then in subclass #Override buttonPressed method.
A complete example:
public class Test extends JFrame {
public Test() {
super("test");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new GridLayout(2, 1));
add(new ParentPanel());
add(new ChildPanel());
pack();
setLocationByPlatform(true);
}
private class ParentPanel extends JPanel implements ActionListener {
public ParentPanel() {
super(new BorderLayout());
JButton button = new JButton("My Class:" + getClass());
button.addActionListener(this);
add(button);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Parent");
}
}
private class ChildPanel extends ParentPanel {
public ChildPanel() {
super();
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Child");
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Test().setVisible(true));
}
}
I the method I posted works. The issue is if you don't remove and add the button to the subclass it doesn't change the action that will run
class ParentClass extends JPanel{
JButton button;
ActionListener buttonAction;
ParentClass{
button = new JButton("Parent Action");
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the parent class");
}
};
button.add(buttonAction);
add(button);
}
}
So in the subclass what you would do is this:
class ChildClass extends ParentClass{
JButton button;
ActionListener buttonAction;
ChildClass{
super();
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the child class");
}
};
button.removeActionListener(button.getActionListeners()[0]);
button.addActionListener(buttonAction);
}
}
I, however, do not know why but would like an explanation as to why buttonAction had to be re-registered.
I have a class whitch extends JPanel:
public class ButtonPanel extends JPanel {
private label;
public ButtonPanel() {
label=new JLabel("waiting for click");
add(label);
}
public void setButtonText() {
label.setText("just clicked");
}
}
I have several instances of that class which is added to JFrame. I want to create one instanse of MouseAdapter class and then add them as a mouse listener to all of the ButtonPanel components on my JFrame. I meen:
ButtonPanel butt1 = new ButtonPanel();
ButtonPanel butt2 = new ButtonPanel();
ButtonPanel butt3 = new ButtonPanel();
//... here goes code which add ButtonPanels to JFrame
MouseAdapterMod mam = new MouseAdapterMod();
butt1.addMouseListener(mam);
butt2.addMouseListener(mam);
butt3.addMouseListener(mam);
The MouseAdapterMod class I want to be separate from the other and locate in it's own package. It should looks like this:
public class MouseAdapterMod extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
//here goes the code of calling setButtonText method of ButtonPanel component on which the event had occurred
}
}
So the problem is that I don't know how to implement mouseClicked method to make it determine which of ButtonPanel generate the event and call the corresponding to that component setButtonText() method. Is anyone know how to do that?
I know that I can achieve this by including event handling functionality in the ButtonPanel class, but thats not appropriate way for me, cuz I want to keep the class structure as I described above and have only one instance of MouseAdapterMod class for handling all of the ButtonPanels.
The MouseEvent#getSource method will return which object has been clicked:
public class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
As the comments note, you're often better off listening for mousePressed or mouseReleased rather than mouseClicked because for mouseClicked to work, the press and release must be from the same point, and if the mouse shifts even a slight amount, the click won't register.
My test program:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class MainForButtonPanel extends JPanel {
public MainForButtonPanel() {
setLayout(new GridLayout(4, 4));
MouseAdapter myMA = new MouseAdapterMod();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
ButtonPanel btnPanel = new ButtonPanel();
btnPanel.addMouseListener(myMA);
add(btnPanel);
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MainForButtonPanel");
frame.getContentPane().add(new MainForButtonPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class ButtonPanel extends JPanel {
private static final int TIMER_DELAY = 2000;
private static final String JUST_CLICKED = "just clicked";
private static final String WAITING_FOR_CLICK = "waiting for click";
private static final Color CLICKED_COLOR = Color.pink;
private JLabel label;
public ButtonPanel() {
label = new JLabel(WAITING_FOR_CLICK);
add(label);
}
public void setButtonText() {
label.setText(JUST_CLICKED);
setBackground(CLICKED_COLOR);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
label.setText(WAITING_FOR_CLICK);
setBackground(null);
((Timer)ae.getSource()).stop();
}
}).start();
}
}
class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
How to add JPanel to JFrame in other class?? I've tried with this code, but when I compile it, it didn't show any component in MyFrame.java (the label "Hello World"). What's wrong with my code?
(Button in MainFrame.java called the MyFrame.java)
Here's the code:
MyPanel.java (contains button and label)
public class MyPanel extends javax.swing.JPanel {
public MyPanel() {
initComponents();
myLabel.setText("Hello World");
}
}
MyFrame.java
public class MyFrame extends javax.swing.JFrame {
MyPanel myPanel = new MyPanel();
public MyFrame() {
initComponents();
this.add(myPanel);
}
}
MainFrame.java
public class MainFrame extends javax.swing.JFrame {
public MainFrame() {
initComponents();
}
private void btnCallFrameActionPerformed(java.awt.event.ActionEvent evt) {
new MyFrame().setVisible(true);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MainFrame().setVisible(true);
}
});
}
}
I don't know what you have done in initComponents method. So I have changed your code a little bit.
public class MyPanel extends javax.swing.JPanel {
public MyPanel() {
initComponents();
//I don't know what you did in initComponents(); so I ve changed the layout to be sure that you didn't use null layout.
this.setLayout(new BorderLayout());
JLabel myLabel = new JLabel();
myLabel.setText("Hello World");
//adding the label in MyPanel
this.add(myLabel);
}
}
public class MyFrame extends javax.swing.JFrame {
MyPanel myPanel = new MyPanel();
public MyFrame() {
initComponents();
// added because of the former reason
this.setLayout(new BorderLayout());
this.add(myPanel);
}
}
I hope you are sure that you can call the btnCallFrameActionPerformed method with some button.
I have a class whitch extends JPanel:
public class ButtonPanel extends JPanel {
private label;
public ButtonPanel() {
label=new JLabel("waiting for click");
add(label);
}
public void setButtonText() {
label.setText("just clicked");
}
}
I have several instances of that class which is added to JFrame. I want to create one instanse of MouseAdapter class and then add them as a mouse listener to all of the ButtonPanel components on my JFrame. I meen:
ButtonPanel butt1 = new ButtonPanel();
ButtonPanel butt2 = new ButtonPanel();
ButtonPanel butt3 = new ButtonPanel();
//... here goes code which add ButtonPanels to JFrame
MouseAdapterMod mam = new MouseAdapterMod();
butt1.addMouseListener(mam);
butt2.addMouseListener(mam);
butt3.addMouseListener(mam);
The MouseAdapterMod class I want to be separate from the other and locate in it's own package. It should looks like this:
public class MouseAdapterMod extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
//here goes the code of calling setButtonText method of ButtonPanel component on which the event had occurred
}
}
So the problem is that I don't know how to implement mouseClicked method to make it determine which of ButtonPanel generate the event and call the corresponding to that component setButtonText() method. Is anyone know how to do that?
I know that I can achieve this by including event handling functionality in the ButtonPanel class, but thats not appropriate way for me, cuz I want to keep the class structure as I described above and have only one instance of MouseAdapterMod class for handling all of the ButtonPanels.
The MouseEvent#getSource method will return which object has been clicked:
public class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
As the comments note, you're often better off listening for mousePressed or mouseReleased rather than mouseClicked because for mouseClicked to work, the press and release must be from the same point, and if the mouse shifts even a slight amount, the click won't register.
My test program:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class MainForButtonPanel extends JPanel {
public MainForButtonPanel() {
setLayout(new GridLayout(4, 4));
MouseAdapter myMA = new MouseAdapterMod();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
ButtonPanel btnPanel = new ButtonPanel();
btnPanel.addMouseListener(myMA);
add(btnPanel);
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MainForButtonPanel");
frame.getContentPane().add(new MainForButtonPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class ButtonPanel extends JPanel {
private static final int TIMER_DELAY = 2000;
private static final String JUST_CLICKED = "just clicked";
private static final String WAITING_FOR_CLICK = "waiting for click";
private static final Color CLICKED_COLOR = Color.pink;
private JLabel label;
public ButtonPanel() {
label = new JLabel(WAITING_FOR_CLICK);
add(label);
}
public void setButtonText() {
label.setText(JUST_CLICKED);
setBackground(CLICKED_COLOR);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
label.setText(WAITING_FOR_CLICK);
setBackground(null);
((Timer)ae.getSource()).stop();
}
}).start();
}
}
class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
I Googled for a lot, and no solutions found. I think there shall be java masters to help me out ...
This is my initialize method:
private void initialize() {
this.setSize(750, 480);
this.setContentPane(getJContentPane());
this.setTitle("Registration");
JPanel topPane = new TopPane();
this.getContentPane().add(topPane,BorderLayout.PAGE_START);
cards=new JPanel(new CardLayout());
cards.add(step0(),"step0");
cards.add(step1(),"step1");
cards.add(step2(),"step2");
this.getContentPane().add(cards,BorderLayout.CENTER);
}
public JPanel step2(){
EnumMap<DPFPFingerIndex,DPFPTemplate> template = new EnumMap<DPFPFingerIndex, DPFPTemplate>(DPFPFingerIndex.class);
JPanel enrol = new Enrollment(template,2);
return enrol;
}
public JPanel step0(){
JPanel userAgree = new UserAgreement();
return userAgree;
}
public JPanel step1(){
JPanel userInfo = new UserInformation();
return userInfo;
}
public JPanel getCards(){
return cards;
}
This, is the method at another step0 JPanel:
jButtonAgree.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
Registration reg = new Registration();
LayoutManager cards = reg.getCards().getLayout();
((CardLayout) cards).show(reg.getCards(),"step1");
}
});
No reation at all, i tried revalidate, repaint and other staff... doesn't work ... any one got any soution here!
It's all about exposing the right methods and constant Strings to the outside world to allow the class to swap views itself. For example, give your first class a private CardLayout field called cardlayout and a private JPanel field called cards (the card holder JPanel), and some public String constants that are used to add your card JPanels to the cards container. Also give it a public method, say called public void swapView(String key) that allows outside classes to swap cards... something like so:
// code corrected
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Registration extends JPanel {
// use these same constants as button texts later
private static final Dimension PREF_SIZE = new Dimension(450, 300);
public static final String USER_AGREEMENT = "User Agreement";
public static final String USER_INFO = "User Information";
public static final String ENROLLMENT = "Enrollment";
// we'll extract them from this array
public static final String[] KEY_TEXTS = {USER_AGREEMENT, USER_INFO, ENROLLMENT};
private CardLayout cardlayout = new CardLayout();
private JPanel cards = new JPanel(cardlayout);
public Registration() {
cards.add(createUserAgreePanel(), USER_AGREEMENT);
cards.add(createUserInfoPanel(), USER_INFO);
cards.add(createEnrollmentPanel(), ENROLLMENT);
setLayout(new BorderLayout());
add(cards, BorderLayout.CENTER);
}
#Override
public Dimension getPreferredSize() {
return PREF_SIZE;
}
private JPanel createEnrollmentPanel() {
JPanel enrol = new JPanel();
enrol.add(new JLabel("Enrollment"));
return enrol;
}
private JPanel createUserAgreePanel() {
JPanel userAgree = new JPanel();
userAgree.add(new JLabel("User Agreement"));
return userAgree;
}
private JPanel createUserInfoPanel() {
JPanel userInfo = new JPanel();
userInfo.add(new JLabel("User Information"));
return userInfo;
}
public void swapView(String key) {
cardlayout.show(cards, key);
}
}
Then an outside class can swap views simply by calling the swapView on the visualized instance of this class, passing in the appropriate key String such as in this case CardTest.USER_INFO to show the user info JPanel.
Now you have a problem with this bit of code where I indicate by comment:
jButtonAgree.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
Registration reg = new Registration(); // **** HERE *****
LayoutManager cards = reg.getCards().getLayout();
((CardLayout) cards).show(reg.getCards(),"step1");
}
});
On that line you're creating a new Registration object, probably one that is completely unrelated to the one that is visualized on the GUI, and so calling methods on this new object will have absolutely no effect on the currently viewed gui. YOu need instead to get a reference to the viewed Registration object, perhaps by giving this class a getRegistration method, and then call its methods, like so:
class OutsideClass {
private Registration registration;
private JButton jButtonAgree = new JButton("Agree");
public OutsideClass() {
jButtonAgree.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// make sure registration reference has been obtained first!
if (registration != null) {
registration.swapView(Registration.USER_AGREEMENT);
}
}
});
}
// here I allow the calling class to pass a reference to the visualized
// Registration instance.
public void setRegistration(Registration registration) {
this.registration = registration;
}
}
For example:
#SuppressWarnings("serial")
class ButtonPanel extends JPanel {
private Registration registration;
public ButtonPanel() {
setLayout(new GridLayout(1, 0, 10, 0));
// go through String array making buttons
for (final String keyText : Registration.KEY_TEXTS) {
JButton btn = new JButton(keyText);
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (registration != null) {
registration.swapView(keyText);
}
}
});
add(btn);
}
}
public void setRegistration(Registration registration) {
this.registration = registration;
}
}
and the MainClass that drives this all
class MainClass extends JPanel {
public MainClass() {
Registration registration = new Registration();
ButtonPanel buttonPanel = new ButtonPanel();
buttonPanel.setRegistration(registration);
buttonPanel.setBorder(BorderFactory.createTitledBorder("Button Panel"));
registration.setBorder(BorderFactory.createTitledBorder("Registration Panel"));
setLayout(new BorderLayout());
add(registration, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Registration");
frame.getContentPane().add(new MainClass());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}