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();
Related
I am trying to make a panel showing a printed statement "Hello World!" and an OK button. Neither will show up on the panel and I have no idea why. I started with a block of code that was supposed to create just a blank popup. The blank popup worked great. I can't add the string or button and see them. I have tried calling paintComponent. I have tried adding the content to the panel. Does anyone know what I am missing?
Here is my code
package painting;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SwingPaintDemo1 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static class SwingPaintDemo extends JPanel{
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("Hello World!", 20,30);
}
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(250,250);
f.setVisible(true);
JButton okbutton = new JButton("OK");
ButtonHandler listener = new ButtonHandler();
okbutton.addActionListener(listener);
SwingPaintDemo displayPanel = new SwingPaintDemo();
JPanel content = new JPanel();
content.setLayout(new BorderLayout());
content.add(displayPanel, BorderLayout.CENTER);
content.add(okbutton, BorderLayout.SOUTH);
}
private static class ButtonHandler implements ActionListener{
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
}
You forgot to add the JPanel to the JFrame. Just add the following line at the bottom of your createAndShowGUI() method:
f.add(content);
I would also recommend moving your f.setVisible(true); line to the bottom of the method just to be safe. When you make the frame visible, the component tree is set up to take into account all the components added to the JFrame. If you add more components after that, you will need to do either manually revalidate the tree or do something that triggers an automatic revalidation. I'm assuming you're not revalidating your tree anywhere, so you should move f.setVisible(true); to after all the components are added.
I'm trying to make a little game that will first show the player a simple login screen where they can enter their name (I will need it later to store their game state info), let them pick a difficulty level etc, and will only show the main game screen once the player has clicked the play button. I'd also like to allow the player to navigate to a (hopefully for them rather large) trophy collection, likewise in what will appear to them to be a new screen.
So far I have a main game window with a grid layout and a game in it that works (Yay for me!). Now I want to add the above functionality.
How do I go about doing this? I don't think I want to go the multiple JFrame route as I only want one icon visible in the taskbar at a time (or would setting their visibility to false effect the icon too?) Do I instead make and destroy layouts or panels or something like that?
What are my options? How can I control what content is being displayed? Especially given my newbie skills?
A simple modal dialog such as a JDialog should work well here. The main GUI which will likely be a JFrame can be invisible when the dialog is called, and then set to visible (assuming that the log-on was successful) once the dialog completes. If the dialog is modal, you'll know exactly when the user has closed the dialog as the code will continue right after the line where you call setVisible(true) on the dialog. Note that the GUI held by a JDialog can be every bit as complex and rich as that held by a JFrame.
Another option is to use one GUI/JFrame but swap views (JPanels) in the main GUI via a CardLayout. This could work quite well and is easy to implement. Check out the CardLayout tutorial for more.
Oh, and welcome to stackoverflow.com!
Here is an example of a Login Dialog as #HovercraftFullOfEels suggested.
Username: stackoverflow Password: stackoverflow
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
public class TestFrame extends JFrame {
private PassWordDialog passDialog;
public TestFrame() {
passDialog = new PassWordDialog(this, true);
passDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new TestFrame();
frame.getContentPane().setBackground(Color.BLACK);
frame.setTitle("Logged In");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
class PassWordDialog extends JDialog {
private final JLabel jlblUsername = new JLabel("Username");
private final JLabel jlblPassword = new JLabel("Password");
private final JTextField jtfUsername = new JTextField(15);
private final JPasswordField jpfPassword = new JPasswordField();
private final JButton jbtOk = new JButton("Login");
private final JButton jbtCancel = new JButton("Cancel");
private final JLabel jlblStatus = new JLabel(" ");
public PassWordDialog() {
this(null, true);
}
public PassWordDialog(final JFrame parent, boolean modal) {
super(parent, modal);
JPanel p3 = new JPanel(new GridLayout(2, 1));
p3.add(jlblUsername);
p3.add(jlblPassword);
JPanel p4 = new JPanel(new GridLayout(2, 1));
p4.add(jtfUsername);
p4.add(jpfPassword);
JPanel p1 = new JPanel();
p1.add(p3);
p1.add(p4);
JPanel p2 = new JPanel();
p2.add(jbtOk);
p2.add(jbtCancel);
JPanel p5 = new JPanel(new BorderLayout());
p5.add(p2, BorderLayout.CENTER);
p5.add(jlblStatus, BorderLayout.NORTH);
jlblStatus.setForeground(Color.RED);
jlblStatus.setHorizontalAlignment(SwingConstants.CENTER);
setLayout(new BorderLayout());
add(p1, BorderLayout.CENTER);
add(p5, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jbtOk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Arrays.equals("stackoverflow".toCharArray(), jpfPassword.getPassword())
&& "stackoverflow".equals(jtfUsername.getText())) {
parent.setVisible(true);
setVisible(false);
} else {
jlblStatus.setText("Invalid username or password");
}
}
});
jbtCancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
parent.dispose();
System.exit(0);
}
});
}
}
I suggest you insert the following code:
JFrame f = new JFrame();
JTextField text = new JTextField(15); //the 15 sets the size of the text field
JPanel p = new JPanel();
JButton b = new JButton("Login");
f.add(p); //so you can add more stuff to the JFrame
f.setSize(250,150);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Insert that when you want to add the stuff in. Next we will add all the stuff to the JPanel:
p.add(text);
p.add(b);
Now we add the ActionListeners to make the JButtons to work:
b.addActionListener(this);
public void actionPerforemed(ActionEvent e)
{
//Get the text of the JTextField
String TEXT = text.getText();
}
Don't forget to import the following if you haven't already:
import java.awt.event*;
import java.awt.*; //Just in case we need it
import java.x.swing.*;
I hope everything i said makes sense, because sometimes i don't (especially when I'm talking coding/Java) All the importing (if you didn't know) goes at the top of your code.
Instead of adding the game directly to JFrame, you can add your content to JPanel (let's call it GamePanel) and add this panel to the frame. Do the same thing for login screen: add all content to JPanel (LoginPanel) and add it to frame. When your game will start, you should do the following:
Add LoginPanel to frame
Get user input and load it's details
Add GamePanel and destroy LoginPanel (since it will be quite fast to re-create new one, so you don't need to keep it memory).
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).
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);
despite some tips, I'm still getting this one wrong. I end up with one basic window and another one with extra features, but without the basic ones from the previous window. Instead, I would like one new window combining the basic and new features. Here is the code I've got: (also which approach would you advise?)
package windows;
import java.awt.*;
import javax.swing.*;
public abstract class WindowTemplate extends JFrame {
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
public WindowTemplate () {
JFrame myFrame = new JFrame("My first window");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setVisible(true);
myFrame.setSize(550, 450);
myFrame.setLocationRelativeTo(null);
// JLabel emptyLabel = new JLabel("");
// emptyLabel.setPreferredSize(new Dimension(550, 450));
// myFrame.getContentPane().setLayout(new CardLayout());
// myFrame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
// myFrame.pack();
}
}
now the one that is meant to be "extended":
package windows;
import java.awt.*;
import javax.swing.*;
public class a_Welcome extends WindowTemplate {
public a_Welcome() {
JPanel area = new JPanel();
JLabel text = new JLabel("One line another line and another line"); // , JLabel.CENTER);
// text.setBounds(80, 400, 400, 50);
add(area);
// area.setLayout(null);
area.add(text, new CardLayout());
// area.add(text); // , BorderLayout.CENTER);
Font font = new Font("SansSerif", Font.BOLD, 30);
text.setFont(font);
text.setForeground(Color.green);
area.setBackground(Color.darkGray);
area.setSize(550, 450);
}
}
// timer-after 5 seconds-go to the next window (countdown in the bottom right corner)
and the main:
package windows;
public class Launcher {
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
// WindowTemplate.createWindow();
// a_Welcome.createWindow();
a_Welcome window = new a_Welcome();
window.setVisible(true);
}
});
}
}
-- Alternatively --
public class WindowTemplate extends JFrame {
// Constructor
public WindowTemplate() {
init();
}
public void init() {
// add basic components
JFrame myFrame = new JFrame("My first window");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setVisible(true);
myFrame.setSize(550, 450);
myFrame.setLocationRelativeTo(null);
}
}
and
public class a_Welcome extends WindowTemplate {
public a_Welcome() {
super();
}
#Override
public void init() {
super.init(); // important so you get the base stuff
// add other components
JPanel area = new JPanel();
JLabel text = new JLabel("One line another line and another line");
add(area);
area.add(text, new CardLayout());
Font font = new Font("SansSerif", Font.BOLD, 30);
text.setFont(font);
text.setForeground(Color.green);
area.setBackground(Color.darkGray);
area.setSize(550, 450);
}
}
Sorry for lots of code and thanks for your help!
I'm not quite sure what your problem is, but your WindowTemplate basically is a JFrame, so you don't want to create a new JFrame in your constructor but rather "apply" those method to this instead of myFrame.
Try something like this:
public WindowTemplate()
{
super("My first window");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // "this" is optional
setVisible(true);
setSize(550, 450);
setLocationRelativeTo(null);
}
and
public a_Welcome()
{
super(); // this is implicit, because a_Welcome extends WindowTemplate, which has got a constructor without parameters
//[add more stuff here]
}
When you're creating a new a_Welcome, its constructor will call the super constructor, which is WindowTemplate which will in turn call the JFrame constructor
First, although you extend JFrame, you create a new JFrame and use it in each constructor. It should be looking like that:
public WindowTemplate () {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setPreferredSize(new Dimension(550, 450));
this.pack();
this.setVisible(true);
Now, if you do it like that, you can add JComponents in each constructor / init method. Instead, you create two separate JFrames, one in each constructor.
I would recommend to avoid too deep hierarchy in case of swing components, since you will face many unexpected layout issues, what works for one, doesn't work for the other, when more components are added.
I think in your second example, in WindowTemplate, you're creating another JFrame when you think you're initializing the this JFrame.
Instead of
JFrame myFrame = new JFrame("My first window");
you probably want
super("My first window");
and then replace any myFrame references thereafter with this
If I read your code correctly, WindowTemplate is a JFrame. And within WindowTemplate's constructor you instantiate another JFrame? This does not make much sense. Instead of creating and configuring myFrame, you should configure this
public WindowTemplate () {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
...
}
as you are doing it in the subclass, where you are calling this.add(area)