Only one component shows up in JFrame - java

As an improvement to my encryption project I decided to make a little GUI. However, when I run the program, only the top element shows up on the screen and it appears to obscure the others, though I have no way of checking. Does anyone know why?
Below is my code in its entirety besides e() and d() because those simply encrypt a string and have nothing to do with a GUI. I would also like a way to speed it up as much as possible without editing the encryption, just to make it as great as possbile.
#SuppressWarnings("serial")
public class EncDecExample extends JFrame implements ActionListener {
final static JPanel top = new JPanel();
final static JPanel mid = new JPanel();
final static JPanel bot = new JPanel();
final static JTextField in = new JTextField(10);
final static JTextField out = new JTextField(10);
final static JButton enc = new JButton("Encrypt");
final static JButton dec = new JButton("Decrypt");
final static JFrame f = new JFrame("Encryption/decryption");
public static void main(String[] args) {
// EncDec.exampleImplement();
f.setSize(500, 500);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
out.setEditable(false);
out.setText("Hello");
in.setVisible(true);
out.setVisible(true);
enc.setVisible(true);
dec.setVisible(true);
top.add(in);
mid.add(enc);
mid.add(dec);
bot.add(out);
f.add(top);
f.add(mid);
f.add(bot);
f.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == enc && !in.getText().equalsIgnoreCase("")) {
out.setText(EncDec.e(in.getText(), 5));
}
else if(e.getSource() == dec && !in.getText().equalsIgnoreCase("")) {
out.setText(EncDec.d(in.getText()));
}
}
}

The content pane of a JFrame has a BorderLayout. If you place a component in a BL with no constraints it ends up in the CENTER. The center can only display one component.
For an immediate effect, I suggest:
f.add(top, BorderLayout.PAGE_START);
f.add(mid);
f.add(bot, BorderLayout.PAGE_END);
Other points.
Take out f.setSize(500, 500); and call pack() immediately before setVisible(true)
For a better way to end the GUI, change f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); to f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
in.setVisible(true); Except for the frame itself, take these out. A component automatically becomes visible when it is added to a top level container and that container is itself made visible.
Change public class EncDecExample extends JFrame to public class EncDecExample This code keeps a reference to a frame, and that is the right way to go.

Related

Assigning current JPanel to new instance of JPanel but does not refresh

I have sub-classed JPanel to provide a generic JPanel container that contains options for a filter selected from a JComboBox.
When the JComboBox is changed from one filter to another, I have a switch statement that checks which filter is now selected and reassigns the "options" JPanel to a new instance of the options class associated with that filter:
public void setFilterOptions(String choice){
switch(choice){
case "Gaussian": options = new GaussianFilterOptions();break;
case "Sobel": options = new SobelFilterOptions();System.out.println("?");break;
}
}
The problem is that the JPanel "options" does not get refreshed in the GUI after setFilterOptions is called. Whichever filter is set to show by default appears upon startup and remains even if I switch the JComboBox selection. I have tried repainting, revalidating, and validating "options" as well as the JPanel containing "options" and the JFrame enclosing the entire application.
I added print statements in each case to verify that they were working when the combo box is switched and not falling through, so I'm sure that is not the problem.
You're confusing variable with object. You have likely originally placed a JPanel object that options referred to into your GUI, but understand, you didn't place the options variable into the GUI, but rather (and again) the JPanel object that it referred to into the GUI.
If later you change the JPanel that the options variable refers to, this will have no effect on the GUI, since it still holds the same original JPanel object that it held before. If you want to change the JPanel displayed, you have to do that directly by swapping out JPanels in the GUI. This is best accomplished by using a CardLayout.
e.g.,
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SwapPanels extends JPanel {
private static final String GAUSSIAN = "Gaussian";
private static final String SOBEL = "Sobel";
private static final String[] FILTER_OPTIONS = {GAUSSIAN, SOBEL};
private CardLayout cardLayout = new CardLayout();
private JPanel cardHolderPanel = new JPanel(cardLayout);
private JPanel gaussianPanel = new JPanel();
private JPanel sobelPanel = new JPanel();
private JComboBox<String> filterCombo = new JComboBox<>(FILTER_OPTIONS);
public SwapPanels() {
JPanel comboPanel = new JPanel();
comboPanel.add(filterCombo);
filterCombo.addActionListener(new ComboListener());
gaussianPanel.add(new JLabel("Gaussian Filtering Done Here"));
sobelPanel.add(new JLabel("Sobel Filtering Done Here"));
cardHolderPanel.add(gaussianPanel, GAUSSIAN);
cardHolderPanel.add(sobelPanel, SOBEL);
int gap = 50;
cardHolderPanel.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new BorderLayout());
add(cardHolderPanel, BorderLayout.CENTER);
add(comboPanel, BorderLayout.PAGE_END);
}
private class ComboListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String key = (String) filterCombo.getSelectedItem();
cardLayout.show(cardHolderPanel, key);
}
}
private static void createAndShowGui() {
SwapPanels mainPanel = new SwapPanels();
JFrame frame = new JFrame("SwapPanels");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also you could do it like this instead of the switch
public void setFilterOptions(String choice){
options = (choice.equals("Gaussian"))? new GaussianFilterOptions():
new SobelFilterOptions();
}
}

How to display one Jframe at a time? [duplicate]

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).

How do I display multiple JPanels with multiple layouts?

I've been working on this project for an assignment and I've been stuck on this problem. I new and don't understand much of the programming jargon so if someone could help explain why my program isn't working that would be great.
The programs purpose is to display a randomly generated matrix of 1's and 0's in a 10x10 layout and have some buttons on the top that have functions. I'm just stock on how to get everything to display.
Thanks in advance.
UPDATE:: Told providing all my code would help
public class Module5 extends JFrame {
private static JTextArea area = new JTextArea();
private static JFrame frame = new JFrame();
private static JPanel general = new JPanel();
private static JPanel buttons = new JPanel();
private static JPanel numbers = new JPanel();
private static JButton button0 = new JButton("Reset to 0");
private static JButton button1 = new JButton("Resset to 1");
private static JButton buttonReset = new JButton("Reset");
private static JButton quit = new JButton("Quit");
public static class Numbers extends JPanel {
public Numbers() {
area.setText(Integer.toString((int) Math.round(Math.random())));
this.add(area);
}
public void Module5(){
numbers.setLayout(new GridLayout(10, 10));
for (int i = 0; i < 100; i++) {
this.add(new Numbers());
}
}
}
public static void main (String[] args) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
general.setLayout(new BoxLayout(general, BoxLayout.Y_AXIS));
general.add(buttons);
general.add(numbers);
buttons.add(button0);
buttons.add(button1);
buttons.add(buttonReset);
buttons.add(quit);
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
}
}
Since this does look like homework I'll give you some pointers but am not going to give you the code.
Move your constructor for Module5 out of the numbers class and into its own class. Also remove the void return type from this to make it a correct constructor.
Move the code in your main into the constructor for Module5. This is the main frame so when you build a new one it should be initialised here, not in main. And remove the setVisible call for now (this is addressed in number 6)
After doing 1 and 2, get rid of your frame variable, your Module5 is a JFrame so anything to do with frame can just be changed to the keyword this (meaning this Module5 object)
Also move the area variable to be within the Numbers class - otherwise every Number is essentially going to share the same text area and This is not what you want.
Don't have your variables as static they should not need to be.
Once this is all done make sure it is running on the Event Dispatch Thread by making your main method like this (the one piece of code I will give you)
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
Module5 mod5 = new Module5();
mod5.setVisible(true);
}
});
}

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);

JFrame removing JPanels and adding a new JPanel

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();

Categories