Swing Actions - Linking Menus and Toolbar - java

I've been studying Java Swing and I'm working on learning actions.
I can successfully create action objects and use them to link items from a JToolBar to JMenuItems. My problem, is that the constructed actions display both icons and text in the toolbar (should only be the icons).
Check out the following code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MenuDemo{
MenuDemo(){
JFrame jfrm = new JFrame("Complete Menu Demo");
jfrm.setSize(220, 200);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar jmb = new JMenuBar();
/* Make the action object */
ImageIcon setIcon = new ImageIcon("setBP.png");
DebugAction setAct = new DebugAction("Set Breakpoint",
setIcon, KeyEvent.VK_S,
KeyEvent.VK_B, "Set Breakpoint");
/* Make the toolbar */
JButton jbtnSet = new JButton(setAct);
JToolBar jtb = new JToolBar("Breakpoints");
jtb.add(jbtnSet);
/* Make the menu */
JMenu jmDebug = new JMenu("Debug");
JMenuItem jmiSetBP = new JMenuItem(setAct);
jmDebug.add(jmiSetBP);
jmb.add(jmDebug);
jfrm.getContentPane().add(jtb, BorderLayout.NORTH);
jfrm.setJMenuBar(jmb);
jfrm.setVisible(true);
}
class DebugAction extends AbstractAction{
public DebugAction(String name, Icon image, int mnem,
int accel, String tTip){
super(name, image);
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(accel,
InputEvent.CTRL_MASK));
putValue(MNEMONIC_KEY, new Integer(mnem));
putValue(SHORT_DESCRIPTION, tTip);
}
public void actionPerformed(ActionEvent ae){
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new MenuDemo();
}
});
}
}
This program yields the following GUI:
I just want the green button in the JToolBar, not text. I think my problem code is in the DebugAction constructor, where I call super(name, image). For the toolbar buttons, I would only want to pass in the image. But for the menu I want both. How can I "turn off" the text for the JToolBar items? Thanks!

How can I "turn off" the text for the JToolBar items?
You turn it off using:
JButton button = new JButton( action );
button.setHideActionText( true );
Or, you can just reset the text on the button:
JButton button = new JButton( action );
button.setText("");

I accepted camickr's answer, but there is a caveat.
For identification purposes, I am grabbing the actionCommand of these buttons. Both setHideActionText(true); and button.setText("") do remove the text, but both produce errors when I try to grab the actionCommand.
To fix this, I explicitly set the actionCommand when I create the action object by adding the additional line in the constructor:
putValue(ACTION_COMMAND_KEY, sometext);
This fixed the errors.

Related

How to use DefaultEditorKit in an AbstractAction

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.

JTextArea swallowing JButton action listener Java

I have an action listener on a JButton and a JTextArea in the button. However when I click the button the text area swallows the event, and nothing happens to the button.
How can I click through the area?
Thank you
Button code
public class CustomFoodItemButton extends JButton{
public JTextArea buttonTitle;
/**
* Public constructor
* #param title
*/
public CustomFoodItemButton(String title) {
//Set button text by using a text area
buttonTitle = new JTextArea();
buttonTitle.setText(title);
buttonTitle.setFont(new Font("Helvetica Neue", Font.PLAIN, 15));
buttonTitle.setEditable(false);
buttonTitle.setWrapStyleWord(true);
buttonTitle.setLineWrap(true);
buttonTitle.setForeground(Color.white);
buttonTitle.setOpaque(false);
//Add the text to the center of the button
this.setLayout(new BorderLayout());
this.add(buttonTitle,BorderLayout.CENTER);
//Set the name to be the title (to track actions easier)
this.setName(title);
//Clear button so as to show image only
this.setOpaque(false);
this.setContentAreaFilled(false);
this.setBorderPainted(false);
//Set not selected
this.setSelected(false);
//Set image
setImage();
}
GUI Class code
private void addFoodItemButtons (JPanel panel){
//Iterate over menu items
for (FoodItem item : menuItems) {
//Create a new button based on the item in the array. Set the title to the food name
CustomFoodItemButton button = new CustomFoodItemButton(item.foodName);
//Add action listener
button.addActionListener(this);
}
}
EDIT For multiline JComponents, check out this answer: https://stackoverflow.com/a/5767825/2221461
It seems to me as if you're overcomplicating things. Why are you using a TextArea on a button if you can't edit the TextArea's text?
There is another constructor for JButtons:
JButton button = new JButton(item.foodname);
This will create a button with the value of 'item.foodname' as text.
You could then simplify your constructor:
public class CustomFoodItemButton extends JButton {
public CustomFoodItemButton(String title) {
super(title);
setName(title);
setOpaque(false);
setContentAreaFilled(false);
setBorderPainted(false);
setSelected(false);
setImage();
}
}
Please let me know if I misinterpreted your question.

Opening a textpane in the same form on a Button click

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.

JFrame's getFocusOwner() not being helpful

I am working with a Swing program and having a little trouble. The program has two windows (both are JFrames). The main window is just fine and should not be relevant to this issue.
The window I am having issues with contains a JScrollPane with a JPanel in it, and has a JMenuBar. The JPanel has a bunch of JTextComponents (some JTextFields, some JTextAreas) on it.
What I want to do is have an ActionListener attached to a JMenuItem find the JTextComponent that has focus.
I have seen the previous posts at focused component reference and How to find out which object currently has focus. My issue is that calling the particular window's getFocusOwner() method merely returns the JFrame's JRootPane, which is utterly unhelpful. Both the JScrollPane and the JPanel in question are focusable according to their isFocusable() methods. This happens even if I actually enter text into one of the JTextComponents before clicking the menu item. The cursor still blinks in the text field while I open the menu, and everything. For what it's worth, getMostRecentFocusOwner() also simply returns the JRootPane.
If you use TextActions, the action knows which JTextComponent has the focus. I've modified some code that I found here to show that even if the TextActions come from one JTextArea, they still will automatically work on any and all text components that have focus:
import java.awt.GridLayout;
import javax.swing.*;
public class TextActionExample {
public static void main(String[] args) {
// Create a text area.
JTextArea ta = new JTextArea(15, 30);
ta.setLineWrap(true);
// Add all actions to the menu (split into two menus to make it more
// usable).
Action[] actions = ta.getActions();
JMenuBar menubar = new JMenuBar();
JMenu actionmenu = new JMenu("Actions");
menubar.add(actionmenu);
JMenu firstHalf = new JMenu("1st Half");
JMenu secondHalf = new JMenu("2nd Half");
actionmenu.add(firstHalf);
actionmenu.add(secondHalf);
int mid = actions.length / 2;
for (int i = 0; i < mid; i++) {
firstHalf.add(actions[i]);
}
for (int i = mid; i < actions.length; i++) {
secondHalf.add(actions[i]);
}
JTextField textField = new JTextField(20);
JPanel textFieldPanel = new JPanel();
textFieldPanel.add(textField);
JPanel mainPanel = new JPanel(new GridLayout(1, 0, 5, 5));
mainPanel.add(new JScrollPane(ta));
mainPanel.add(new JScrollPane(new JTextArea(15, 30)));
mainPanel.add(textFieldPanel);
// Show it . . .
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(mainPanel);
f.setJMenuBar(menubar);
f.pack();
f.setVisible(true);
}
}
This is very interesting stuff that I have to learn more about.
I think I have solved this, because of the fact that you lose focus when you click on a menu item, we simply have to wait for focus to return to the component before we check who has focus, I have done this using a swing timer that waits 100ms and then executes its method to check which component has focus:
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.TimerTask;
import javax.swing.*;
public class JavaApplication180 extends JFrame {
private JTextField[] JTextFields;
private JMenuBar menuBar;
private JMenu menu;
private JMenuItem item;
public JavaApplication180() {
initComponents();
createAndShowUI();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new JavaApplication180();
}
});
}
private void createAndShowUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(2, 2, 10, 10));
setJMenuBar(menuBar);
addComponentsToPane();
pack();
setVisible(true);
}
private void initComponents() {
JTextFields = new JTextField[4];
menuBar = new JMenuBar();
item = new JMenuItem("Who has focus?");
item.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
TimerTask tt = new TimerTask() {
#Override
public void run() {
JOptionPane.showMessageDialog(null, getMostRecentFocusOwner().getName());
}
};
new java.util.Timer().schedule(tt, 100);
}
});
menu = new JMenu("File");
menu.add(item);
menuBar.add(menu);
}
private void addComponentsToPane() {
for (int i = 0; i < JTextFields.length; i++) {
JTextFields[i] = new JTextField();
JTextFields[i].setText(String.valueOf(i));
JTextFields[i].setName(String.valueOf(i));
getContentPane().add(JTextFields[i]);
}
}
}
I'm probably too late, but I just did the following in my JFrame constructor.
this.rootPane.setFocusable(false);
Now
getFocusOwner()
will return the current JTextComponent instead of the rootPane.
I then used this code in an ActionListener attached to my JMenuItem to select the text within it.
if (getFocusOwner() instanceof JTextField)
{
((JTextField) getMostRecentFocusOwner()).selectAll();
}
It should be noted that If you have a JScrollPane etc, you may have to use setFocusable(false) on all the components between the rootPane and the textfields.
Hope this helps anyone else with the same issue!
Source: Personal Experience
When I've needed this, I wrote a focus listener. I had a JPanel with two columns of JTextFields and the focus listener kept track of which column was last used by the user. I enablesd the user to enter some text into that last focused column with a button click. You would use just one instance of your FocusListener for all text fields and have a field referencing the most recently focused component. Your menu action can then query that field to determine which text field to use.
See http://docs.oracle.com/javase/tutorial/uiswing/events/focuslistener.html

Add functionality to a menu button in java

I am new to Java and I was wondering how to add functionality to menu item?
What I would like it to do, is to set two values to 0.
This is the code I have currently:
JMenuItem clear = new JMenuItem("Clear");
Options.add(clear);
This example is from the book "Java
Foundation Classes in a Nutshell".
Written by David Flanagan. Copyright
(c) 1999 by O'Reilly & Associates.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MenuDemo {
public static void main(String[] args) {
// Create a window for this demo
JFrame frame = new JFrame("Menu Demo");
JPanel panel = new JPanel();
frame.getContentPane().add(panel, "Center");
// Create an action listener for the menu items we will create
// The MenuItemActionListener class is defined below
ActionListener listener = new MenuItemActionListener(panel);
// Create some menu panes, and fill them with menu items
// The menuItem() method is important. It is defined below.
JMenu file = new JMenu("File");
file.setMnemonic('F');
file.add(menuItem("New", listener, "new", 'N', KeyEvent.VK_N));
file.add(menuItem("Open...", listener, "open", 'O', KeyEvent.VK_O));
file.add(menuItem("Save", listener, "save", 'S', KeyEvent.VK_S));
file.add(menuItem("Save As...", listener, "saveas", 'A', KeyEvent.VK_A));
JMenu edit = new JMenu("Edit");
edit.setMnemonic('E');
edit.add(menuItem("Cut", listener, "cut", 0, KeyEvent.VK_X));
edit.add(menuItem("Copy", listener, "copy", 'C', KeyEvent.VK_C));
edit.add(menuItem("Paste", listener, "paste", 0, KeyEvent.VK_V));
// Create a menubar and add these panes to it.
JMenuBar menubar = new JMenuBar();
menubar.add(file);
menubar.add(edit);
// Add menubar to the main window. Note special method to add menubars
frame.setJMenuBar(menubar);
// Now create a popup menu and add the some stuff to it
final JPopupMenu popup = new JPopupMenu();
popup.add(menuItem("Open...", listener, "open", 0, 0));
popup.addSeparator(); // Add a separator between items
JMenu colors = new JMenu("Colors"); // Create a submenu
popup.add(colors); // and add it to the popup menu
// Now fill the submenu with mutually-exclusive radio buttons
ButtonGroup colorgroup = new ButtonGroup();
colors.add(radioItem("Red", listener, "color(red)", colorgroup));
colors.add(radioItem("Green", listener, "color(green)", colorgroup));
colors.add(radioItem("Blue", listener, "color(blue)", colorgroup));
// Arrange to display the popup menu when the user clicks in the window
panel.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
// Check whether this is the right type of event to pop up a popup
// menu on this platform. Usually checks for right button down.
if (e.isPopupTrigger())
popup.show((Component)e.getSource(), e.getX(), e.getY());
}
});
// Finally, make our main window appear
frame.setSize(450, 300);
frame.setVisible(true);
}
// A convenience method for creating menu items.
public static JMenuItem menuItem(String label,
ActionListener listener, String command,
int mnemonic, int acceleratorKey) {
JMenuItem item = new JMenuItem(label);
item.addActionListener(listener);
item.setActionCommand(command);
if (mnemonic != 0) item.setMnemonic((char) mnemonic);
if (acceleratorKey != 0)
item.setAccelerator(KeyStroke.getKeyStroke(acceleratorKey,
java.awt.Event.CTRL_MASK));
return item;
}
// A convenience method for creating radio button menu items.
public static JMenuItem radioItem(String label, ActionListener listener,
String command, ButtonGroup mutExGroup) {
JMenuItem item = new JRadioButtonMenuItem(label);
item.addActionListener(listener);
item.setActionCommand(command);
mutExGroup.add(item);
return item;
}
// A event listener class used with the menu items created above.
// For this demo, it just displays a dialog box when an item is selected.
public static class MenuItemActionListener implements ActionListener {
Component parent;
public MenuItemActionListener(Component parent) { this.parent = parent; }
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
String cmd = item.getActionCommand();
JOptionPane.showMessageDialog(parent, cmd + " was selected.");
}
}
}
Hope it help you get started
You will need to add an ActionListener. This is an interface which must implement a method called actionPerformed.
E.g
clear.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
// Clear two values.
}
});`
This will add an anonymous ActionListener that is invoked once the JMenuItem is clicked.
Hope that helps.

Categories