I used a plug-in of Eclipse to create the class diagram of this code:
public class ButtonGrid
{
private static int difficulty, moveleft, Counter, treasure_x , treasure_y;
private static String message;
JTextField tf = new JTextField();
public static JTextField tf2 = new JTextField();
JFrame frame = new JFrame(); //creation of the main game window
JPanel panel = new JPanel();
JPanel panel2 = new JPanel(new FlowLayout());
JPanel panel3 = new JPanel();
JLabel hint = new JLabel("Hint:");
JButton[][] grid; //grid buttons
public ButtonGrid (int width, int length)
{
}
ActionListener al = new ActionListener() //Action listener for the buttongrid
{
public void actionPerformed(ActionEvent e)
{
}
};
ActionListener al2 = new ActionListener() // Action listener for the reset button
{
public void actionPerformed (ActionEvent e)
{
}
}
};
public static void main (String[] args)
{
}
I cut some useless parts to reduce the size. The diagram that Eclipse draw is this one:
Do you think it's correct? I'm wondering because i thougth the ActionListeners were considered sub-classes, and also the ActionListener in the main method is not showed, but maybe it's just me not understanding how class diagrams work.
It looks right to me. The ActionListeners you have defined are anonymous classes for your protected attributes a1, and a2. Basically what the anonymous classes are doing is subclassing the ActionListener class. These new, unnamed classes are set to a1, and a2. That is why they show up the way they do in the class diagram. Also the reason that the one in your main method isn't showing up, is that anonymous ActionListener is a local variable to your main function.
Here is some information that Oracle: has about anonymous classes (http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html)
Hope this help, good luck with your programming.
Your diagram seems correct. None of the variables you create inside the methods will appear in this diagram. Only the variables you define on the top (or outside the methods but inside the class definition) will appear in the diagram:
private static int difficulty, moveleft, Counter, treasure_x , treasure_y;
private static String message;
JTextField tf = new JTextField();
public static JTextField tf2 = new JTextField();
JFrame frame = new JFrame(); //creation of the main game window
JPanel panel = new JPanel();
JPanel panel2 = new JPanel(new FlowLayout());
JPanel panel3 = new JPanel();
JLabel hint = new JLabel("Hint:");
JButton[][] grid; //grid buttons
ActionListener al = new ActionListener() //Action listener for the buttongrid
{
//defintion of this ActionListner
};
ActionListener al2 = new ActionListener() // Action listener for the reset button
{
//definition of this ActionListener
};
ActionListener is actually an interface:
http://docs.oracle.com/javase/7/docs/api/java/awt/event/ActionListener.html
You must define it or else you can't use it. A subclass is a class that has a parent class:
http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
Related
I have four buttons each on four different panels. If I press the button I would want the panel it's on to change color. The problem is I only know how to do that for one button and not all four. Here is my code so far...
public class tester implements ActionListener
{
JPanel B;
JPanel A;
public static void main(String[]args)
{
new tester();
}
public void tester()
{
JFrame test = new JFrame("tester:");
B = new JPanel();
A= new JPanel();
JPanel cc = new JPanel();
JPanel dd = new JPanel();
JButton b = new JButton("ButtonB");
JButton a = new JButton("ButtonA");
JButton c = new JButton("ButtonC");
JButton d = new JButton("ButtonD");
test.setLayout(new GridLayout(2,2));
test.setSize(600,500);
B.setBackground(Color.BLUE);
A.setBackground(Color.RED);
cc.setBackground(Color.BLACK);
dd.setBackground(Color.WHITE);
B.add(b);
A.add(a);
cc.add(c);
dd.add(d);
test.add(A);
test.add(B);
test.add(cc);
test.add(dd);
test.setVisible(true);
b.addActionListener(this);
a.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
B.setBackground(Color.PINK);
}
}
You can use anonymously created Action listeners instead of implementing interface in your class.
b.addActionListener(new ActionListener() {
//method impl.
});
And use that to create 4 different actions.
Or you could get source of action from
e.getSource()
And then decide based on that.
Or you can skip ActionListener all the way, and use lambda
b.addActionListener(e -> someActionOrSomething(e))
You have to check the resource and can perform action based on it If you are trying to keep a common ActionListener,
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==b)//button b
B.setBackground(Color.PINK);
else if(e.getSource()==a)//button a
A.setBackground(Color.BLACK);
}
Please note you have to declare your buttons globally, If you have to use it inside the class,
public class Test implements ActionListener
{
JPanel B;
JPanel A;
JButton b;
JButton a;
Also you have created the implementation in a method called tester which should be called as,
new Test().tester();
I have a ArrayList of JPanel. And each items of this list has a JButton.
Now, when JButton is clicked I want to remove its' parent JPanel from the ArrayList. So how can I make the JButton remove its' parent from the ArrayList?
Thanks in advance.
public class TestingArrayList extends JFrame {
JPanel grandPanel; // a JPanel for all the panels
ArrayList<JPanel> panelParent = new ArrayList<>(); // JPanel ArrayList
public TestingArrayList() {
super("Test");
setLayout(new FlowLayout());
grandPanel = new JPanel();
add(grandPanel);
for (int i = 0; i < 10; i++) { // adding 10 JPanel into grandPanel
panelParent.add(new JPanel());
grandPanel.add(panelParent.get(i));
// adding JButton in all panels
JButton btnParent = new JButton("X");
panelParent.get(i).add(btnParent);
// add new task button action
btnParent.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(getParent());
//What to do!!!
}
});
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1000, 100);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new TestingArrayList();
}
}
You have all you need right in your code. You just need a final reference to the JPanel of interest as this will allow you to use it within the anonymous inner ActionListener class:
for (int i = 0; i < 10; i++) {
// make it final so that it is accessible from inner anon class
final JPanel myPanel = new JPanel();
panelParent.add(myPanel);
grandPanel.add(myPanel);
JButton btnParent = new JButton("X");
myPanel.add(btnParent);
btnParent.addActionListener(event -> panelParent.remove(myPanel));
}
If you also want to remove it from the grandPanel, then you'll need more...
btnParent.addActionListener(event -> {
panelParent.remove(myPanel);
grandPanel.remove(myPanel);
grandPanel.revalidate();
grandPanel.repaint();
});
Note, that if you wanted to use Seymore's method of removing the JPanel, you first need to understand that the source object obtained by calling getSource() on the ActionEvent parameter is the object that the listener was added to -- here a JButton not a JPanel, and also the type of object returned is Object, and so no Swing component methods can be called on it without casting. And so you would need to wrap all in parenthesis in order to allow you to call methods of that type. For example:
parentPanel.remove((JPanel) ((JButton) event.getSource()).getParent());
or
parentPanel.remove((JPanel) ((JComponent) event.getSource()).getParent());
I find it easier to separate lines when code gets this convoluted:
// since a JButton extends from JComponent
JComponent source = (JComponent) event.getSource();
JPanel parent = (JPanel) source.getParent();
parentPanel.remove(parent);
btnParent.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(getParent());
panelParent.remove((JPanel)(event.getSource().getParent()));
}
});
In my program I have a wizard based layout. Implemented by CardLayout. So there is a set of classes that extend JPanels. I want to have buttons in each panel to navigate to other panels. fro example, when the program is showing panel one, I want to have a button to show panel 2.
I tired to create a method in main cardlayout panel holder so any other class can change the showing panel by this method, but it does not works and a stackoverflow error come up.
Here are my classes
Base Frame:
public class Base {
JFrame frame = new JFrame("Panel");
BorderLayout bl = new BorderLayout();
public Base(){
frame.setLayout(bl);
frame.setSize(800, 600);
frame.add(new LeftBar(), BorderLayout.WEST);
frame.add(new MainPanel(), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
new Base();
}
}
Main class that holds sub panels:
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel() {
NewSession session = new NewSession();
ChooseSource chooseSource = new ChooseSource();
panelHolder.add(session, "Session");
panelHolder.add(chooseSource, "ChooseSource");
cl.show(panelHolder, "Session");
add(panelHolder);
}
public void showPanel(String panelIdentifier){
cl.show(panelHolder, panelIdentifier);
}
}
Sub panel 1
public class NewSession extends JPanel {
MainPanel ob2 = new MainPanel();
public NewSession(){
JButton newSessionBTN = new JButton("Create A New Session");
newSessionBTN.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
System.out.println("HI");
ob2.showPanel("ChooseSource");
}
});
add(newSessionBTN);
}
}
Sub panel 2
public class ChooseSource extends JPanel {
public ChooseSource(){
JLabel showMe = new JLabel("Show Me");
JButton back = new JButton("Back");
//MainPanel ob = new MainPanel();
back.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
//ob.showPanel("start");
}
});
add(back);
add(showMe);
}
}
As you can see I have button in each sub panel and those buttons must show the other panel after clicking. In later they will also transfer the data from one to another.
ERROR:
Exception in thread "main" java.lang.StackOverflowError
at java.awt.Component.setFont(Component.java:1899)
at java.awt.Container.setFont(Container.java:1748)
at javax.swing.JComponent.setFont(JComponent.java:2751)
at javax.swing.LookAndFeel.installColorsAndFont(LookAndFeel.java:208)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(BasicPanelUI.java:66)
at javax.swing.plaf.basic.BasicPanelUI.installUI(BasicPanelUI.java:56)
at javax.swing.JComponent.setUI(JComponent.java:663)
at javax.swing.JPanel.setUI(JPanel.java:153)
at javax.swing.JPanel.updateUI(JPanel.java:126)
at javax.swing.JPanel.<init>(JPanel.java:86)
at javax.swing.JPanel.<init>(JPanel.java:109)
at javax.swing.JPanel.<init>(JPanel.java:117)
at InnerPanels.NewSession.<init>(NewSession.java:21)
at StrongBaseLayout.MainPanel.<init>(MainPanel.java:22)
The error is longer than this, by repeating last two lines.
How can I make it working?
Also I had another idea to have a next and previous buttons at the bottom of the page to switch panels. But am not sure which one is optimal. Any idea?
Whenever you see an unexpected StackOverflowError always look for the presence of inadvertent recursion, and in fact, that's exactly what you have going on here since MainPanel creates a NewSession object which then creates a new MainPanel object which then creates a new NewSession object which then creates a new MainPanel object .... repeating ad infinitum or until stack memory (hence the stack overflow) runs out.
here:
public class NewSession extends JPanel {
MainPanel ob2 = new MainPanel(); // *****
and here:
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel() {
NewSession session = new NewSession(); // *****
Don't do that. Instead take care to create one and only one of each object. Use setter methods or constructor parameters to help you do this.
For example, change to this:
public class NewSession extends JPanel {
MainPanel ob2;
NewSession(MainPanel mainPanel) {
this.ob2 = mainPanel;
and this:
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel() {
NewSession session = new NewSession(this);
Regarding:
Also I had another idea to have a next and previous buttons at the bottom of the page to switch panels. But am not sure which one is optimal. Any idea?
I'm not sure what you mean here. Define "optimal".
I am currently learning how to use ActionListeners and I have a few questions about how it should be done.
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(0,1));
frame.setSize(250,250);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0,1));
final JTextField text1 = new JTextField(" ",10);
final JTextField text2 = new JTextField(" ",10);
final JTextField text3 = new JTextField(" ",10);
final JTextField text4 = new JTextField(" ",10);
panel.add(text1);
panel.add(text2);
panel.add(text3);
panel.add(text4);
ActionListener a = new ActionListener(){
public void actionPerformed(ActionEvent e){
text4.setText(text1.getText()+""+text2.getText()+""+text3.getText());
}
};
JButton buton = new JButton("Go");
buton.addActionListener(a);
frame.add(panel);
frame.add(buton);
frame.revalidate();
}
Given the code in the example, that is the only method I use inside my main class. As you can see for the listeners I am currently using some anonymous listeners that are implemented inside my main(). The thing is... I use them because clicking a button in the frame actually needs to change the content of another element.
My question is : Can you make the listener non-anonymous while still being able to use the other components? What I am thinking is moving the ActionListener implementation for the button in another class, but then how do I reach the properties of the other elements?
Example :
class listener implements ActionListener{
public void actionPerformed(ActionEvent e){
text4.setText(text1.getText()+""+text2.getText()+""+text3.getText());
}
}
then in my main() class I want to simply call :
listener l = new listener();
buton.addActionListener();
And still be able to make this outside listener acces properties of the elements inside the main class.
Yes, you can. But you'll need to explicitely pass the components to the listener, instead of passing them implicitely to the anonyous class:
class MyListener implements ActionListener {
private JTextField text1;
private JTextField text2;
private JTextField text3;
private JTextField text4;
public MyListener(JTextField text1, JTextField text2, JTextField text3, JTextField text4) {
this.text1 = text1;
this.text2 = text2;
this.text3 = text3;
this.text4 = text4;
}
#Override
public void actionPerformed(ActionEvent e){
text4.setText(text1.getText()+""+text2.getText()+""+text3.getText());
}
}
And in the main method:
button.addActionListener(new MyActionListener(text1, text2, text3, text4);
Usually though, components are stored in instance variables of an object (subclass of JPanel, typically), and listeners are implemented as inner classes (anonymous or not) that can thus access the instance variables directly:
public class MyPanel extends JPanel {
private JTextField textField;
private JButton button;
public MyPanel() {
// ...
button.addActionListener(new MyActionListener());
}
private class MyActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(textField.getText());
}
}
}
Also, note that:
you should not access swing components from the main thread. Only from the EDT. Read the swing concurrency tutorial.
you should call pack() and setVisible() after the components have been added. revalidate() is useless in this case. Don't call setSize(). It's the role of the layout manager and of the pack() method to find the appropriate dimension of the frame.
I don't what the problem is? I try to switch the two seperate classes extends JPanel with the cardLayout by using JButton and I don't know am I used the correct code...
Here is my coding.
CardLayoutMenu
public class CardLayoutMenu extends JFrame implements ActionListener{
CardLayout cardLayout = new CardLayout();
private JPanel p1 = new JPanel(cardLayout);
final String MAIN = "MAIN";
final String OPTION = "OPTION";
MainPanel mainPanel = new MainPanel();
OptionPanel optionPanel = new OptionPanel();
private Object object;
public CardLayoutMenu(Object object) {
this.object = object;
}
public CardLayoutMenu(){
setLayout(new BorderLayout());
setTitle("Card Layout Menu");
setSize(300,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
setLocationRelativeTo(null);
add(p1);
p1.add(mainPanel, MAIN);
p1.add(optionPanel, OPTION);
}
public void actionPerformed(ActionEvent e){
try{
cardLayout.show(p1, OPTION);
}catch(Exception ex){
System.out.println("" + ex);
}
}
}
Here is my MainPanel
public class MainPanel extends JPanel{
private JButton jbtOption = new JButton("Option");
public MainPanel() {
setLayout(new FlowLayout());
add(jbtOption);
jbtOption.addActionListener(new CardLayoutMenu(this));
}
}
Then my OptionPanel, use the JButton jbtBack to go back the MainPanel
public class OptionPanel extends JPanel{
private JButton jbtBack = new JButton("Back");
public OptionPanel() {
setLayout(new FlowLayout());
add(jbtBack);
}
}
This code here will cause an infinite recursion:
public MainPanel() {
setLayout(new FlowLayout());
add(jbtOption);
jbtOption.addActionListener(new CardLayoutMenu(this));
}
Since this constructor is ultimately called from the CardLayoutMenu class, you'll have a CardLayoutMenu object that creates a MainPanel object which creates a CardLayoutMenu object that creates a MainPanel object which creates a CardLayoutMenu object that creates a MainPanel object which creates a ... well, I think that you get the picture.
One basic rule I strongly urge on you is to not make your GUI classes implement Listener interfaces as it is asking the class to do too much and often leads to confusing code such as yours. This is sort of fine in small example programs, but I wish that it wasn't used as it encourages newbies to continue to do this sort of thing. Instead consider creating an ActionListener object and pass this listener to any class that needs a button that needs to tell the CardLayout to change views. You can pass this listener into these classes via a constructor or setter method parameter.