In a sample program I have one class that places:
GUI components on a JPanel which is inside a JFrame.
A method makeMenu to create a menu bar
An ActionListener inside the makeMenu method to change the JPanels background color when called.
Main method.
public class GUI extends JFrame {
private JPanel jPanelRight;
private JPanel jPanelLeft;
JMenuBar menuBar;
JMenu file, help;
JMenuItem changeColor;
public GUI() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setJMenuBar(makeMenu()); // call constructor to create the menu
this.setSize(800, 600); // set frame size
this.setVisible(true); // display frame
this.setTitle("understanding objects");
setLayout(new BorderLayout()); // layout manager
jPanelLeft = new JPanel(); //left jpanel
jPanelLeft.setPreferredSize(new Dimension(400, 800)); // to set the size of the left panel
jPanelLeft.setBackground(Color.blue);
jPanelRight = new JPanel(); //right jpanel
jPanelRight.setPreferredSize(new Dimension(400, 600)); // to set the size of the right panel
jPanelRight.setBackground(Color.green);
this.add(jPanelLeft, BorderLayout.WEST); //add jpanel to the left side of the frame
this.add(jPanelRight, BorderLayout.EAST); //add jpanel to the right side of the frame
}//end constructor
public JMenuBar makeMenu() {
menuBar = new JMenuBar(); //menu bar
file = new JMenu("File"); //menu item
menuBar.add(file);
help = new JMenu("Help"); //menu item
menuBar.add(help);
changeColor = new JMenuItem("Change Colour"); //sub menu item
changeColor.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jPanelRight.setBackground(Color.red);
}
});
file.add(changeColor);
return menuBar;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GUI();
}
});
} // end
}//end class
I am trying to separate the code into 3 or 4 classes.
GUI class
ActionListener class
MakeMenu class
Main class (to run program)
one problem that keeps occurring is that i when i separate the code i can only change using System.out.println(); and can not change the GUI i.e. i can print out that the jPanelRight is now red but can not actually change the jPanelRight to red.
I am possibly going about this the wrong way.
A GUI to use a different class to create its menu and another different class to control the actions for the GUI's menu.
Related
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).
Main Class:
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Main extends JFrame {
public static void main(String[] args) {
JFrame frame = new JFrame("Checking Account Actions");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
CheckingAccountActions panel = new CheckingAccountActions();
MyWindowAdapter winAdapter = new MyWindowAdapter(panel);
frame.addWindowListener(winAdapter);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
} // Main()
class MyWindowAdapter extends WindowAdapter {
private CheckingAccountActions saved;
public MyWindowAdapter(CheckingAccountActions saved) {
this.saved = saved;
}
// in your window closing method
// check the state of checkActions first before doing anything
public void windowClosing(WindowEvent e) {
// note -- don't check for saved in a static way
// use a method on the instance.
if(!saved.saved) {
String message = "The data in the application is not saved.\n"
+ "Would you like to save it before exiting the
+ application?";
int confirm = JOptionPane.showConfirmDialog (null, message);
if (confirm == JOptionPane.YES_OPTION)
CheckingAccountActions.chooseFile(2);
}
JFrame frame = (JFrame)e.getSource();
frame.setVisible(false);
// Main.frame.setVisible(false);
System.exit(0);
}
} // MyWindowAdapter()
This class, as you see, extends JPanel and this is where my Menu items are initialized, but do I use Main class for this statement 'setJMenuBar(menuBar);', since it gives an error in CheckingAccountActions because JFrame is in MAIN.
CheckingAccountActions class:
public class CheckingAccountActions extends JPanel {
// Panel
private JLabel message;
// Menu
private JMenuBar menuBar;
private JMenu File;
private JMenuItem Read, Write;
private JMenu Account;
private JMenuItem NewAccount, ListAccounts, ListChecks, ListDeposits, FindAccount;
private JMenu Transactions;
private JMenuItem AddTransactions;
// code...
//
//
// code...
public CheckingAccountActions() {
//************************** PANEL *****************************************
// JLabel
message = new JLabel("Please choose one of the items: ");
message.setFont(new Font("Helvetica", Font.BOLD, 15));
CheckingAccountActionsListener listener = new CheckingAccountActionsListener();
//************************** MENU ******************************************
// Menu
File = new JMenu("File");
// MenuItem
Read = new JMenuItem("Read from file");
Write = new JMenuItem("Write to file");
// ActionListener
Read.addActionListener(listener);
Write.addActionListener(listener);
// Add Buttons to Menu
File.add(Read);
File.add(Write);
// Menu
Account = new JMenu("Account");
// MenuItem
NewAccount = new JMenuItem("Add new account");
ListAccounts = new JMenuItem("List accounts transaction");
ListChecks = new JMenuItem("List all checks");
ListDeposits = new JMenuItem("List all deposits");
FindAccount = new JMenuItem("Find an account");
// ActionListener
NewAccount.addActionListener(listener);
ListAccounts.addActionListener(listener);
ListChecks.addActionListener(listener);
ListDeposits.addActionListener(listener);
FindAccount.addActionListener(listener);
// Add Buttons to Menu
Account.add(NewAccount);
Account.add(ListAccounts);
Account.add(ListChecks);
Account.add(ListDeposits);
Account.add(FindAccount);
// Menu
Transactions = new JMenu("Transactions");
// MenuItem
AddTransactions = new JMenuItem("Add Transactions");
// ActionListener
AddTransactions.addActionListener(listener);
// Add Buttons to Menu
Transactions.add(AddTransactions);
// MenuBar
menuBar = new JMenuBar();
menuBar.add(File);
menuBar.add(Account);
menuBar.add(Transactions);
setBackground(Color.white);
setPreferredSize(new Dimension(240, 250));
setJMenuBar(menuBar);
}
private class CheckingAccountActionsListener implements ActionListener {
// code...
}
Edit: what I am confused about is how to add my MenuBar to the Frame while the Frame is in another class?
FINAL EDIT: I got it working. I just moved all my JFrame components to CheckingAccountActions class.
Take a look at the section from the Swing tutorial on How to Use Menus. The MenuDemo example will show you one way to structure your program.
It also shows you the proper way to create your GUI on the Event Dispatch Thread.
setJMenuBar(menubar) is not what you actually looking for. If you want to set the menubar to your frame, just add the menu bar to the frame with the method add(menuBar).
I'm trying to center a JMenu's popup so I can use it on a JPanel and it doesn't look off. Here is some code that demos what I am trying to do:
import javax.swing.*;
public class Menu extends JMenu{
public static void main(String[] args) {
JFrame f = new JFrame("Menu Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar menuBar = new JMenuBar();
menuBar.add(new Menu());
JPanel background = new JPanel();
background.add(menuBar);
f.setContentPane(background);
f.setSize(250, 100);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public Menu() {
super("I'm a Menu");
add(new JMenuItem("Can This Popup be Centered?"));
add(new JMenuItem("Not To the Right?"));
}
}
Here's the current output
Here's what I want (or close to)
If there is a better way to do this other than using a JMenu, please let me know.
Thanks.
I figured out the answer. I override processMouseEvent to know when the menu was clicked, and than simply set the location of the popup menu relative to the location of the menu.
#Override
protected void processMouseEvent(MouseEvent e) {
super.processMouseEvent(e);
if(e.getID() == MouseEvent.MOUSE_PRESSED)
getPopupMenu().setLocation(
getLocationOnScreen().x+getWidth()/2-getPopupMenu().getWidth()/2,
getLocationOnScreen().y+getHeight());
}
I am facing a problem with my JMenuBar location in my Java application.
I am actually using ComponentResizer.java code from the article.
and everything with the resizing works fine except from the north area of my application
(undecorated JFrame) and its corners (of North Area) because the JMenuBar is preventing me from resizing from that area.
Is there a solution or maybe a hack to move the JMenuBar down a little or enable the Resizing
in the north area?
I also use setJMenuBar() method to add the JMenuBar to the north area of my application.
Code:
public class MyApp extends JFrame {
private MyApp frame;
private JMenuBar menuBar;
public static void main(String[] args) {
frame = new MyApp();
frame.setUndecorated(true);
frame.setVisible(true);
}
public MyApp(){
initComponents();
}
private void initComponents(){
setTitle("MediaForm");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 673, 482);
menuBar = new JMenuBar();
setJMenuBar(menuBar);
}
}
JMenuBar extends JComponent, therefore you can put it anywhere you would put an ordinary component. Note that it could be confusing to the users if you put it to unexpected locations.
Also see this: add JMenuBar to a JPanel?
I've not tested this, but JRootPane is a JComponet, it may be possible to add a EmptyBorder to it, allowing the JMenuBar to be offset.
Failing that, you'll probably need to implement your own JRootPane to manage the layout of the JMenuBar & content pane
UPDATE with Testing
public class TestMenuFrame extends JFrame {
public TestMenuFrame() throws HeadlessException {
setTitle("Test");
getRootPane().setBorder(new EmptyBorder(10, 10, 10, 10));
JMenuBar mb = new JMenuBar();
mb.add(new JMenu("Test"));
setJMenuBar(mb);
setSize(100, 100);
getContentPane().setBackground(Color.RED);
setLocationRelativeTo(null);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new TestMenuFrame().setVisible(true);
}
}
My main class displays a JMenuBar. This JMenuBar is managed from "calculator.ui.MenuBar."
public JMenuBar createMenuBar()
{
JMenuBar menuBar = new JMenuBar();
new calculator.ui.MenuBar(menuBar);
return menuBar;
}
MenuBar creates my "File" JMenu and "Insert" JMenu.
public MenuBar(JMenuBar menuBar)
{
new FileMenu(menuBar);
new InsertMenu(menuBar);
}
FileMenu contains all the options for "File." In the File class, there is a JMenuItem called "New Calculator." Now, when you click "New Calculator," I want the JPanel in my main class to create an instance of Calculator in my main class.
newFileSubMenu = new JMenu("New...");
calculatorFileSubMenu = new JMenuItem("New Calculator");
calculatorFileSubMenu.getAccessibleContext().setAccessibleDescription(
"New Calculator");
newFileSubMenu.add(calculatorFileSubMenu);
ActionListener newCalculatorListener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
newCalculator();
}
};
calculatorFileSubMenu.addActionListener(newCalculatorListener);
This is the code for my main class JPanel:
public Container createContentPane() {
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setOpaque(true);
JTabbedPane tabbedPane = new JTabbedPane();
return contentPane;
}
My questions are related to the design of my program. For each instance of Calculator, I want to:
Create a JPanel within the main JPanel that contains my Calculator (what stumps me here is how do I - from my FileMenu class - create a JPanel that's in my main class?).
Make sure that the Calculator object refreshes.
Note: I also want my JPanels to be in TabbedPanes (if that changes anything; if it doesn't, then I can figure that part out once I know the answer for the first question.)
Thanks for your help, I hope I've been clear enough in what I want to do.
In your menu item's Action, you can use setSelectedIndex() on your JTabbedPane to select the pane holding an existing calculator instance. You can use setComponentAt() to replace the content of any tab with an instance of your calculator.
There's a related example here.