How to hide Swing accelerators by a text pane? - java

I have a Swing application with multiple panes. Some of the panes are text ones (JTextPane), some are dialog-like (with buttons and sliders) and some are graphical (custom painted ). I have a few actions defined in the main menu with simple accelerators like K, P or O.
I would like those accelerators to be processed by the menu actions only if the currently focused pane is not processing them. Specifically, I do not want them to be processed by the menu when the user is just typing in a text pane.
I am creating actions and menu items using:
action = new javax.swing.AbstractAction
new MenuItem(action)
I am registering accelerators with:
action.putValue(javax.swing.Action.ACCELERATOR_KEY, keyStroke)
Is it possible to "eat" (suppress) the key press event for the keys which are processed in the text panes so that they are not passed to the main menu for the global processing?
If not, are there some alternatives to do something similar, like to register the accelerators I know should not be processed when in a text pane for some panes only?
I am adding a code based on an answer to make the question clearer (and to make developing alternate solutions easier):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here I want no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here I want accelerators working"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}

Here is the example. In text area no key bindings working. In text field work all key bindings. Also all the menu items are accessible (enabled) from the menu.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
menu.add(new PrintAction("O", KeyStroke.getKeyStroke(KeyEvent.VK_O, 0)));
menu.add(new PrintAction("K", KeyStroke.getKeyStroke(KeyEvent.VK_K, 0)));
menu.add(new PrintAction("P", KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)));
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
area.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
setItemStatus(menu, true);
}
#Override
public void focusGained(FocusEvent e) {
setItemStatus(menu, false);
}
});
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static void setItemStatus(JMenu aMenu, boolean aStatus) {
for (Component item : aMenu.getMenuComponents()) {
((JMenuItem) item).getAction().setEnabled(aStatus);
}
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}

Here is a solution using KeyBindinds, as suggested by camickr. It is shorter than the one provided by Sergiy Medvynskyy, and I find it more straightforward, but it has a drawback the shortcut is not displayed in the menu, which is a result of the shortcut not being defined in the action itself.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O");
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators") {
{
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0), "command_O");
getActionMap().put("command_O", oAction);
}
}, BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr) {
super("Print: " + aPrintStr);
str = aPrintStr;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}

It is possible to use KeyEventDispatcher to filter key events.
(Credit: I have adapted the code from answer to Application wide keyboard shortcut)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
final JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addKeyEventDispatcher( new KeyEventDispatcher() {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
// pass only KEY_TYPED for letters with no modifiers in the editing area, suppress KEY_PRESSED, KEY_RELEASED
return area.isFocusOwner() && keyStroke.getModifiers()==0 && e.getID()!=KeyEvent.KEY_TYPED && Character.isLetter(e.getKeyChar());
}
});
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}

Related

Adding a scrollable menu to a submenu

I'm trying to adapt to submenus the code found at https://coderanch.com/t/343946/java/Scrolling-JMenu in order to have a scrollbar rather than buttons like suggested in the answer of Java: Creating a scrolling submenu. However I am having a some troubles for getting a "standard" behaviour:
The parent menu should not disappear when the mouse is focused/hovering on the scrollable menu (see Font menu).
The scrollable menu should disappear when the mouse is not focused/hovering on it or on its parent submenu (see Font menu).
The scrollable menu should not disappear even if the text of the submenu is long (see Help menu).
Thanks in advance for your help. Here's my code:
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
public class ScrollingMenu extends JFrame {
private final JPopupMenu fontNameMenu = new JPopupMenu();
private final JMenu[] fontMenuArray = new JMenu[] {new JMenu("Font Name"), new JMenu("Font Style")};
private JMenu menu = new JMenu("Font");
private final JMenu[] helpMenuArray = new JMenu[] {new JMenu("Very very very very very very very long Font Name Menu")};
private JMenu hmenu = new JMenu("Help");
public static void main(String[] args) {
JFrame scrollingMenu = new ScrollingMenu();
scrollingMenu.setVisible(true);
}
public ScrollingMenu() {
// Creating a long array
String[] systemFontArray = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
JCheckBoxMenuItem[] fontNameArray = new JCheckBoxMenuItem[systemFontArray.length];
// Creating the scrollable menu
GridBagLayout fontNameLayout=new GridBagLayout();
JPanel fontNamePanel = new JPanel();
fontNamePanel.setLayout(fontNameLayout);
for (int i=0;i<systemFontArray.length;i++) {
fontNameArray[i] = new JCheckBoxMenuItem(systemFontArray[i]);
fontNameLayout.setConstraints(fontNameArray[i],new GridBagConstraints(0,i,1,1,0,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
fontNamePanel.add(fontNameArray[i]);
}
JScrollPane fontScrollPane = new JScrollPane(fontNamePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.fontNameMenu.add(fontScrollPane);
// Adding the scrollable menu to a submenu
addML(ScrollingMenu.this.fontMenuArray[0], ScrollingMenu.this.fontNameMenu, new Dimension(200, 200));
// Creating the Font Style submenu (for underlining problem 2)
this.fontMenuArray[1].add(new JCheckBoxMenuItem("Bold"));
this.fontMenuArray[1].add(new JCheckBoxMenuItem("Italic"));
this.fontMenuArray[1].add(new JCheckBoxMenuItem("Plain"));
// Adding the submenus to the Font menu
for (int i=0;i<this.fontMenuArray.length;i++) {
this.menu.add(this.fontMenuArray[i]);
}
// Adding the scrollable menu to a long text submenu (problem 3)
addML(ScrollingMenu.this.helpMenuArray[0], ScrollingMenu.this.fontNameMenu, new Dimension(200, 200));
// Adding the submenu to the Help menu
for (int i=0;i<this.helpMenuArray.length;i++) {
this.hmenu.add(this.helpMenuArray[i]);
}
JMenuBar menuBar = new JMenuBar();
menuBar.add(this.menu);
menuBar.add(this.hmenu);
this.setJMenuBar(menuBar);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
}
private static void addML (JMenu subMenu, JPopupMenu popupMenu, Dimension dimension) {
popupMenu.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent focusEvent) {
if(popupMenu.isVisible() && !subMenu.isSelected())
popupMenu.setVisible(false);
}
});
popupMenu.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent mouseEvent) {
if(!subMenu.isSelected())
popupMenu.setVisible(false);
}
});
popupMenu.setInvoker(subMenu);
popupMenu.setPreferredSize(dimension);
subMenu.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mouseEvent) {
if(!popupMenu.isVisible())
displayFontNameMenu(subMenu, popupMenu);
else
popupMenu.setVisible(false);
}
#Override
public void mouseEntered(MouseEvent mouseEvent) {
if(!popupMenu.isVisible() && subMenu.isSelected())
displayFontNameMenu(subMenu, popupMenu);
}
#Override
public void mouseExited(MouseEvent mouseEvent) {
if(popupMenu.isVisible() && !popupMenu.contains(mouseEvent.getPoint())) {
popupMenu.setVisible(false);
}
}
});
}
private static void displayFontNameMenu(JMenu subMenu, JPopupMenu popupMenu) {
Rectangle rectangle = subMenu.getBounds();
Point point = new Point(rectangle.x +rectangle.width, rectangle.y);
SwingUtilities.convertPointToScreen(point, subMenu.getParent());
popupMenu.setLocation(point.x, point.y);
popupMenu.setVisible(true);
}
}

Mnemonic behavior since Java 1.7 (still present in 1.8.0.121)

We have a legacy piece of software that runs on Java 1.6. When we finally got the green light to upgrade it to Java 1.8, the following problem manifested itself.
We have a set of radio buttons with accelerator keys. If a JTextComponent of any sort has the focus, and you hit one of the radio button accelerators (say, ALT-s), and you release the "s" before you release the ALT, the UIManager will activate the menu bar. (This only happens with the Windows look and feel)
Looks like a bug, and I've been thinking of writing a workaround by "consuming" the ALT release in those cases, but maybe someone has a better idea? Using a different look and feel is not an option, nor is switching off the standard Alt behavior in the UI Manager.
Here's a short code sample. Note there are no accelerator/mnemonic conflicts of any sort.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.UIManager;
public class MnemonicTest extends JFrame {
public MnemonicTest() {
super("MnemonicTest");
init();
}
public static void main(String[] args) throws Exception {
MnemonicTest test = new MnemonicTest();
test.setVisible(true);
}
private void init() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e1) {
e1.printStackTrace();
}
setSize(new Dimension(500,400));
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(stopButton, BorderLayout.SOUTH);
JMenuBar jMenuBar = new JMenuBar();
JMenu menu = new JMenu("XXX");
JMenuItem a1 = new JMenuItem("a1", 'A');
JMenuItem b1 = new JMenuItem("b1", 'B');
JMenuItem c1 = new JMenuItem("c1", 'C');
menu.add(a1);
menu.add(b1);
menu.add(c1);
jMenuBar.add(menu);
this.setJMenuBar(jMenuBar);
JPanel p = new JPanel();
ButtonGroup group = new ButtonGroup();
p.add(new JTextField("XXXXXXXXXX"), BorderLayout.CENTER);
JRadioButton but1 = new JRadioButton("test");
but1.setMnemonic('s');
JRadioButton but2 = new JRadioButton("2222");
p.add(but1);
p.add(but2);
group.add(but1);
group.add(but2);
getContentPane().add(p, BorderLayout.CENTER);
}
}
I did manage to find a solution that works, even if it's not exactly a beauty contest winner. If you have a better one, please post it!!
The problem seems to be that the KeyEvent is sent to the radio button and not to the pane or the text field. And when the system sees that the ALT key has been released, it invokes the default action.
Of course, a plain vanilla Alt when a radio button has the focus should still do what it is supposed to do: activate the menu bar.
If you press, say, Alt-S (our accelerator), the radio button will receive: keyPressed(Alt) -> keyPressed("S") -> keyReleased("S") -> keyReleased(Alt).
Thus, if we save the value of the last key pressed, we'll consume the last event (keyReleased(Alt)) unless the last key pressed was also an Alt.
This is a workaround, and not a pretty one, but it works. The code is as follows (I've left my debug statements in the code):
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.UIManager;
public class MnemonicTest extends JFrame {
int codeLast = 0;
private final class RadioButtonKeyAdapter extends KeyAdapter {
private static final int NO_CODE = 0;
private int lastCode = 0;
#Override
public void keyPressed(KeyEvent e) {
System.out.println("pressed source: " + e.getSource() + "\n" + e.getKeyCode());
this.setLastCode(e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("released source: " + e.getSource() + "\n" + e.getKeyCode());
if (e.getKeyCode() == KeyEvent.VK_ALT && this.getLastCode() != e.getKeyCode()) {
e.consume();
}
this.setLastCode(NO_CODE);
}
private int getLastCode() {
return lastCode;
}
private void setLastCode(int lastCode) {
this.lastCode = lastCode;
}
}
private static final long serialVersionUID = 1L;
public MnemonicTest() {
super("MnemonicTest");
init();
}
public static void main(String[] args) throws Exception {
MnemonicTest test = new MnemonicTest();
test.setVisible(true);
}
private void init() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e1) {
e1.printStackTrace();
}
setSize(new Dimension(500,400));
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(stopButton, BorderLayout.SOUTH);
JMenuBar jMenuBar = new JMenuBar();
JMenu menu = new JMenu("XXX");
JMenuItem a1 = new JMenuItem("a1", 'A');
JMenuItem b1 = new JMenuItem("b1", 'B');
JMenuItem c1 = new JMenuItem("c1", 'C');
menu.add(a1);
menu.add(b1);
menu.add(c1);
jMenuBar.add(menu);
this.setJMenuBar(jMenuBar);
JPanel p = new JPanel();
ButtonGroup group = new ButtonGroup();
JTextField textField = new JTextField("XXXXXXXXXX");
p.add(textField, BorderLayout.CENTER);
JRadioButton but1 = new JRadioButton("test");
but1.setMnemonic('s');
JRadioButton but2 = new JRadioButton("2222");
p.add(but1);
p.add(but2);
group.add(but1);
group.add(but2);
getContentPane().add(p, BorderLayout.CENTER);
but1.addKeyListener(new RadioButtonKeyAdapter());
but2.addKeyListener(new RadioButtonKeyAdapter());
}
}

Creating a java swing album

I'd like to create a Java Swing Photo Album but I can't manage to find the right way to do it. I think it should be to create two ArrayList, one to stock the photo objects and another one to stock the buttons.
After that I should find a way to assign each images to the buttons and add them into the panel.
My question is : Do you think it is the right way to do it and if so, could you give me a hint? (For the last class at the bottom)
Here's my code at the moment :
Main :
import javax.swing.JFrame;
public class Main extends JFrame {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new AlbumFrame();
}
});
}
}
AlbumFrame :
import java.awt.BorderLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class AlbumFrame extends JFrame {
private JPanel MenuPanel;
private JPanel PhotoPanel;
public AlbumFrame(){
super("JPhone");
setLayout(new BorderLayout());
PhotoPanel = new PhotoPanel();
add(PhotoPanel,BorderLayout.CENTER);
MenuPanel = new MenuPanel();
add(MenuPanel,BorderLayout.SOUTH);
setSize(480,800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
MenuPanel
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MenuPanel extends JPanel implements ActionListener{
private static final long serialVersionUID = 1L;
private JButton backButton;
private JButton homeButton;
private JButton turnButton;
private JButton addButton;
final private JFileChooser fc;
public MenuPanel(){
fc = new JFileChooser();
backButton = new JButton(new ImageIcon(getClass().getResource("/Images/back.png")));
homeButton = new JButton(new ImageIcon(getClass().getResource("/Images/home.png")));
turnButton = new JButton(new ImageIcon(getClass().getResource("/Images/turn.png")));
addButton = new JButton(new ImageIcon(getClass().getResource("/Images/add.png")));
backButton.setPreferredSize(new Dimension(55,55));
homeButton.setPreferredSize(new Dimension(55,55));
turnButton.setPreferredSize(new Dimension(55,55));
addButton.setPreferredSize(new Dimension(55,55));
backButton.addActionListener(this);
homeButton.addActionListener(this);
turnButton.addActionListener(this);
addButton.addActionListener(this);
setLayout(new FlowLayout(FlowLayout.CENTER));
add(backButton);
add(homeButton);
add(turnButton);
add(addButton);
}
public void actionPerformed(ActionEvent e) {
JButton clicked = (JButton)e.getSource();
//Test for the moment
if(clicked == backButton){
System.out.println("back");
}else if(clicked == homeButton){
System.out.println("home");
}else if(clicked == turnButton){
System.out.println("turn");
}else if(clicked == addButton){
int returnVal = fc.showOpenDialog(MenuPanel.this);
if(returnVal == JFileChooser.APPROVE_OPTION){
File file = fc.getSelectedFile();
}
}
}
}
PhotoPanel
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JPanel;
public class PhotoPanel extends JPanel implements ActionListener {
ArrayList<Photo> Album = new ArrayList<Photo>();
ArrayList<JButton> Buttons = new ArrayList<JButton>();
public PhotoPanel(){
setLayout(new FlowLayout(FlowLayout.CENTER));
}
public void actionPerformed(ActionEvent e) {
}
}
I would use separate class like PhotoCard to avoid lists:
class PhotoCard {
public PhotoCard(Photo photo) {
add(photo);
// also add buttons, listeners, etc.
}
}
that holds necessary data and initializes listeners.
And then class can be added to to your PhotoPanel:
PhotoPanel.add(new PhotoCard(...));

get keystrokes in java without focusing?

i wanted to make a java program for getting keystrokes without focusing and without keyevent class object for my project ..
is there any way to do so..??
i tried this but it is not fulfilling my requirements!!
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.text.Keymap;
public class key1 {
private static void showUI() {
JFrame jFrame = new JFrame("");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = jFrame.getContentPane();
JTextField txt = new JTextField();
container.add(txt, BorderLayout.NORTH);
ActionListener actListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(event.getActionCommand() + " selected");
}
};
JPanel jPane = new JPanel();
JButton defaultButton = new JButton("Hit Enter");
defaultButton.addActionListener(actListener);
jPane.add(defaultButton);
JButton otherButton = new JButton("Onother Button");
otherButton.addActionListener(actListener);
jPane.add(otherButton);
container.add(jPane, BorderLayout.SOUTH);
Keymap map = txt.getKeymap();
KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false);
map.removeKeyStrokeBinding(stroke);
jFrame.getRootPane().setDefaultButton(defaultButton);
jFrame.setSize(350, 250);
jFrame.setVisible(true);
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
showUI();
}
});
}
}
I don't believe this is possible at the Swing level..the entire KeyEvent API revolves around some Component having focus :(
In fact, I'm pretty sure the JVM only generates events based on what the OS gives to it..and you can only get those events if something is in focus.
However, I've found a library that might do what you want. I have never used it though..just looked up out of curiosity:
http://code.google.com/p/jnativehook/

Java tabbed panes within internal frame

I am trying to get an internal frame to contain tabbed panes. However, my code does not seem to be loading the panes into the internal frame. I have my code in the java files, called InternalFrame.java and TabbedPaneSample.java. The code for both files is included below. Can anyone show me how to fix the code below so that it loads the tabbed panes when I run InternalFrame.java?
Here is my code:
The code for InternalFrame.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
TabbedPaneSample myTabbedPaneSample = new TabbedPaneSample();
public InternalFrame() {
super("Click button to open internal frame with two panels.");
setSize(500, 400);
openButton = new JButton("Open");
Panel p = new Panel();
p.add(openButton);
add(p, BorderLayout.SOUTH);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
desktop.setOpaque(true);
add(desktop, BorderLayout.CENTER);
}
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
desktop.add(internalFrame, new Integer(1));
internalFrame.setVisible(true);
}
}
}
public static void main(String args[]) {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
}
And the code for TabbedPaneSample.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class TabbedPaneSample extends JTabbedPane {
private JTabbedPane tabbedPane = new JTabbedPane();
private ImageIcon closeImage = new ImageIcon("C:/test/shipIcon.gif");
private Dimension closeButtonSize;
private int tabCounter = 0;
public TabbedPaneSample() {
closeButtonSize = new Dimension(closeImage.getIconWidth() + 2, closeImage.getIconHeight() + 2);
}
public void add() {
final JPanel content = new JPanel();
JPanel tab = new JPanel();
tab.setOpaque(false);
JLabel tabLabel = new JLabel("Tab " + (++tabCounter));
JButton tabCloseButton = new JButton(closeImage);
tabCloseButton.setPreferredSize(closeButtonSize);
tabCloseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int closeTabNumber = tabbedPane.indexOfComponent(content);
tabbedPane.removeTabAt(closeTabNumber);
}
});
tab.add(tabLabel, BorderLayout.WEST);
tab.add(tabCloseButton, BorderLayout.EAST);
this.addTab(null, content);
this.setTabComponentAt(this.getTabCount() - 1, tab);
}
public static void main(String[] args) {
TabbedPaneSample main = new TabbedPaneSample();
main.add();
main.add();
}
}
Here's one approach, shown below. A more flexible approach using Action is referenced here.
Addendum: Reviewing your code, you should let the various layout managers and component preferred sizes do more of the work, as shown. In particular, this.setPreferredSize() is done for demonstration purposes. In a real application, you would restore user size and location preferences.
package overflow;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/posts/6514889 */
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
public InternalFrame() {
super("Click button to open internal frame with two tabs.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(400, 400));
openButton = new JButton("Open");
JPanel p = new JPanel();
p.add(openButton);
this.add(p, BorderLayout.SOUTH);
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
this.add(desktop, BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(null);
}
class OpenListener implements ActionListener {
private static final int DELTA = 40;
private int offset = DELTA;
public void actionPerformed(ActionEvent e) {
internalFrame = new JInternalFrame(
"Internal Frame", true, true, true, true);
internalFrame.setLocation(offset, offset);
offset += DELTA;
internalFrame.add(createTabbedPane());
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
private JTabbedPane createTabbedPane() {
JTabbedPane jtp = new JTabbedPane();
createTab(jtp, "One");
createTab(jtp, "Two");
return jtp;
}
private void createTab(JTabbedPane jtp, String s) {
jtp.add(s, new JLabel("TabbedPane " + s, JLabel.CENTER));
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
});
}
}
First of all, I think Finally, I think you shouldn't use desktop.add(internalFrame, new Integer(1)) but rather desktop.add(internalFrame) instead, the reason is that JDesktopPane uses its layers (it is a JLayeredPane subclass) internally, and I don't think you should play with layers yourself.
Then, following this problem I had once with JInternalFrame, I would advise you call pack() after adding the internal frame to the desktop pane.
Hence, you should try with your OpenListener class looking like this:
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
// desktop.add(internalFrame, new Integer(1));
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
}
Besides, I also agree with trashgod comments on Action of course and the simplifying rework he has done on your snippet.
I preferred to create in my Main Frame class (which extends JFrame) the following function:
private void showIntFrame(Class intFrameClass) {
JInternalFrame targetFrame = null;
int xoff = 0, yoff = 0;
for(JInternalFrame jif : jdp.getAllFrames()) {
if(jif.getClass().equals(intFrameClass))
targetFrame = jif;
if(jif.getLocation().x > xoff)
xoff = jif.getLocation().x;
if(jif.getLocation().y > yoff)
yoff = jif.getLocation().y;
}
if(targetFrame == null) {
try {
Constructor<JInternalFrame> c = intFrameClass.getConstructor(MainFrame.class);
targetFrame = c.newInstance(MainFrame.this);
} catch (Exception ex) {
System.err.println("Exception in MainFrame.showIntFrame() while creating new JInternalFrame instance. " + ex.getLocalizedMessage());
ex.printStackTrace();
return;
}
jdp.add(targetFrame);
targetFrame.setLocation(xoff + 30, yoff + 30);
}
targetFrame.setVisible(true);
try {
targetFrame.setSelected(true);
} catch (PropertyVetoException ex) {
System.err.println("PropertyVetoException in MainFrame.showIntFrame() while activating JInternalFrame instance. " + ex.getLocalizedMessage());
}
}
Here jdp is instance of JDesktopPane, which previously was set as ContentPane of my main JFrame.
Because my programs often contain numbers of different classes, inherited from JInternalFrame, it is easier to call this function from event handlers to show new subclass of JInternalFrame.
Every subclass of JInternalFrame in my programs have one constructor with one parameter - MainFrame (main JFrame).

Categories

Resources