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).
Related
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.
My notepad program that I'm writing uses AbstractActions for each item in the JMenuBar, and I want to keep it consistent that way throughout my code. And now I'm implementing Cut, Copy, Paste into the program but I'm unsure of how to do that with Action.
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.text.DefaultEditorKit;
public class Home {
static Action Cut = new AbstractAction("Cut-Action") {
public void actionPerformed(ActionEvent e) {
// Where I want to use cut
new DefaultEditorKit.CutAction();
}
};
static public JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Edit");
menu.add(Cut); // Adds the cut action
// adds the non-action method
JMenuItem item = new JMenuItem(new DefaultEditorKit.CutAction());
item.setText("Cut-NonAction");
menu.add(item);
menuBar.add(menu);
return menuBar;
}
public static void main(String[] args) {
JFrame frame = new JFrame("Home");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar menuBar = createMenuBar();
frame.add(menuBar, BorderLayout.NORTH);
JTextPane txt = new JTextPane();
JScrollPane s = new JScrollPane(txt);
frame.add(s, BorderLayout.CENTER);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
How would I be able to use the cut action in my abstract action??
I figured it out with a little bit of trial and error.
I changed this code:
public void actionPerformed(ActionEvent e) {
new DefaultEditorKit().CutAction();
}
to:
public void actionPerformed(ActionEvent e) {
Action cut = new DefaultEditorKit.CutAction();
cut.actionPerformed(e);
}
How would I be able to use the cut action in my abstract action??
Why are you trying to do this? The is not the way to use the Actions from the editor kit.
This is the proper way to use the actions:
JMenuItem item = new JMenuItem(new DefaultEditorKit.CutAction());
Or if you happen to need the CutAction on a menu and on a toolbar you would use code like:
Action cut = new DefaultEditorKit.CutAction();
cut.putValue(Action.NAME, "Cut");
JMenuItem cutMenuItem = new JMenuItem( cut );
JButton cutButton = new JButton( cut );
Now the same Action is shared which means you can enable/disable the Action and both components will be affected. Read the section from the Swing tutorial on How to Use Actions for more information and examples.
what is the right way to access elements from a parent component when an adapter is used? Example:
In my JFrame is a Menu with an item "Connect". I handle the "pressed" event with a MouseAdapter:
mntmConnect.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent arg0) {
mainDialog.getY();
}
});
As you can see I want to access components or methods of the mainDialog where this Menu(item) belongs to. But in that MouseAdapter of course no "mainDialog" is known.
So here are my approaches:
1. Declare attributes that a needed as final
2. Create your own MouseAdapter that takes "mainDialog" as a variable in the ctor
Both of them seem circumstantial to me. What is the right way to do this?
What is the right way to do this?
All 3 of these approaches are right.
Declare attributes that are needed for an anonymous class as final.
Declare attributes that are needed for an anonymous class as class global.
Create a MouseAdapter class that takes "mainDialog" as a variable in the constructor.
I tend to use 2 for small MouseAdapter anonymous classes.
I tend to use 3 for larger MouseAdapter classes. I make these separate classes and put them in a controller package.
I handle the "pressed" event with a MouseAdapter
You should NOT be doing this. You should be adding and ActionListener (or Action) to the JMenuItem.
All compnents have a parent. So if you want to know the parent window of the menu item that was clicked you need to keep finding the parents component until you reach the window. Here is one way:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MenuItemFrame extends JFrame implements ActionListener
{
public MenuItemFrame()
{
JMenuBar menuBar = new JMenuBar();
setJMenuBar( menuBar );
JMenu menu = new JMenu( "File" );
menuBar.add( menu );
JMenuItem item1 = new JMenuItem("Item 1");
item1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0, false));
menu.add( item1 );
JMenu subMenu1 = new JMenu("SubMenu 1");
menu.add( subMenu1 );
JMenuItem subItem1 = new JMenuItem("SubItem 1");
subMenu1.add( subItem1 );
JMenu subMenu12 = new JMenu("SubMenu 12");
subMenu1.add( subMenu12 );
JMenuItem subItem12 = new JMenuItem("SubItem 12");
subMenu12.add( subItem12 );
item1.addActionListener( this );
subItem1.addActionListener( this );
subItem12.addActionListener( this );
}
public void actionPerformed(ActionEvent e)
{
JMenuItem mi = (JMenuItem)e.getSource();
mi.setText(mi.getText() + "0");
JMenu menu = getMenuBarMenu(mi);
JRootPane rootPane = SwingUtilities.getRootPane(menu);
JFrame frame = (JFrame)SwingUtilities.windowForComponent(menu);
System.out.println(frame);
}
public JMenu getMenuBarMenu(JMenuItem item)
{
JMenu menu = null;
while (menu == null)
{
JPopupMenu popup = (JPopupMenu)item.getParent();
item = (JMenuItem)popup.getInvoker();
if (! (item.getParent() instanceof JPopupMenu) )
menu = (JMenu)item;
}
return menu;
}
public static void main(String[] args)
{
JFrame frame = new MenuItemFrame();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.setSize(200, 200);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
I am trying to design a basic editor type of GUI in Java using Swing. I have a menu item named New clicking on which I want a blank text area to fill up the GUI. My code is as folows :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class UI extends JFrame {
private JMenuBar bar;
private JMenu menu;
private JMenuItem item;
private JTextPane tp;
public UI() {
setLayout(new FlowLayout());
bar = new JMenuBar();
setJMenuBar(bar);
menu = new JMenu("File");
bar.add(menu);
item = new JMenuItem("New");
menu.add(item);
item.addActionListener(new xyz());
}
public class xyz implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
JTextPane tp = new JTextPane();
add(tp);
}
}
public static void main(String args[]) {
// do the rest of the stuffs
}
}
However, even on clicking on the New, I do not get the textPane on the same frame. Can someone please explain.
use JTextPane#setText("") instead of to create a new JTextPane
otherwise you have to notify Container with (re)validate() and repaint()
The text-panes should probably be added to a JTabbedPane if this app. supports multiple documents. If it is intended for 'single document', put the text pane onto the frame at start-up.
Hi i have MainFrame class:
public class MainFrame extends JFrame{
private JLabel originalLabel;
private JLabel filteredImage;
public MainFrame(){
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
initComponents();
setVisible(true);
}
private void initComponents(){
ImageFilterMenuBar menuBar = new ImageFilterMenuBar();
originalLabel = new JLabel("Test1");
filteredImage = new JLabel("Test2");
Component verticalStrut = Box.createVerticalStrut(10);
JPanel central = new JPanel();
central.add(originalLabel);
central.add(verticalStrut);
central.add(filteredImage);
add(new RadioButtonsPanel(), BorderLayout.SOUTH);
add(central, BorderLayout.CENTER);
setJMenuBar(menuBar);
}
}
and MenuBar class:
public class ImageFilterMenuBar extends JMenuBar{
private JMenu fileMenu;
private JMenuItem openImage;
private JMenuItem exit;
public ImageFilterMenuBar(){
initCompoments();
}
private void initCompoments() {
fileMenu = new JMenu("File");
setMenuItems();
add(fileMenu);
}
private void setMenuItems(){
openImage = new JMenuItem("Open Image");
exit = new JMenuItem("Exit");
openImage.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
InputEvent.CTRL_MASK));
exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_CANCEL,InputEvent.SHIFT_MASK));
openImage.addActionListener(new OpenListener());
exit.addActionListener(new ExiteListener());
fileMenu.add(openImage);
fileMenu.add(exit);
}
}
in MenuBar class you can sea OpenButton. it's open JFileChooser and returns me url of file which I chose.
So now I don't know how to send this url into my MainFrame class where I want to display this file..
Any ideas??
The easiest solution is to pass a reference to MainFrame to the ImageFilterMenuBar:
ImageFilterMenuBar menuBar = new ImageFilterMenuBar(this);
Then, add a method like below in the MainFrame:
public void setImageFile(File file) {
// do whatever here
}
In the ImageFilterMenuBar you would keep a reference to the MainFrame in a member variable and use it to call setImageFile() once the JFileChooser returns a File.
A more difficult to implement solution would be to implement the observer pattern. This is the way the listeners work in Swing.
You would register the main frame as a listener and the other class would be the one to notify about file selection changes.
To open a file chooser and get the selected file:
JFileChooser chooser = new JFileChooser(path);
int result = chooser.showOpenDialog(mainFrame);
File file = chooser.getSelectedFile();
if (result == JFileChooser.APPROVE_OPTION && file != null && file.exists()) {
mainFrame.setImageFile(file);
}
Do not extend menu-bar or frame, simply keep references to them in the same app. ..
I was about to add "that has an URL class attribute." but it is not clear how you are using the URL. If it is for a JEditorPane I might declare the instance of it in place of the URL attribute, and just set the page directly on selection in the listener.