getContentPane and linking GUIs together - java

I'm having trouble with getContentPane() in my GUI.
public class CryptoMainMenu extends JPanel implements ActionListener {
public CryptoMainMenu()
{
Templates template = new Templates();
//setting up the primary panel
primaryPanel = new JPanel();
primaryPanel.setLayout(new BorderLayout());
//setting up algorithm button
algorithm = new JButton("Algorithm");
algorithm.addActionListener(this);
add(primaryPanel);
setSize(730, 400);
}
}
public class CryptoCategoriesMenu extends JFrame implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == back)
{
CryptoMainMenu main = new CryptoMainMenu();
main.setVisible(true);
this.setVisible(false);
}
}
}
In CryptoMainMenu if I'm extending JPanel I can't use getContentPane().add(primaryPanel), but if I just have add(primaryPanel), then my program isn't working because I linked all of my GUI classes together, so that when it gets to CryptoCategoriesMenu, and if I try pressing the JButton back, CryptoMainMenu shows as blank window. Is there something similar to getContentPane() that I can use with JPanel?
Edit:
This is suppose to a menu type GUI. In CryptoMainMenu, it displays a GUI where the user can press a button and it leads to another GUI which is CryptoCategoriesMenu. In CryptoCategoriesMenu, it shows another set of buttons and one of them is back. When I just have add() and I press back, CryptoMainMenu doesn't show up and that's the problem I'm having.

Related

Show or hide a button in a J frame form using another Jframe form

Please help.
In my java project I'm taking user inputs from Jframe form "interface" and press the "check btn". Then new Jframe form "CheckEntry" popups to show whether the entered data is correct. In "CheckEntry" form there is a confirm button. When the confirm button pressed I need to dissappear the "check btn in form Interface" and show the "save button" to send the data to the database.
First I hide the save button in form "Interface"
public Interface() {
initComponents();
conn = db.java_db();
Toolkit toolkit = getToolkit();
Dimension size = toolkit.getScreenSize();
setLocation(size.width/2 - getWidth()/2,size.height/2 - getHeight()/2);
btn_save.setVisible(false);
}
Then in "CheckEntry form", event confirm btn pressed I set the check btn to dissappear and show the save button
private void btn_confirm ActionPerformed(java.awt.event.ActionEvent evt) {
Interface i = new Interface();
i.btn_chk.setVisible(false);
i.btn_save.setVisible(true);
this.dispose();
}
This is not making any change to the form Interface. Please help. Thank You.
Your problem is here:
private void btn_confirm ActionPerformed(java.awt.event.ActionEvent evt) {
Interface i = new Interface(); // ***** HERE *****
i.btn_chk.setVisible(false);
i.btn_save.setVisible(true);
this.dispose();
}
The problem is that while this code does make a JButton invisible in an Interface object, it is the wrong Interface object since it is one that has been newly created in this class and is not the one that is visible to the user.
A solution is to not do this, not create a new instance but to rather pass the correct visualized instance into the child window where it can be acted upon, and where its state change can be shown to the user.
So you can pass the correct instance into the child window class when you create the child window, and assign the parent window class to a variable, and then you can change it as needed.
Side note: the child window should be a JDialog, likely a modal JDialog and not another JFrame.
For example:
import java.awt.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class MainForm extends JFrame {
private CheckEntryForm checkEntryForm = new CheckEntryForm(this);
private JButton showCheckEntryDialogBtn = new JButton("Show Check Entry Form");
private JButton saveEntryBtn = new JButton("Save");
private JPanel mainPanel = new JPanel();
public MainForm() {
super("Main GUI");
setDefaultCloseOperation(EXIT_ON_CLOSE);
showCheckEntryDialogBtn.addActionListener(e -> {
checkEntryForm.setVisible(true);
});
saveEntryBtn.setVisible(false);
mainPanel.add(showCheckEntryDialogBtn);
mainPanel.add(saveEntryBtn);
mainPanel.setPreferredSize(new Dimension(400, 300));
add(mainPanel);
pack();
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new MainForm().setVisible(true));
}
public void entryCheckOK() {
showCheckEntryDialogBtn.setVisible(false);
saveEntryBtn.setVisible(true);
// let the layout managers do their thing...
// and also remove dirty pixels
mainPanel.revalidate();
mainPanel.repaint();
}
}
#SuppressWarnings("serial")
class CheckEntryForm extends JDialog {
private MainForm mainForm;
private JButton confirmBtn = new JButton("Confirm");
public CheckEntryForm(MainForm mainForm) {
super(mainForm, "Check Entry", ModalityType.APPLICATION_MODAL);
this.mainForm = mainForm;
confirmBtn.addActionListener(e -> confirmAction());
JPanel mainPanel = new JPanel();
mainPanel.add(confirmBtn);
mainPanel.setPreferredSize(new Dimension(300, 200));
add(mainPanel);
pack();
setLocationRelativeTo(mainForm);
}
private void confirmAction() {
mainForm.entryCheckOK();
dispose();
}
}
Explanation
Here, the child window is a dialog window, a JDialog to be precise:
class CheckEntryForm extends JDialog {
Also, I pass a reference of the MainForm main GUI into this dialog when and where I create it:
private CheckEntryForm checkEntryForm = new CheckEntryForm(this);
and use it to set a field in the child window class:
class CheckEntryForm extends JDialog {
private MainForm mainForm;
private JButton confirmBtn = new JButton("Confirm");
public CheckEntryForm(MainForm mainForm) {
super(mainForm, "Check Entry", ModalityType.APPLICATION_MODAL);
this.mainForm = mainForm; // **** here ***
Then in the child button's ActionListener, I call a public method of the main Window, one that deletes the button, and re-sets the layout managers of the container:
in child window:
private void confirmAction() {
mainForm.entryCheckOK();
dispose();
}
in the main window:
public void entryCheckOK() {
showCheckEntryDialogBtn.setVisible(false);
saveEntryBtn.setVisible(true);
// let the layout managers do their thing...
// and also remove dirty pixels
mainPanel.revalidate();
mainPanel.repaint();
}
Some side recommendations:
Better to use a CardLayout to swap views rather than to show/hide or remove components directly.
Better to avoid extending JFrame or JDialog directly but rather to extend or create JPanels since this will result in much more flexible code.

Is there a better way to have JPanels communicate?

I'm working on a game which consists entirely of menus/screens which you interact with using buttons, essentially a text-based game but without the typing. To do this I have been working with Swing to create a basic UI, following this video series.
In order to have actions performed in one panel affect the state of another, I have followed the tutorial and created a UIListener interface, which extends EventListener. When a button is pressed in one JPanel, the fireUIEvent method of the panel is called, which in turn calls the sole method of the interface, uiEventOccurred, which is implemented in an anonymous class inside the main JFrame class. Then the JFrame can do whatever it wants with the event, and modify other JPanels it contains accordingly.
For example, I have a panel that represents the town. It has a button you click to travel to the dungeon. When this button is clicked, the town panel is replaced by the dungeon panel, which has a button you can click to return to the town.
I'll post the relevant classes:
the main frame class
public class GameMainFrame extends JFrame{
public JPanel rightPanel;
public GameMainFrame(String title) {
super(title);
/* Setting The Overall Layout */
setLayout(new BorderLayout());
/* Creating Individual UI Panels */
UIPanel uip_town = new Town_UI();
UIPanel uip_dung = new Dungeon_UI();
/* Creating A Nested Panel */
rightPanel = new JPanel();
rightPanel.setLayout(new BorderLayout());
rightPanel.add(uip_text, BorderLayout.WEST);
rightPanel.add(uip_town, BorderLayout.NORTH);
/* Creating A Listener To React To Events From The UI Panels */
uip_town.addUIListener(new UIListener() {
public void uiEventOccurred(UIEvent event) {
System.out.println("event text: " + event.getText());
if (event.getText().equals("goto_dungeon")) {
rightPanel.remove(uip_town);
rightPanel.add(uip_dung, BorderLayout.NORTH);
validate();
} else if (event.getText().equals("goto_town")) {
rightPanel.remove(uip_dung);
rightPanel.add(uip_town, BorderLayout.NORTH);
validate();
}
}
});
/* Adding Panels To The Content Pane Of The Frame */
Container c = getContentPane();
c.add(uip_info, BorderLayout.WEST);
c.add(rightPanel, BorderLayout.CENTER);
}
}
UIPanel class
public class UIPanel extends JPanel {
private EventListenerList listenerList;
public UIPanel() {
listenerList = new EventListenerList();
}
public void fireUIEvent(UIEvent event) {
Object[] listeners = listenerList.getListenerList();
for (int i = 0; i < listeners.length; i += 2) {
if (listeners[i] == UIListener.class) {
((UIListener) listeners[i + 1]).uiEventOccurred(event);
}
}
}
public void addUIListener(UIListener listener) {
listenerList.add(UIListener.class, listener);
}
public void removeUIListener(UIListener listener) {
listenerList.remove(UIListener.class, listener);
}
}
Town_UI class
public class Town_UI extends UIPanel {
public Town_UI() {
Dimension size = getPreferredSize();
size.height = 466;
setPreferredSize(size);
setBorder(BorderFactory.createTitledBorder("Town"));
JButton btn_dungeon_enter = new JButton("Enter the dungeon");
add(btn_dungeon_enter);
btn_dungeon_enter.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireUIEvent(new UIEvent(this, "goto_dungeon"));
}
});
}
}
Dungeon_UI class
public class Dungeon_UI extends UIPanel {
public Dungeon_UI() {
Dimension size = getPreferredSize();
size.height = 466;
setPreferredSize(size);
setBorder(BorderFactory.createTitledBorder("Dungeon"));
JButton btn_town_return = new JButton("Return to town");
add(btn_town_return);
btn_town_return.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireUIEvent(new UIEvent(this, "goto_town"));
}
});
}
}
UIEvent object
public class UIEvent extends EventObject {
private String text;
public UIEvent(Object source, String text) {
super(source);
this.text = text;
}
public String getText() {
return text;
}
}
UIListener interface
public interface UIListener extends EventListener {
public void uiEventOccurred(UIEvent e);
}
I have two problems with this. Number one, it is currently bugged. When I run the application, the Town_UI panel appears with its button "Enter the dungeon", and upon clicking on it the frame correctly updates, replacing the Town_UI panel with the Dungeon_UI panel. However, clicking on the "Return to town" button on the dungeon panel doesn't do anything. When trying to debug this I found that the cause was in the UIPanel method fireUIEvent. When the "Return to town" button is pressed, this method is correctly called, but when it creates the Object array using getListenerList, the array is empty, so it skips the for-loop and no action is performed. Because I am unfamiliar with ActionEvents and EventListeners in Java, though, I am not sure how to fix this.
My other problem is that all of the behaviors that occur when a button is pressed are handled in the anonymous class in the GameMainFrame class. This means that if I want to have a bunch of different buttons all do different things (which I do plan on implementing), I'll need a whole bunch of conditionals in the anonymous class to determine what button is pressed and perform the corresponding behavior. I feel like it would be a lot cleaner if the button behavior could be implemented in the anonymous ActionListener class of each button, but I'm not sure how I should restructure my code so that I can do this but also allow any action on any panel able modify any other panel.
In the tutorial I watched he claimed that this implementation of EventListeners was what you should do in order to avoid making your code a rat's nest, but it seems like that is where my code is heading if I use this implementation for what I am trying to do.

Swing - Dispose a frame [duplicate]

This question already has answers here:
The Use of Multiple JFrames: Good or Bad Practice? [closed]
(9 answers)
Closed 7 years ago.
My aim is for an action listener to close a specific JFrame when the user hits the JButton to quit.
Overall, when the program starts a large JFrame opens then a small one in front....in my code the user enters some details in this small one and hits submit(for the sake of simplicity, ive omitted this code here and replaced submit with quit)
So when this quit buttons pressed. I expect this small JFrame to close. I can't seem to figure this out. The action listeners in a different class and ive tried making instances and had no luck. I've commented out the code I've tried below when attempting to solve this issue.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class test
{
public static void main(String Args[])
{
makeGUI m = new makeGUI();
}
}
class makeGUI
{
JButton close = new JButton("CLOSE ME");
makeGUI()
{
frame f1 = new frame();
JFrame smallframe = new JFrame(); //want to close this one
JPanel jp = new JPanel(new FlowLayout());
smallframe.setSize(300,300);
smallframe.setLocationRelativeTo(null);
smallframe.setDefaultCloseOperation(smallframe.DISPOSE_ON_CLOSE);
close.addActionListener(new action());
jp.add(close);
smallframe.add(jp);
smallframe.setVisible(true);
}
class action implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//makeGUI s1 = new makeGUI();
if (e.getSource () == close)
{
//s1.smallframe.dispose();
System.out.println("gotcha");
}
}
}
}
class frame extends JFrame
{
frame ()
{
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("big one");
setVisible(true);
}
}
First, it's not a good practice to name classes with a lowercase, so try renaming to something like MakeGUI instead of makeGUI.
The problem with your commented code is that it creates a new instance of makeGUI every time the button is clicked and the action listener is invoked. The result is that when you click on the close button, a new frame is created, then an inner one and this inner one gets immediately closed. The only thing you'd be doing is creating more and more frames. You should keep the instance as a state, for instance as a class member:
class MakeGUI {
JFrame smallframe;
JButton close = new JButton("CLOSE ME");
MakeGUI() {
frame f1 = new frame();
smallframe = new JFrame(); //want to close this one
JPanel jp = new JPanel(new FlowLayout());
smallframe.setSize(300, 300);
smallframe.setLocationRelativeTo(null);
smallframe.setDefaultCloseOperation(smallframe.DISPOSE_ON_CLOSE);
close.addActionListener(new action());
jp.add(close);
smallframe.add(jp);
smallframe.setVisible(true);
}
class action implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == close) {
// use this instead of dispose
smallframe.dispatchEvent(new WindowEvent(smallframe, WindowEvent.WINDOW_CLOSING));
System.out.println("gotcha");
}
}
}
}
If you want to simulate someone pressing the [X] button then you can use this code to programmatically trigger this event:
smallFrame.dispatchEvent(new WindowEvent(smallFrame, WindowEvent.WINDOW_CLOSING));
Aside from that, your code is not working because you are not closing your instance of the small window, instead you are creating another instance and disposing of it. Inside your close event you should be closing the smallFrame instance.
You can do this by either passing your JFrame to the constructor of your ActionListener or making smallFrame a class variable.
It appears you are using the small JFrame as a pop up to get information or display information. If so, you may want to look into the JOptionPane class which is made for "Dialogue Boxes".
Documentation:
http://docs.oracle.com/javase/7/docs/api/javax/swing/JOptionPane.html

Where have I messed up regarding creating a Game Menu?

I am trying to create a basic game menu for a game right now. I am just testing out the menu for now, and most of the options I wrote are just to test out whether the menu actually works or not. So I have a Menu class and a OptionPanel class as well.
Here is the Menu Class:
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
public class Main extends JFrame {
JPanel cardPanel;
public Main(String title) {
super(title);
setBounds(100, 100, 800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cardPanel = new JPanel();
CardLayout cl = new CardLayout();
cardPanel.setLayout(cl);
OptionPanel panel1 = new OptionPanel(this);
Board panel2 = new Board();
Rules panel3 = new Rules();
cardPanel.add(panel1,"1");
cardPanel.add(panel2,"2");
cardPanel.add(panel3,"3");
add(cardPanel);
setVisible(true);
}
public static void main(String[] args)
{
Main w = new Main("AP Animation Demo");
}
public void changePanel() {
((CardLayout)cardPanel.getLayout()).next(cardPanel);
requestFocus();
}
}
And here is my Option Panel class:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class OptionPanel extends JPanel implements ActionListener {
Main w;
public OptionPanel(Main w) {
this.w = w;
JButton button = new JButton("Press me!");
button.addActionListener(this);
add(button);
JButton button2 = new JButton("Game rules");
button2.addActionListener(this);
add(button2);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.BLACK);
}// Call JPanel's paintComponent method to paint the background
public void actionPerformed(ActionEvent e) {
w.changePanel();
}
}
How do I make it so when the menu pops up, I can click on one button that leads to the game, and when clicking on another button, get linked to another screen. I think it has something to do with the actionPerformed thing, so I tried adding if (e.getSource == button) and stuff like that, but it could not find any button variable. Any advice/feedback?
If you want the actionPerformed() method to be able to access a button variable, then the variable has to have an instance scope (or static, less preferable almost always). Referring to it in the method as you have it written won't work because the button variable is local to the constructor.
The suggestion in the comments is to make a separate ActionListener for each button; you only need to use the if (e.getSource() == button) if the one actionPerformed() method is getting called for multiple buttons. The difference between these is a little much for a SO answer; you can get a tutorial on action listeners in the Java tutorials at Oracle.
The way you have started above suggests you are going to use the OptionPanel as a single action listener for all buttons, and therefore it needs to test which button invoked it. If instead you have a separate action listener for each button, then it knows which button invoked it and doesn't need to test.
Try looking up "anonymous inner classes" as they relate to action listeners in Java.

Difficulty removing all components from a Jpanel

G'day all,
I am coding a main menu for a project. The menu displays properly. I have also set up ActionListeners for the three buttons on the menu.
What I wish to do is reuse the JPanel for a new set of radio buttons when the user chooses "Start a New Game".
However, coding ActionPerformed to remove the existing components from the JPanel has me stumped. I know removeAll is somehow important, but unfortunately NetBeans informs me I cannot call it on my mainMenu JPanel object within ActionPerformed. So i have commented it out in my code below, but left it in so you can see what I am trying to do.
Your thoughts or hints are appreciated.
Here is my main code:
public class Main {
public static void main(String[] args) {
MainMenu menu = new MainMenu();
menu.pack();
menu.setVisible(true);
}
}
Here is my mainMenu code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MainMenu extends JFrame implements ActionListener {
JButton startNewGame = new JButton("Start a New Game");
JButton loadOldGame = new JButton("Load an Old Game");
JButton seeInstructions = new JButton("Instructions");
public MainMenu() {
super("RPG Main Menu");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainMenu = new JPanel();
mainMenu.setLayout(new FlowLayout());
startNewGame.setMnemonic('n');
loadOldGame.setMnemonic('l');
seeInstructions.setMnemonic('i');
startNewGame.addActionListener(this);
loadOldGame.addActionListener(this);
seeInstructions.addActionListener(this);
mainMenu.add(startNewGame);
mainMenu.add(loadOldGame);
mainMenu.add(seeInstructions);
setContentPane(mainMenu);
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == startNewGame) {
// StartNewGame code goes here
// mainMenu.removeAll();
}
if (source == loadOldGame) {
// LoadOldGame code goes here
}
if (source == seeInstructions) {
// Quit code goes here
}
}
}
Consider using a CardLayout instead, which manages two or more components (usually JPanel instances) that share the same display space. That way you don't have to fiddle with adding and removing components at runtime.
You need mainMenu to be a member variable:
public class MainMenu extends JFrame implements ActionListener {
JButton startNewGame = new JButton("Start a New Game");
JButton loadOldGame = new JButton("Load an Old Game");
JButton seeInstructions = new JButton("Instructions");
JPanel mainMenu = new JPanel();
Why do you feel the need to re-use this object?
You don't have a reference to mainMenu actionPerformed use. If you declare mainMenu with the buttons. It would work.
The problem is that the actionPerformed method is trying to call the JPanel mainMenu which is out of scope, i.e. the mainMenu variable is not visible from the actionPerformed method.
One way to get around this is to have the JPanel mainMenu declaration in the class itself and make it an instance field which is accessible to all instance methods of the class.
For example:
public class MainMenu extends JFrame implements ActionListener
{
...
JPanel mainMenu;
public MainMenu()
{
...
mainMenu = new JPanel();
...
}
public void actionPerformed(ActionEvent e)
{
...
mainMenu.removeAll();
}
}
Avoid attempting to "reuse" stuff. Computers are quite capable of tidying up. Concentrate on making you code clear.
So instead of attempting to tidy up the panel, simply replace it with a new one.
Generally a better way to write listeners is as anonymous inner classes. Code within these will have access to final variables in the enclosing scope and to members of the enclosing class. So, if you make mainMenu final and you ActionListeners anonymous inner classes, your code should at least compile.
Also don't attempt to "reuse" classes. Try to make each class do one sensible thing, and avoid inheritance (of implementation). There is almost never any need to extend JFrame, so don't do that. Create an ActionListener for each action, rather than attempting to determine the event source.
Also note, you should always use Swing components on the AWT Event Dispatch Thread. Change the main method to add boilerplate something like:
public static void main(final String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
runEDT();
}});
}

Categories

Resources