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);
Related
I have a simple task.
There is a frame. There are two panel in that frame. In second panel there is a button. When user click that button first panel must change its content.
Here is a code:
package test;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
class MyJPanel1 extends JPanel {
MyJPanel1() {
this.add(new JButton("MyJPanel1"));
}
}
class MyJPanel2 extends JPanel {
MyJPanel2() {
this.add(new JButton("MyJPanel2"));
}
}
class MyFrame extends JFrame {
JPanel topPanel = null;
MyFrame() {
super("Test");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new GridLayout(0, 1, 20, 20));
topPanel = new MyJPanel1();
this.add(topPanel);
JPanel bottomPanel = new JPanel();
this.add(bottomPanel);
JButton button = new JButton("switch");
button.addMouseListener(new MouseClickListener());
bottomPanel.add(button);
this.pack();
this.setVisible(true);
}
class MouseClickListener extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent e) {
topPanel = new MyJPanel2();
System.out.println("switch");
topPanel.invalidate();
topPanel.validate();
topPanel.repaint();
MyFrame.this.invalidate();
MyFrame.this.validate();
MyFrame.this.repaint();
}
}
}
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new MyFrame();
}
});
}
}
But that don't work. After I click on button I see text in console, but first panel remain the same. I read that I must use invalidate() validate() and repaint() methods and I did, but it isn't help.
Any help would be appreciated.
If you want to "switch" panels then you should be using a CardLayout. The CardLayout allows 2 (or more) components to share the same space in a container but only one is ever visible at a time.
Read the section from the Swing tutorial on How to Use CardLayout for more information and working examples.
In your mouseClicked() method you create a new topPanel, but you don't do anything with it. Perhaps you meant to remove the original topPanel from myFrame, create a new topPanel, and then add the new toipPanel to myFrame.
Note that this may not be the best strategy (creating a new topPanel).
When you choose a state, the frame's content pane removes its components. Then depending on the state you chose, another class takes the content pane and adds onto it. After doing so, the frame gets packed to resize accordingly.
I want free control over whats in the Frame, such as being able to put panels side by side, above one another, ect.. so I really don't want to use CardLayout. (I'd much rather have 1 panel handle both loginscreen and chat. Then, be able to display another panel next to that one).
I'm using the JFrame's content pane for my login and chat screen, but when I run my code, I get a small frame (has SOME size, but hardly any) that's white on the inside.
show frame
switch to chat
remove everything on pane (currently nothing)
add components onto pane
pack frame so it can size accordingly to the pane
revalidate if needed (not sure when I need to revalidate or not)
Please tell me what I'm doing wrong, and maybe guide me in the right direction.
PS: There are no errors
EDIT: The only thing I can think of is that since I'm passing frame.getContentPane() through the method, and methods are pass-by-value, the actual reference to frame.getContentPane() might not be noticing the changes I'm asking for. But then I don't know why the inside of the frame would be white (as if my JTextArea tried rendering), and there's padding on the inside of the frame, so there has to be something happening..
Main.java:
package main;
import ui.Frame;
public class Main {
public static Frame frame = new Frame();
public static void main(String[] args) {
frame.show();
frame.switchState(State.chat);
}
public static enum State {
login, chat;
}
}
Frame.java:
package ui;
import main.Main.State;
import javax.swing.JFrame;
public class Frame {
private Panel currentpanel; //from package ui, not AWT
private ChatPanel chatpanel = new ChatPanel();
private JFrame frame;
public Frame() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
}
public void show() {
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void switchState(State state) {
frame.removeAll();
switch(state) {
case chat:
currentpanel = chatpanel;
currentpanel.addComponentsTo(frame.getContentPane());
break;
}
frame.pack();
frame.revalidate();
}
}
Panel.java:
package ui;
import java.awt.Container;
public interface Panel {
public void addComponentsTo(Container pane);
}
ChatPanel.java:
package ui;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JTextArea;
public class ChatPanel implements Panel {
private JTextArea toparea = new JTextArea();
private JTextArea bottomarea = new JTextArea();
#Override
public void addComponentsTo(Container pane) {
pane.setPreferredSize(new Dimension(500, 500));
pane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.gridx = 0;
gbc.ipadx = 450;
gbc.ipady = 350;
pane.add(toparea, gbc);
gbc.gridy = 1;
gbc.ipady = 100;
pane.add(bottomarea);
}
}
I know that can be quite frustrating.
have you tried calling
pack(); or repaint();
I found the problem. It was calling frame.removeAll(); before adding anything to it.
When I tried if(frame.getComponents().length > 0), it still triggered removeAll(), but the problem wasn't fixed. Seeing how I haven't added anything yet, I checked to see what the component was (by printing out the object), and it was a JRootPane.
After that, I tried printing out frame.getContentPane().getComponents().length, it gave me 0 as expected.
Long story short: This is how switchPanel(State state) should look:
public void switchState(State state) {
if(frame.getContentPane().getComponents().length > 0)
frame.removeAll();
switch(state) {
case chat:
currentpanel = chatpanel;
currentpanel.addComponentsTo(frame.getContentPane());
break;
}
frame.pack();
frame.revalidate();
}
NOTE: I still recommend CardLayout, but if you insists in dynamically setting the frame's content pane the here it is.
The frame class
public class SwitchingFrame extends JFrame {
public static enum State {ONE, TWO}
private PanelONE panel1 = new PanelONE();
private PanelTWO panel2 = new PanelTWO();
public SwitchingFrame() {
getContentPane().setLayout(new BorderLayout());
pack();
setVisible(true);
}
public void switchState(State state) {
setVisible(false);
getContentPane().removeAll();
if (state.equals(State.ONE))
getContentPane().add(panel1, BorderLayout.CENTER);
else
getContentPane().add(panel2, BorderLayout.CENTER);
pack();
setVisible(true);
}
}
The two panel classes which are switched
public class PanelONE extends JPanel {
public PanelONE() {
add(new JLabel("ONE"));
}
}
public class PanelONE extends JPanel {
public PanelTWO() {
add(new JLabel("TWO"));
}
}
The main method which includes buttons to simulate changing the panels
public class TestSwitchingFrame {
public static void main(String[] args) {
final SwitchingFrame sframe = new SwitchingFrame();
JFrame frame = new JFrame();
JButton b1 = new JButton("ONE");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sframe.switchState(SwitchingFrame.State.ONE);
}
});
JButton b2 = new JButton("TWO");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sframe.switchState(SwitchingFrame.State.TWO);
}
});
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(b1);
frame.getContentPane().add(b2);
frame.pack();
frame.setVisible(true);
}
}
You do not need (not should) write your own interface (Panel). Your two panels should extend JPanel and set within the frames content pane. Your frame should extend JFrame and does not need to override its show method (let Swing do it for you). The specific implementation of the switchState function should eventually depend on the end result you want. There are similar ways to accomplish almost the same result.
I am new to swing, can anyone help me out with this...
It is not showing my "label" , instead it shows me only components which are in the "panel" class.
One more question, can anyone clarify me about LayoutManagers ?
Can 2 or more LayoutManagers be used in a frame ? like for the frame i will be using FlowLayout and i have a JPanel added to the frame for which i will be using BoxLayout ... is it possible in the first place ??
import javax.swing.*;
import java.awt.event.*;
import java.awt.Graphics;
public class JForm1 extends JFrame
{
public JForm1()
{
init();
}
public static void main(String[] args)
{
JForm1 form = new JForm1();
}
public void init()
{
JFrame frame = new JFrame("My Form 1");
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
JLabel label = new JLabel("Enter your Name : ");
panel MyPanel = new panel();
frame.getContentPane().add(label);
frame.getContentPane().add(MyPanel);
frame.setVisible(true);
}
}
class panel extends JPanel implements ActionListener
{
JButton submitButton;
JTextField text;
panel()
{
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
}
public void paintComponent(Graphics g)
{
text = new JTextField("Enter Name here");
text.setSize(100,25);
submitButton = new JButton("Submit");
submitButton.setSize(50,90);
submitButton.setBounds(200, 0, 80, 80);
submitButton.addActionListener(this);
this.add(text);
this.add(submitButton);
}
public void actionPerformed(ActionEvent event)
{
if(event.getSource()==submitButton)
{
System.out.println("The Entered Name is : "+text.getText());
}
}
}
What is this ?:
public void paintComponent(Graphics g)
{
text = new JTextField("Enter Name here");
text.setSize(100,25);
submitButton = new JButton("Submit");
submitButton.setSize(50,90);
submitButton.setBounds(200, 0, 80, 80);
submitButton.addActionListener(this);
this.add(text);
this.add(submitButton);
}
This code has nothing to do in paintComponent. paintComponent is about "painting a component", ie, paint a rectangle, draw a line, fill an oval, etc... This is absolutely not the place where to add your components. Instead, call that code in your constructor.
Additionally, if you are using LayoutManager's (which you should), calling setSize/setBounds/setLocation is useless (dimply remove those calls).
A few more things:
If you override paintComponent, make sure to invoke the super-method
Don't extends JFrame if not needed (here it is clearly not needed)
Follow Java naming conventions (class names should start with an UpperCase letter, variables and methods with a lowerCase letter)
All Swing-related code must be called on the EDT. Start your UI within a SwingUtilities.invokeLater() block.
Try by changing layout to FlowLayout for mypanel.
mypanel.setLayout(new FlowLayout());
I have this piece of code and read that validate can refer to laying out a container's subcomponents. "Layout-related changes, such as setting the bounds of a component, or adding a component to the container, invalidate the container automatically." (source: javadoc).
However, I see no difference whatsoever between keeping validate() or removing it from this little piece of code.
Can you show me a convincing example where you can see distinct behaviour in two cases (with or without validate) to prove a point? Any other comments/advice appreciated.
public class Sw1
extends JApplet
{
JLabel lbl;
public void init()
{
lbl = new JLabel ("a label");
JPanel pan = (JPanel) getContentPane ();
pan.add(lbl);
validate();
}
}
Here is the program after I intended the push of a button to add a label. It renders an exception when I push the button:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class Sw_test
extends JApplet
implements ActionListener
{
JLabel lbl;
JButton bt ;
JPanel pan ;
JLabel l;
public void init()
{
lbl = new JLabel ("label 1");
bt = new JButton ("go ahead, press me");
bt.addActionListener(this);
JPanel pan = (JPanel) getContentPane ();
pan.setLayout(new FlowLayout());
pan.add(lbl);
pan.add(bt);
validate();
}
public void actionPerformed(ActionEvent ev)
{
l = new JLabel("new label");
pan.add(l);
}
}
You would need to call it if you add a component to a panel after it has been initialized and made visible.
Try adding a button to your applet, and on the click of the button, add a new label to the applet.
i will quote the API:
The validate method is used to cause a container to lay out its subcomponents again. It should be invoked when this container's subcomponents are modified (added to or removed from the container, or layout-related information changed) after the container has been displayed.
so as you see, it is important if you modify your layout, AFTER it has been initialized.
That is the reason why you donĀ“t see any difference
btw: here is your example :
public class TestFrame extends JFrame{
private JButton b = new JButton();
public TestFrame() {
this.setLayout(new GridLayout(5,5));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TestFrame.this.add(new JLabel("whatever"));
//try it with and without
//validate();
}
});
this.setSize(300, 300);
this.setVisible(true);
}
public static void main(String[] args) {
new TestFrame();
}
}
I currrently have a SwingWorker that sends a HTTP Request and I override the SwingWorker's done() method to change contents in a JFrame. I want to basically remove everything and add a new members panel on the JFrame depending on the values returned from the Server.
Now, the problem I am facing is that when I invoke the following methods below on the JFrame, it doesn't remove anything from the JFrame nor does it change it's contents contained within the Frame.
//TODO: Investigate why JFrame content pane won't repaint.
f.removeAll();
//Pass the frame f reference only into MainDisplay, it doesn't actually do anything apart from allowing a class to add a JMenuBar on the JFrame.
f.add(new MainDisplay(f));
f.getContentPane().invalidate();
f.getContentPane().validate();
f.getContentPane().repaint();
The current fix I have is this below but I would rather change the contents of the JFrame rather then loading a new one up.
f.dispose();
f=new ApplicationFrame();
I've looked through previous answers on here and on Google and some state use validate() or invalidate() whilst calling repaint() to repaint the JFrame.
Any suggestions/help would be much appreciated.
Edit: I think I am going to debug more since there must be something else going wrong.
for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame {
private static final long serialVersionUID = 1L;
public MyFrame() {
final JPanel parentPanel = new JPanel();
parentPanel.setLayout(new BorderLayout(10, 10));
final JPanel childPanel1 = new JPanel();
childPanel1.setBackground(Color.red);
childPanel1.setPreferredSize(new Dimension(300, 40));
final JPanel childPanel2 = new JPanel();
childPanel2.setBackground(Color.blue);
childPanel2.setPreferredSize(new Dimension(800, 600));
JButton myButton = new JButton("Add Component ");
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
parentPanel.remove(childPanel1);
parentPanel.add(childPanel2, BorderLayout.CENTER);
parentPanel.revalidate();
parentPanel.repaint();
pack();
}
});
setTitle("My Empty Frame");
setLocation(10, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
parentPanel.add(childPanel1, BorderLayout.CENTER);
parentPanel.add(myButton, BorderLayout.SOUTH);
add(parentPanel);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame myFrame = new MyFrame();
}
});
}
}
You are trying to repaint()/validate() the ContentPane. Did you try doing same on the JFrame?
You can also try JFrame#pack().
modification of your code
f.setContentPane(new MainDisplay(f));
f.getContentPane().invalidate();
f.getContentPane().validate();
f.getContentPane().repaint();
You may try using Frame.pack() again it worked for me. Or try one od those following methods:
Frame.setOpaque(false);
Frame.setEnabled(false);
Frame.setVisible(false);
Frame.removeAll();