stopCellEditing on JDialog - java

My question is similar to this one: JTable Cell Update doesn't work.
However, I am using JDialog instead of a JTable specified in above link. I have a custom class which extends JDialog. I use JEditorPane as a text-component in that dialog and create simple OK, Cancel buttons. Now the problem is, when I enter something in the JEdiorPane and presses OK button, the value is not applied to the text-component until I move the focus out of a JDialog or hit tab/ENTER.
I want the container to be notified that I am done with editing as soon as I press the OK button. In short I want to explicitly have a feature similar to stopCellEditing(). How can I do that?

See this example which seems to work correctly and does the same thing as you described:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TestEditorPaneDialog {
public void init() {
final JFrame frame = new JFrame();
JButton clickMe = new JButton("Click me");
clickMe.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
showDialog(frame);
}
});
frame.add(clickMe);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
showDialog(frame);
}
private void showDialog(final JFrame frame) {
final JDialog dialog = new JDialog(frame, true);
final JEditorPane pane = new JEditorPane();
pane.setText("Type something here");
JPanel south = new JPanel();
JPanel buttons = new JPanel(new GridLayout(1, 0, 10, 10));
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
JOptionPane.showMessageDialog(frame, "You have typed in: " + pane.getText());
}
});
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
buttons.add(ok);
buttons.add(cancel);
south.add(buttons);
dialog.add(new JScrollPane(pane));
dialog.add(south, BorderLayout.SOUTH);
dialog.setSize(250, 150);
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestEditorPaneDialog().init();
}
});
}
}

Related

How do I change the background colour in the Play class?

I want to change the color of the background and a clear window without creating a new JFrame. Any suggestions?
import java.awt.*;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Dodge EM");
frame.setSize(1000, 700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
placeComponents(frame);
frame.setVisible(true);
frame.getContentPane().setBackground(Color.black);
}
private static void placeComponents(JFrame frame) {
frame.setLayout(null);
JLabel dodgeEM = new JLabel("Dodge EM");
dodgeEM.setForeground (Color.RED);
dodgeEM.setFont(new Font("Serif", Font.BOLD, 30));
dodgeEM.setBounds(440,10,300,150);
frame.add(dodgeEM);
JButton playButton = new JButton("Play");
playButton.setBounds(460,150,95,30);
frame.add(playButton);
ActionListener play = new Play();
playButton.addActionListener(play);
JButton scoresButton = new JButton("Scores");
scoresButton.setBounds(460,250,95,30);
frame.add(scoresButton);
JButton helpButton = new JButton("Help");
helpButton.setBounds(460,350,95,30);
frame.add(helpButton);
JButton quitButton = new JButton("Quit");
quitButton.setBounds(460,450,95,30);
frame.add(quitButton);
}
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Play extends JFrame implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
//JOptionPane.showMessageDialog(null, "Play button has been pressed");
this.getContentPane().setBackground(Color.red);
}
}
Any suggestions are much appreciated.
Rather then creating a new class, you can add the action listener to your button like shown below
playButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
//do stuff onclick
frame.getContentPane().setBackground(Color.yellow);
}
});

How to prevent typing in a TextArea also triggering Key Bindings?

I am trying to implement hotkeys in a JFrame with a split pane that has a JTree on one of the panes. The key bindings work great, except that when a user is editing the name of a JTree node if they press a key that has a key binding the keystroke is typed in the text area and it triggers the key binding. Any ideas on how to allow the editing of nodes, while still implementing hotkeys?
Below is an example that demonstrates the behavior. The "1" and "2" keys are bound, so if you type either one in the text area, you'll see the popup.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class KeyBindingTest {
static JButton button1;
static JButton button2;
static JPanel panel;
public KeyBindingTest() {
panel = new JPanel(new BorderLayout());
JToolBar tb = new JToolBar();
tb.setFloatable(false);
button1 = new JButton("First Button");
button1.addActionListener(new ButtonAction());
button2 = new JButton("Second Button");
button2.addActionListener(new ButtonAction());
tb.add(button1);
tb.add(button2);
panel.add(tb, BorderLayout.PAGE_START);
JTextArea ta = new JTextArea(10, 30);
JScrollPane opts = new JScrollPane(ta);
panel.add(opts, BorderLayout.PAGE_END);
setKeyBindings(tb);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
KeyBindingTest test = new KeyBindingTest();
test.createAndShowUI();
}
});
}
private void setKeyBindings(JToolBar tb) {
tb.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_1, 0), "first");
tb.getActionMap().put("first", new ButtonAction());
tb.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_2, 0), "second");
tb.getActionMap().put("second", new ButtonAction());
}
private void createAndShowUI() {
JFrame frame = new JFrame();
frame.getRootPane().setDefaultButton(button1);
frame.setLayout(new BorderLayout());
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public class ButtonAction extends AbstractAction {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(panel, "You pressed a button \n" + e.paramString());
}
}
}
This is a reason why typically hotkeys have an Alt or Control modifier.
You can modify the Action to determine which component has focus:
#Override
public void actionPerformed(ActionEvent e)
{
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Component focusedComponent = kfm.getFocusOwner();
if (focusedComponent instanceof JTextArea)
return;
JOptionPane.showMessageDialog(panel, "You pressed a button \n"+e.paramString());
}
It's been a while since I've done Swing, but I think you can call consume() on the ActionEvent to prevent it from being passed to other listeners. I.e., if you call consume before the keystroke hits the other listeners, you can prevent the numbers from showing up in the field.
To clarify:
public class ButtonAction extends AbstractAction
{
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(panel, "You pressed a button \n"+e.paramString());
e.consume();
}
}
You might have to account for the order of the listeners though (like I said, it's been a while.)

How can I switch focus to a canvas?

I have this class and I want to switch focus to the Game class right after it was invoked. I might've not understand the purpose of focus but when I press start I have to click on the game canvas itself so I can use the keyboard . In other words: How can I make it so I don't have to click on it to use the keyboard?
package com.runner.panels;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import com.runner.main.Game;
import com.runner.main.Main;
public class PlayPanel extends JPanel{
private static final long serialVersionUID = 1L;
public PlayPanel(){
//setting the layout of the playpanel to null
setLayout(null);
//setting up the info panel : high score, meters ran, pause button etc...
JPanel info = new JPanel();
info.setBounds(0,0,1200,50);
add(info);
//back button
JButton back = new JButton("Back");
info.add(back);
Game game = new Game();
game.setBounds(0,50,1200,521);
game.setBackground(Color.black);
add(game);
back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) Main.mainp.getLayout();
cl.show(Main.mainp, "Menu");
}
});
}
}
Off topic: (kinda)
The fact that you are doing Main.mainp.getLayout();, calling the panel statically tells me you have poor design and should be looking into other options like an Model-view-controller pattern, an Observer pattern, or at the very least passing a reference of of the Main to the panel, instead of using static objects/calls.
Back on topic
Sounds like a common KeyListener problem. Generally to gain focus you call requestFocusInWindow(). But you still have to worry about other components stealing the focus way after the fact.
I would instead recommend using Key Bindings instead of KeyListener. You have more control over the focus. For instance, by using
InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("SPACE"), "hitSpace");
panel.getActionMap().put("hitSpace", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
// do something.
}
});
The panel will have immediate access to the action once you show it from the CardLayout. If you happen to use any other components that would steal the focus away from the panel, the action is still accessible because of the WHEN_IN_FOCUSED_WINDOW input map
Here's a simple example. Type A if it is on panel A, you will see it print. If you type B, it won't print because panel A is in the window. Also if you try and press the button in the panel to steal the focus, you can still type and it will still print. Same goes for panel B
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Main {
CardLayout layout = new CardLayout();
JPanel panel = new JPanel(layout);
JPanel p1 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JPanel p2 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JButton b1 = new JButton("panelA");
JButton b2 = new JButton("panelB");
public Main() {
addKeyBind(p1, "pressA", "A");
addKeyBind(p2, "pressB", "B");
p1.add(new JButton("Button for Panel A"));
p2.add(new JButton("Button for Panel B"));
panel.add(p1, "panelA");
panel.add(p2, "panelB");
b1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelA");
}
});
b2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelB");
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(b1);
buttonPanel.add(b2);
JFrame frame = new JFrame();
frame.add(panel);
frame.add(buttonPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void show(String panelName) {
layout.show(panel, panelName);
}
private void addKeyBind(JComponent comp, String name, final String stroke) {
InputMap im = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(stroke), name);
comp.getActionMap().put(name, new AbstractAction(){
public void actionPerformed(ActionEvent e) {
System.out.println(stroke + " pressed");
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Main();
}
});
}
}
Take some time to go over the link I gave you for Key Bindings to learn more.
Back off-topic
Take a look at #AndrewThompson's comment about the null layouts. Learn how to use the LayoutManagers
I believe your problem would be fixed if you add
setFocusable(true);
to your PlayPanel constructor (works for me).
Also, if you want a specific Panel in your GUI to have focus when you start your application, follow the link in the comment of "user3218114", as this will explain how to implement this functionality with Listeners.
Good luck!
You don't need to do anything. The container should be focusable for that.
Here is a code to demonstrate.
package one;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
public class PlayPanel extends Canvas {
public static void main(String... args) {
PlayPanel p = new PlayPanel();
p.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
p.msg = "Focus gained";
p.repaint();
}
#Override
public void focusLost(FocusEvent e) {
p.msg = "Focus Lost";
p.repaint();
}
});
p.setBackground(Color.GRAY);
JFrame f = new JFrame();
f.add(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.setLocation(300, 300);
f.setVisible(true);
}
String msg = "NO FOCUS";
public void paint(Graphics g) {
g.drawString(msg, 50, 50);
}
}

Mouse clicks ignored on modal JDialog

I'm having trouble understanding the behaviour of a modal JDialog.
When the dialog is set to visible all works fine until the user clicks back on the parent JFrame that was used to launch it. Although the dialog remains on top as expected, all subsequent mouse clicks back on the JDialog are ignored. The form items in the JDialog can still be filled in, but only if you navigate using tab. Is this normal or am I missing something obvious?
Below is a simple example that illustrates the behaviour:
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class TestApp {
private JFrame frame;
public TestApp() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btnRun = new JButton("run");
btnRun.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
JDialog dialog = getChildDialog();
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
dialog.setVisible(true);
}
});
frame.getContentPane().add(btnRun, BorderLayout.CENTER);
}
public JDialog getChildDialog() {
JDialog dialog = new JDialog();
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
dialog.setBounds(100, 100, 450, 300);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextField(), BorderLayout.CENTER);
panel.add(new JTextField(), BorderLayout.NORTH);
panel.add(new JTextField(), BorderLayout.SOUTH);
panel.add(new JLabel("Blah"), BorderLayout.EAST);
panel.add(new JLabel("Blah"), BorderLayout.WEST);
dialog.getContentPane().setLayout(new BorderLayout());
dialog.getContentPane().add(panel, BorderLayout.CENTER);
return dialog;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestApp window = new TestApp();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Thank you for the feedback. I think this must be a bug in the JVM I'm using (OpenJDK 2.4.7 7u55-2.4.7-1ubuntu1).
I've just run the same code on a Windows Java 7 JVM and don't get the same behaviour. I will submit a bug report.

Adding Text In a New Window

I'm in a bit of a situation here.I'm making a new program, when you click on the menu bar it opens a new window for the Licence, now here is the problem, how would I add text into that new window, here is my code for the new window:
JFrame frame = new JFrame("Licence");
frame.setSize(500,120);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
I know this is a easy question, I just can't think of the correct code for it.
You can try something like
JDialog dialog = new JDialog(your_frame_reference, "Licence");
dialog .setModal(true);
dialog .setLocationRelativeTo(null);
dialog. getContentPane().add(new JLabel(your_text);
dialog .setVisible(true);
You can use label
JFrame frame = new JFrame("Licence");
JLabel label = new JLabel("Text-Only Label");
label.setFont(new Font("Serif", Font.PLAIN, 36));
frame.add(label);
You can add text by creating JLabels like so:
JLabel label = new JLabel("Hello World");
This can then be added to your JFrame.
Try this Example
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestDialog {
protected static void initUI() {
JPanel pane = newPane("Label in frame");
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.pack();
frame.setVisible(true);
}
public static JPanel newPane(String labelText) {
JPanel pane = new JPanel(new BorderLayout());
pane.add(newLabel(labelText));
pane.add(newButton("Open dialog"), BorderLayout.SOUTH);
return pane;
}
private static JButton newButton(String label) {
final JButton button = new JButton(label);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window parentWindow = SwingUtilities.windowForComponent(button);
JDialog dialog = new JDialog(parentWindow);
dialog.setLocationRelativeTo(button);
dialog.setModal(true);
dialog.add(newPane("Label in dialog"));
dialog.pack();
dialog.setVisible(true);
}
});
return button;
}
private static JLabel newLabel(String label) {
JLabel l = new JLabel(label);
l.setFont(l.getFont().deriveFont(24.0f));
return l;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}

Categories