StackOverflowError in GUI code - java

Any idea why my code is not connected to the frame?
Frame:
import javax.swing.*;
import java.awt.*;
public class CourseGUI extends JFrame {
public CourseGUI()
{
super("CourseGUI Frame");
JPanel topPane = new TopPanel();
JPanel topPanel = new JPanel();
topPanel.setBackground(java.awt.Color.WHITE);
Dimension d = new Dimension(800,600);
topPanel.setPreferredSize(d);
this.setLayout(new BorderLayout());
this.add(topPanel, BorderLayout.NORTH);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800,600);
this.setVisible(true);
}
public static void main(String[] args)
{
new CourseGUI();
}
}
Panel:
import javax.swing.*;
import java.awt.*;
public class TopPanel extends JPanel {
public TopPanel() {
TopPanel tp = new TopPanel();
tp.add(new JLabel("Course Info"));
tp.setSize(300,300);
tp.setVisible(true);
}
}
With the panel, I tried to get it where it will be on the NORTH of the Frame, sadly, it's not working. I am a beginner programmer, well In SCHOOL this year to actually learn this, Our teacher taught us this 4 days ago and I can not be anymore confused. Tried to get help several times on this, even from professor, with no avail, someone please help me out and explain. Thanks in advance.

public class TopPanel extends JPanel {
public TopPanel() {
TopPanel tp = new TopPanel();
tp.add(new JLabel("Course Info"));
tp.setSize(300,300);
tp.setVisible(true);
}
}
By creating a TopPanel object inside its own constructor you are causing near infinite recursion:
your TopPanel constructor will create a new TopPanel object
whose constructor will create a new TopPanel object
whose constructor will create a new TopPanel object
whose constructor will create a new TopPanel object whose constructor ,....
... etc -- recursion until your memory runs out. Don't do this.
Instead, don't do this:
public class TopPanel extends JPanel {
public TopPanel() {
// get rid of the recursion
// TopPanel tp = new TopPanel();
// add the label to the current TopPanel object, the "this"
add(new JLabel("Course Info"));
// setSize(300,300); // generally not a good idea
// tp.setVisible(true); // not needed
}
// this is an overly simplified method. You may wish to calculate what the
// preferred size should be, or simply don't set it and let the components
// size themselves.
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
Edit
Also, while not in error, this:
JPanel topPane = new TopPanel();
JPanel topPanel = new JPanel();
is very confusing since the two JPanel variables are close enough in name to confuse us, and more importantly to confuse your future self. You will want to use more logical and distinct variable names.

Related

Layout Problem in Java - set a 20%opaque Panel on Bottom of JFrame

Well, actually I have a Layout problem in java Swing. I simply want to add a JPanel on the bottom of a Frame - a coding snipplet that might be done with every web based language in about 5 Minutes. Not so in Java. I tried to add a jPanel to a jFrame, that Contains a jContentPane, set the size of the jPanel to what I need and to repaint and revalidate the jFrame, as well as setting the LayOutManager to null.
Java shows me in this case a full-width jPanel, that fills my whole jFrame.
Therefore I tried another approach: I divided my jPanel in a fully transparent jPanel on top and a 20%opaque jPanel on the bottom. Still it didn't work out as expected.
Since then I tried to resize the child jPanels of my new Panel and the Panel as well and tried to repaint and revalidate the jFrame. Without any effect.
Despite of my efforts, java still shows me a full sized 20%opaque jPanel on the whole jFrame, that now contains another 20%opaque jPanel on Top.
I know that this whole problem is caused by the LayoutManager, Java useless per Default. However, it is not an option to set the LayoutManager to null or even change the LayoutManager of our jFrame, because that would lead us to refactor the whole functionality of our tiny app we worked on for several weeks.
public void showUndoPanel() {
System .out.println("Show Undo Panel");
JPanel myPanel = new JPanel(null);
JPanel glassPanel = new JPanel();
JPanel ContentPanel = new JPanel();
JLabel myJLabel = new JLabel("Great Job!");
myPanel.setBackground(new Color(255,122,122,100));
glassPanel.setSize(650, 550);
glassPanel.setBackground(new Color(255,122,122,100));
myPanel.add(glassPanel);
ContentPanel.setSize(650, 30);
ContentPanel.setBackground(new Color(255,122,122,20));
ContentPanel.add(myJLabel);
myPanel.revalidate();
myPanel.repaint();
undoPanel = myPanel;
myJFrame.add(undoPanel);
myJFrame.revalidate();
}
What I expected:
What it actually does:
Well, I solved the problem by using a BoxLayoutManager and a RigidArea. In case if anyone else may encounter that problem again in the future, I decided to provide the code for this simple solution.
public void showUndoPanel() {
System .out.println("Show Undo Panel");
JPanel myPanel = new JPanel(null);
JPanel glassPanel = new JPanel();
JPanel ContentPanel = new JPanel();
JLabel myJLabel = new JLabel("Great Job!");
myPanel.setBackground(new Color(255,255,255,0));
myPanel.setLayout(new BoxLayout(myPanel, BoxLayout.PAGE_AXIS));
glassPanel.setSize(650, 650);
glassPanel.setBounds(0,0,650,550);
glassPanel.setBackground(new Color(255,122,122,0));
myPanel.add(glassPanel);
myPanel.add(Box.createRigidArea(new Dimension(0,450)));
ContentPanel.setSize(650, 30);
ContentPanel.setBounds(0,750,650,30);
ContentPanel.setBackground(new Color(255,122,122,20));
ContentPanel.add(myJLabel);
myPanel.add(ContentPanel);
myPanel.revalidate();
myPanel.repaint();
undoPanel = myPanel;
myJFrame.add(undoPanel);
myJFrame.revalidate();
}
Now it behaves as expected:
BorderLyout would make it easier to implement.
Note the comments in the following mre:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
private static JFrame myJFrame;
public static void main(String[] args) {
myJFrame = new JFrame();
myJFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
myJFrame.setLocationRelativeTo(null);
showUndoPanel();
myJFrame.pack();
myJFrame.setVisible(true);
}
public static void showUndoPanel() {
JPanel myPanel = new JPanel();
myPanel.setBackground(new Color(255,255,255,0));
myPanel.setLayout(new BorderLayout());
JPanel glassPanel = new JPanel(); //uses FlowLayout by default
//glassPanel.setSize(650, 650); //use preferred size
glassPanel.setPreferredSize(new Dimension(650, 650));
//glassPanel.setBounds(0,0,650,550); //no need to set bounds. bounds are set by the layout manager
glassPanel.setBackground(new Color(255,122,122,0));
myPanel.add(glassPanel, BorderLayout.CENTER);
JPanel contentPanel = new JPanel(); //uses FlowLayout by default
//contentPanel.setSize(650, 30);//use preferred size
contentPanel.setPreferredSize(new Dimension(650, 30));
//contentPanel.setBounds(0,750,650,30); //no need to set bounds. bounds are set by the layout manager
contentPanel.setBackground(new Color(255,122,122,20));
JLabel myJLabel = new JLabel("Great Job!");
contentPanel.add(myJLabel);
myPanel.add(contentPanel, BorderLayout.SOUTH);
myJFrame.add(myPanel);
}
}

Two JPanels in one JFrame

I want to use two JPanels in one JFrame, with an invisible horizontal line between them. I played a little bit and got this:
public class Application {
public static void main(String[] args)
{
JFrame jframe = new JFrame();
jframe.setSize(500,700);
jframe.setVisible(true);
jframe.setTitle("Title");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);
JSplitPane splitPane = new JSplitPane();
JPanel leftPanel = new JPanel();
JPanel rightPanel = new JPanel();
splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setDividerLocation(250);
splitPane.setLeftComponent(leftPanel);
splitPane.setRightComponent(rightPanel);
jframe.add(splitPane);
}
}
Now, the first problem is how can I turn off the "resizability" of the Line between the panels? And how do I make it "invisible"? Maybe use something else than split pane?
Second of all, how do can I work with only one side of the JPanel?
(I am working on an application that lets you draw a circle on the left hand side).
This seems like an easy question but I am relatively new to Java.
As said before in a comment by #MadProgrammer you can use BorderLayout or GridBagLayout but as you're placing the "split" line right in the middle of both panels you could use GridLayout which will make both panels be of the same size no matter if the window is resized.
I didn't tried with GridBagLayout but I did an example on how you could achieve this pane separation without using a JSplitPane.
With GridLayout all you need to do is add the elements to the left pane (in my example I used a JLabel to differentiate them) while in BorderLayout you need to specify that the panel where you'll be painting the circle to be aligned to the left (WEST constant) as I did.
However if you use BorderLayout approach and add text or elements to the right pane, they will be aligned to the right, you can fix it by "boxing" the elements in another pane with a different Layout.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Application {
private JFrame frame;
private JPanel containerPane;
private JPanel topPane;
private JPanel bottomPane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Application().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame("Example of 2 panels");
containerPane = new JPanel();
topPane = new JPanel();
bottomPane = new JPanel();
containerPane.setLayout(new GridLayout(2, 1));
topPane.setLayout(new GridLayout(1, 2));
bottomPane.setLayout(new BorderLayout());
topPane.add(new JLabel("Left side"));
topPane.add(new JLabel("Right side"));
bottomPane.add(new JLabel("Left side"), BorderLayout.WEST);
bottomPane.add(new JLabel("Right side"), BorderLayout.EAST);
topPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLUE), "Using GridLayout"));
bottomPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLUE), "Using BorderLayout"));
containerPane.add(topPane);
containerPane.add(bottomPane);
frame.add(containerPane);
// frame.pack();
frame.setSize(500, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I didn't call pack() in this example because the size of both panels (or JLabels in this case was not tall enough to show the difference:
Using pack():
Calling setSize():
Additional tips
Don't forget to place your program on the Event Dispatch Thread (EDT), I did it by writing these lines on the main method:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Application().createAndShowGui();
}
});
Don't place all your code on the constructor, otherwise it will be hard to maintain
It looks like you can use GridLayout to do this. Here is what i think,
public class Application {
public static void main(String[] args) {
JFrame jframe = new JFrame();
jframe.setTitle("Title");
jframe.setResizable(false);
//This creates one row and two equally divided columns
GridLayout gridLayout = new GridLayout(0, 2);
jframe.setLayout(gridLayout);
gridLayout.layoutContainer(jframe);
JPanel leftPanel = new JPanel();
leftPanel.add(new Label("Left side"));
jframe.add(leftPanel);
JPanel rightPanel = new JPanel();
rightPanel.add(new Label("Right side"));
jframe.add(rightPanel);
jframe.setSize(800, 500);
jframe.setVisible(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Here is how it looks:
The panels will not resize as well as there is no line visible that seprates them.

BorderLayout - JPanel in JPanel

I want to create two JPanel containers nested in another panel, but why does it show nothing as the code below? It seems that my two panels are not on the ABC panel?
public class ABC extends JPanel
{
Frame frame;
public ABC(Frame frame)
{
super();
this.frame = frame;
setLayout(new BorderLayout());
JPanel one = new JPanel();
JPanel two = new JPanel();
add(one,BorderLayout.NORTH);
add(two,BorderLayout.CENTER);
one.setVisible( true );
two.setVisible( true );
}
public class one extends JPanel {
public one() {
setLayout(new FlowLayout(FlowLayout.LEFT));
createA();
setVisible(true);
}
}
public class two extends JPanel {
public two() {
setLayout(new FlowLayout(FlowLayout.LEFT));
createB();
setVisible(true);
}
}
private void createA(){
add(ButtonA);
add(ButtonAA);
add(ButtonAAA);
}
private void createB(){
add(ButtonB);
}
}
Ur using it in the wrong way, u must use youre own clases (one, two) not the JPANEL:
JPanel one = new one();
JPanel two = new two();
add(one,BorderLayout.NORTH);
add(two,BorderLayout.CENTER);
Btw, try to change the name of your clases can be confusing, to One, Two
try to change the prefererSize of the panel one because when you put a panel in NORTH OR anywhere else but the CENTRE it should have a size
use border to see the edge of the panel
one.setBorder(BorderFactory.createLineBorder(Color.black));
two.setBorder(BorderFactory.createLineBorder(Color.blue));
one.setpreferredsize(new new dimension(width,height));
add(one,BorderLayout.NORTH);

Adding JPanel to another JPanel in a different class

I'm trying to add a JPanel to another JPanel from another class. The program does not longer throw an error and all methods have been run, but the new panel just has a black screen. A basic version of the program looks as follows:
package ninjadragon;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class NinjaDragon extends JFrame implements ActionListener{
public JPanel panelMain;
public JPanel panelTurnBase;
public static void main(String[] args) {
NinjaDragon();
}
public static void NinjaDragon() {
NinjaDragon frame;
frame = new NinjaDragon();
frame.CreateMenuScreen();
JFrame.setDefaultLookAndFeelDecorated(true);
frame.setSize(750, 750);
frame.show();
frame.setResizable(false);
frame.pack();
}
private void CreateMenuScreen() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container window = getContentPane();
panelMain =new JPanel();
panelMain.setPreferredSize(new Dimension(750,750));
panelMain.setBackground(Color.BLACK);
panelMain.setLayout (new FlowLayout());
window.add(panelMain);
PanelTop();
PanelButtons();
PanelIcon();
}
#Override
public void actionPerformed(ActionEvent event) {
Object eventSource = event.getSource();
if (eventSource == buttonStart) {
panelMain.removeAll();
TurnBase TB = new TurnBase();
TB.CreateTurnBase();
}
}
The other class looks something like this:
public void CreateTurnBase() {
panelMain=new JPanel();
panelTurnBase =new JPanel();
setLayout(new FlowLayout());
setPreferredSize(new Dimension(750,750));
setBackground(Color.BLUE);
panelTurnBase.setLayout (new FlowLayout());
panelMain.add(panelTurnBase);
System.out.println("1");
PanelTurnBaseTop();
PanelGameScreen();
PanelTurnBaseBottom();
repaint();
revalidate();
buttonAttack = new JButton("Attack");
buttonAttack.addActionListener(this);
panelTurnBase.add(buttonAttack);
System.out.println("2");
}
The reason the panel has "just a black screen" is because you dont add anything to it, and you tell it to have a black screen.
i.e
panel.setBackground(Color.BLACK);
You never actually do anything to that first panel inside of any of those methods, which I can assume based on your representation of your second "class" (it's a method). Hence why it stays black.
You say:
panelMain=new JPanel();
panelTurnBase =new JPanel();
You're creating new JPanels every time and just call them panelMain and they just sit inside of that method, never leaving. You either need to return a JPanel or give it a JPanel as an argument.
The program is doing exactly what you tell it to do.
Also, do not compare Objects like this:
eventSource == buttonStart
You should use:
eventSource.equals(buttonStart);

How to use Card layout?

I'm having a hard time trying to figure out what is a card layout. I read so many articles and implemented this small example of to see how card layout works. But I can't understand some methods(which are commented). Can someone please help me (I use commandline).
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class C_layout implements ActionListener
{
JButton b2;
JButton b1;
JFrame f1;
JPanel card1;
JPanel card2;
JPanel Jp;
void Example()
{
f1=new JFrame("CardLayout Exercise");
f1.setLocationRelativeTo(null);
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f1.setSize(500,500);
f1.setVisible(true);
Container cont=f1.getContentPane();
cont.setLayout(null);
Jp=new JPanel(new CardLayout()); //<-- How to implement card layout here (MAIN PANEL)
f1.add(Jp);
Jp.setLayout //<-- Not sure what means here ERROR
card1=new JPanel(); // First panel
Jp.add(card1);
card2=new JPanel(); // Second panel
Jp.add(card2);
JLabel lb1=new JLabel("This is the first Panel");
lb1.setBounds(250,100,100,30);
card1.add(lb1);
b1=new JButton("NEXT >>");
b1.setBounds(350,400,100,30);
b1.addActionListener(this);
card1.add(b1);
JLabel lb2=new JLabel("This is the second Panel");
lb2.setBounds(250,100,100,30);
card2.add(lb2);
b2=new JButton("<< PREV");
b2.setBounds(250,300,100,30);
b2.addActionListener(this);
card2.add(b2);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==b1)
{
CardLayout cardLayout = (CardLayout) Jp.getLayout();
cardLayout.show(card2,"2");
}
if(e.getSource()==b2)
{
// I still haven't implemented this action listener
}
}
}
class LayoutDemo1
{
public static void main(String[] args)
{
C_layout c=new C_layout();
c.Example();
}
}
cont.setLayout(null); is bad, bad idea, lose it quickly...
You're going to need a reference to your CardLayout in order to manage it. Start by defining a instance field of CardLayout...
private CardLayout cardLayout;
Now, create your instance of CardLayout and apply it to your panel...
cardLayout = new CardLayout();
Jp=new JPanel(cardLayout);
This...
Jp.setLayout //<-- Not sure what means here ERROR
doesn't do anything, it's not a valid statement as far as Java is concerned, in fact, it's actually a method, which should take a reference to the LayoutManager you want to use, but since you've already done that when you created the instance of Jp, you don't need it...
You're going to need some way to identify the components you want to show, CardLayout does this via String names, for example...
card1=new JPanel(); // First panel
Jp.add(card1, "card1");
card2=new JPanel(); // Second panel
Jp.add(card2, "card2");
Now, in your ActionListener, you want to ask CardLayout to show the required view...
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==b1)
{
cardLayout.show(Jp1,"card2");
} else if(e.getSource()==b2)
{
cardLayout.show(Jp1,"card1");
}
}
Note, in order for CardLayout#show to work, you need to pace it a reference of the container to which the CardLayout is assigned AND the name of the view you want to display.
See How to Use CardLayout for more details

Categories