JButton KeyPressed - Nothing Happens - java

I'm trying to make it so that pressing the right arrow key does the same thing as pressing a JButton. I can bind the right arrow key to the button itself - but that means I have to have pressed the button before the right key works. Now I'm trying to see if binding to the actual JFrame is what I want, but I can't get anything to happen when I bind to the frame at all:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
onButtonPress();
}
private void formKeyPressed(java.awt.event.KeyEvent evt) {
if (evt.getKeyCode() == KeyEvent.VK_RIGHT){
onButtonPress();
}
}
private void onButtonPress() {
pressNum++;
jLabel1.setText("Button has been pressed " + pressNum + " times.");
}

As a general rule of thumb, you should avoid KeyListener. The main reason is, in order for a KeyListener to generate key events, the component it is registered to must be focusable AND have keyboard focus. In your case, this would probably mean adding a KeyListener to every component in your UI which "might" gain keyboard focus, not something which is practical in the real world.
Instead, you should make use of the Key Bindings API, which provides you the means to define the level of focus required in order for it to trigger the associated actions.
The Key Bindings API and the example make use of the Actions API, which allows me to define a single unit of work which can be applied to a number of "actionable" controls
The example also makes use of a delegate/callback/listener (namely CounterListener) which allows me to decouple the "side effects" from the action itself.
This basically means that the Action can do what it needs to do, but "other" interested parties can perform some other action when it changes. You could, equally attach an ActionListener to the Action, but this was just simpler and quicker to implement
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
JLabel label = new JLabel("...");
MyAwesomeAction action = new MyAwesomeAction(new CounterListener() {
#Override
public void counterChanged(int count) {
label.setText("Button has been pressed " + count + " times");
}
});
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
JButton button = new JButton(action);
add(button, gbc);
add(label, gbc);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "MakeItSo");
am.put("MakeItSo", action);
}
}
public interface CounterListener {
public void counterChanged(int count);
}
public class MyAwesomeAction extends AbstractAction {
private int count;
private CounterListener listener;
public MyAwesomeAction(CounterListener listener) {
putValue(NAME, "Make it so");
this.listener = listener;
}
#Override
public void actionPerformed(ActionEvent e) {
count++;
listener.counterChanged(count);
}
}
}

This example has a JButton with two listeners: an ActionListener and and a KeyListener. The key listener is implemented with the KeyAdapter abstract class. From the API documentation:
KeyAdapter is for receiving keyboard events. The methods in this class
are empty. This class exists as convenience for creating listener
objects.
Create a listener object using the extended class and then register it
with a component using the component's addKeyListener method. When a
key is pressed, released, or typed, the relevant method in the
listener object is invoked, and the KeyEvent is passed to it.
The example code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ButtonListeners {
private JLabel label;
private int counter;
public static void main(String [] args) {
new ButtonListeners().gui();
}
private void gui() {
JFrame frame = new JFrame();
frame.setTitle("JButton Listeners");
JButton button = new JButton("jButton1");
button.addActionListener(actionEvent -> displayLabel());
button.addKeyListener(new ButtonKeyPressListener());
label = new JLabel("Press button or -> key");
frame.add(button, BorderLayout.SOUTH);
frame.add(label, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(300, 150);
frame.setVisible(true);
}
private void displayLabel() {
label.setText("Action count: " + ++counter);
}
private class ButtonKeyPressListener extends KeyAdapter {
#Override public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
displayLabel();
}
}
}
}

Related

Why is my program not listening to keyEvents?

I am trying to develop a main menu for a game in java, but my JMenuItems wouldn't listen to the KeyEvents and I don't understand why. Note that I don't want to set any JMenuBars nor JMenus as this program is intended to be a game used with screen readers, so I don't want accessibility roles to be read. Furthermore, adding a menu complicates the access to the elements with the keyboard and I want the focus to start in the first option.
This is my code:
import java.util.Set;
import java.util.HashSet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.MenuKeyEvent;
import javax.swing.event.MenuKeyListener;
public class Screen {
public Screen() {
// Accept arrow keys as focus traversal keys
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTrave rsalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,set);
// definition of Menu Items
JMenuItem mi=new JMenuItem("play");
JMenuItem mi2=new JMenuItem("exit");
mi.setFocusable(true);
mi2.setFocusable(true);
// Attempt with MenuKeyListener
mi.addMenuKeyListener(new MenuKeyListener() {
public void menuKeyReleased(MenuKeyEvent e) {
System.out.println("Play released");
}
public void menuKeyTyped(MenuKeyEvent e) {}
public void menuKeyPressed(MenuKeyEvent e) {}
});
// Attempt with ActionListener
mi2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
mi.setVisible(true);
mi2.setVisible(true);
JPanel mp = new JPanel();
JFrame mf = new JFrame("Game");
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mp.add(mi);
mp.add(mi2);
mf.add(mp);
mf.setVisible(true);
}
public static void main(String args[]) {
new Screen();
}
}
I've tried with both ActionListener and MenuKeyListener, with and without the JPanel, changing visibilities... I also tried to use KeyEventDispatcher but I didn't know how to send a KeyEvent to the component that returns KeyboardFocusManager.getFocusOwner().
Please help.
There's a lot to help with in this case. For starters,
public static void main(String args[]) {
new Screen();
}
is wrong. It is not appropriate to perform any operation that alters the Swing layout or presentation on the main thread. Instead do
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Screen();
}
});
}
if you decide that you want to put swing calls into an object's constructor in this way.
Ideally your Screen would be a JFrame but one that is customized to meet your needs. That means you might want to create a new class GamePanel that extends JPanel
public class Screen extends JFrame {
public Screen() {
super("Game"); // to remind us that the JFrame is created
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel());
pack();
setVisible(true);
}
}
public class GamePanel extends JPanel {
public GamePanel() {
super();
}
}
Now, if you want that panel to listen to keys, you need to add a KeyListener interface. This only gives it the capability to listen, it doesn't make it listen.
public class GamePanel extends JPanel implements KeyListener {
...
public void keyTyped(KeyEvent e) {
System.out.println("KEY TYPED: " + e);
}
public void keyPressed(KeyEvent e) {
System.out.println("KEY PRESSED: " + e);
}
public void keyReleased(KeyEvent e) {
System.out.println("KEY RELEASED: " + e);
}
}
Now you can add your key listener to the Screen or to the GamePanel (it will listen to itself). Whenever the focus is in one of these items, and a key is pressed, the even will be routed to the listener.
public class GamePanel extends JPanel implements KeyListener {
public GamePanel() {
super();
addKeyListener(this);
}
...
}
Ideally, you might want to not combine your key listener with the panel itself, but make it a "Command Processor" of some sort. In that case, remove the KeyListener code from the JPanel and make a completely new CommmandHandler object that implements KeyListener.
As far as Actions go, they are convenience items that pre-configure menu entries with lots of things (icons, acceleration keys, text, callback functions). If you are avoiding menus for whatever reason, you will find that much of their utility in setting up menus is misdirected for your purpose. Effectively, they are configuration entries that configure the MenuItem objects to handle a key (through the KeyListener interface and then dispatch a swing Event object. This provide "better than key" tracking of items through an application as it converts a keyboard letter k to a class ActionEvent which is passed to the registered "action handler" typically a subclass of AbstractAction.
An example of an Action would be
public class MoveLeft extends AbstractAction { // which extends ActionListener
private final GameState gameState;
public MoveLeft(GameState gameState) {
super("move left", new ImageIcon(MoveLeft.class.getResource("/images/moveleft.png"));
putValue("SHORT_DESCRIPTION", "left");
putValue("MNEMONIC_KEY", "l");
this.gameState = gameState;
}
public void actionPerformed(ActionEvent e) {
gamestate.getSelected().moveLeft();
}
}
Assuming you wanted this convenience, you would initialize your CommandHandler with Actions, maybe like so:
public CommandHandler implements KeyListener {
private int actionId;
...
public void addAction(Action action) {
handlers.put(action.getValue("MNEMONIC_KEY")., action);
}
public void keyTyped(KeyEvent e) {
Action action = handlers.get(String.valueOf(e.getKeyChar());
ActionEvent event = new ActionEvent(this, id, action.getValue("NAME"));
action.actionPerformed( event );
}
}
As you can see, the added convenience of having Actions defined for the actions within your game is a balanced by making your components that use them be configured by them (and using them in the KeyListener implementations).
For large projects, the simplicity of having all your actions listed generally makes creating Actions well worth the effort; but, for smaller projects that are mostly using custom components, the added one-time-cost of making the KeyListener components use actions might outweigh the benefits.
Don't use JMenuItem this way, that's not how it's intended to be used
Instead, I'd start with JButton. The following makes use of your focus transversal code, the Action API and the key bindings API
import java.awt.AWTKeyStroke;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set);
Action playAction = new AbstractAction("Play") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("play");
}
};
playAction.putValue(Action.MNEMONIC_KEY, (int)'P');
Action exitAction = new AbstractAction("Exit") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("exit");
}
};
exitAction.putValue(Action.MNEMONIC_KEY, (int)'x');
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "play");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), "exit");
am.put("play", playAction);
am.put("exit", exitAction);
JButton playButton = new JButton(playAction);
JButton exitButton = new JButton(exitAction);
add(playButton, gbc);
add(exitButton, gbc);
}
}
}
Now, you could do something similar with JLabel, but, JLabel isn't focusable by default, nor does it render any kind of focus indication. Instead, I might be tempted to just strip down a JButton so it didn't paint its border or content/background instead

Running a method after switching cards in cardlayout

I'm sure someone has asked this question before, but my google-fu is not strong today.
I have a JFrame that uses a CardLayout as its manager. How do I run a "Start" method when I switch to each JPanel without using a switch?
The code I use to add the frames to the layout is:
/**
* Adds JPanels to the Card Layout.
* #param panel is the JPanel to add to the layout.
* #param windowName is the identifier used to recognise the Panel.
*/
public final void addToCards(final JPanel panel, final WindowNames windowName) {
view.getBasePanel().add(panel, windowName.getValue());
}
The code I use to switch the layout is:
/**
* Method to change the JPanel currently visible on the BasePanel.
* #param windowName is the name of the JPanel to change to.
*/
public final void changePanel(final WindowNames windowName) {
view.getCardLayout().show(view.getBasePanel(), windowName.getValue());
}
Currently I have an ActionListener set that will call the switch code, but I can't work out how to call the "Start" method within the screen that it will be switching to.
I have an interface setup for each of the JPanels so that the method name will be identical in each.
You can just use a ComponentListener for the panel(s). When the panel becomes the view of the CardLayout, it will fire a component event and handled by componentShown in your listener (as well as the panel taken out of view, handling the componentHidden). Call your start() method there. This way you don't have to explicitly call the start() when the panel changes, as it be called for you.
See How to Write Component Listeners for more details.
Here is a simple example.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main {
private static final String PANEL_A = "panelA";
private static final String PANEL_B = "panelB";
CardLayout layout = new CardLayout();
JPanel panel = new JPanel(layout);
ComponentListenerPanel p1 = new ComponentListenerPanel(PANEL_A);
ComponentListenerPanel p2 = new ComponentListenerPanel(PANEL_B);
JButton b1 = new JButton(PANEL_A);
JButton b2 = new JButton(PANEL_B);
public Main() {
panel.add(p1, PANEL_A);
panel.add(p2, PANEL_B);
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
show(PANEL_A);
}
});
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
show(PANEL_B);
}
});
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 class ComponentListenerPanel extends JPanel {
private String panelName;
public ComponentListenerPanel(String panelName) {
this.panelName = panelName;
addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent evt) {
stop();
}
#Override
public void componentShown(ComponentEvent evt) {
start();
}
});
}
public void start() {
System.out.println(panelName + " started");
}
public void stop() {
System.out.println(panelName + " stopped");
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}
});
}
}
Note you haven't actually said where the start method is, so this code/answer is just assuming you have some start method in custom panel. Hope I guessed right. In the future, or even now, you should always post an MCVE so that we don't have to do all this guessing.
I have an interface setup for each of the JPanels so that the method name will be identical in each
So then the problem is getting the current panel that is visible when the panels are swapped so you can invoke the method.
Check out Card Layout Focus for a class that extends CardLayout to provide a few helper methods to add additional functionality for the CardLayout. You would use the getCurrentCard() method.
So your changePane(...) method might be something like:
public final void changePanel(final WindowNames windowName) {
//view.getCardLayout().show(view.getBasePanel(), windowName.getValue());
RXCardLayout layout = view.getCardLayout();
layout.show(view.getBasePanel(), windowName.getValue());
MyInterface panel = (MyInterface)layout.getCurrentCard();
panel.someMethod(...);
}
Of course you would also need to use the RXCardLayout as the layout manager for your main panel.

Using Keybinding

I'm doing some very basic coding, just trying to learn the basic concepts behind keybinding. It all seems very straightforward but there's something wrong with my logic or structure that is keeping my code from executing the way I want it to.
Here is my code
public class Board {
ButtonListener buttonlistener;
EnterAction enterAction;
public Board(){
JFrame skeleton = new JFrame();
skeleton.setDefaultCloseOperation(EXIT_ON_CLOSE);
skeleton.setVisible(true);
skeleton.setSize(400, 400);
buttonlistener = new ButtonListener();
enterAction = new EnterAction();
JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
JButton button = new JButton("button");
button.addActionListener(buttonlistener);
panel.add(button);
skeleton.add(panel);
panel.getInputMap().put(KeyStroke.getKeyStroke("s"), "doEnterAction");
panel.getActionMap().put("doEnterAction", enterAction);
}
public class ButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("button pressed");
}
}
public class EnterAction extends AbstractAction{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("enter pressed");
}
}
public static void main(String[] args){
new Board();
}
So, it should be pretty simple. As you can see I'm just trying to make it print out "enter pressed" whenever you press enter, but it isn't printing out anything (unless you click the button also shown in the code above). Also, in eclipse, the EnterAction class is underlined in yellow, I think it may not be being called right, but I don't know why it wouldn't be.
Any help is appreciated, thanks.
Change
panel.getInputMap().put(KeyStroke.getKeyStroke("s"), "doEnterAction");
To
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "doEnterAction");
Also
skeleton.setDefaultCloseOperation(EXIT_ON_CLOSE);
the parameter must be JFrame.EXIT_ON_CLOSE or just put number 3.
The immediate issue I can see is with the following statement
panel.getInputMap().put(KeyStroke.getKeyStroke("s"), "doEnterAction");
KeyStroke.getKeyStroke("s") is going to return null. The requirements for the String passed to this method are very particular and not well documented (IMHO).
You could use KeyStroke.getKeyStroke("S") instead, but I prefer to use KeyStroke.getKeyStroke(KeyEvent.VK_S, 0) as there is no chance of ambiguity in the statement.
I would also recommend that you define the focus boundaries as well for the input map...
Instead of panel.getInputMap(), try using panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) to ensure that the key event will be triggered if the window is focused
Take a look at JComponent#getInputMap for more details.
If you haven't already done so, you should also take a look at How to use Key Bindings
I think Azad and MadProgrammer are correct, I only had to make one more simple change in addition to what they recommended to get the program running. I have numbered the three items for you as a comment in the code: (copy and paste and you are good to go).
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Board {
ButtonListener buttonlistener;
EnterAction enterAction;
public Board() {
JFrame skeleton = new JFrame();
//Change #1 below
skeleton.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
skeleton.setVisible(true);
skeleton.setSize(400, 400);
buttonlistener = new ButtonListener();
enterAction = new EnterAction();
JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
JButton button = new JButton("button");
button.addActionListener(buttonlistener);
panel.add(button);
skeleton.add(panel);
//Change #2 below
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke("S"), "doEnterAction");
panel.getActionMap().put("doEnterAction", (Action) enterAction);
}
public class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("button pressed");
}
}
public class EnterAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("enter pressed");
}
}
public static void main(String[] args) {
new Board();
}
//Change #3 below
}
here is the screenshot:

accessing swing component of other class

I have two classes mainpanel.java and subpanel.java. The subpanel.class contains a checkbox and some labels. I want to change the setSelected() and setText() of these components when i click some buttons in the mainpanel.java .
I have created a method in subpanel.java which i call from mainpanel.java and pass the boolean values.
public void schedulerchange(boolean check){
System.out.println("checked"+check);
scheduleenabler.setEnabled(check);
scheduleenabler.setSelected(check);
scheduleinfo.setText("Scheduler in On");
//subpanel21.updateUI();
}
When i call this function from mainpanel.java the function is called but the values don't change unless i make jcheckbox and jlabel static. But from what i learned we should not use static components unless very necessary.
Is there some other way to change the components?
If I have understood your question then I think you want to write a separate ActionListener class and perform action there which will enable or disable the JCheckBox in the UI-class. The below code shows that. Pass your checkbox reference to that PerformAction class and make it enabled or disabled by clicking on the button.
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MainClass {
MainClass() {
JFrame jfrm = new JFrame("JTable Demo");
jfrm.setLayout(new FlowLayout());
jfrm.setSize(460, 180);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JCheckBox check = null;
// Get the Panel from the subclass;
JPanel panel = new CheckBox().getCheckBoxPanel();
// From the compoenents present in the panel get the CheckBox compoenent.
for(int i = 0; i < panel.getComponentCount(); i++) {
if(panel.getComponent(i) instanceof JCheckBox) {
check = (JCheckBox) panel.getComponent(i);
}
}
JButton button = new JButton("Click");
// Pass the CheckBox Compoenent to the ActionListener.
button.addActionListener(new PerformAction(check));
jfrm.add(button);
jfrm.add(panel);
jfrm.setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MainClass();
}
});
}
}
class PerformAction implements ActionListener {
JCheckBox check = null;
public PerformAction(JCheckBox checkBox) {
check = checkBox;
}
#Override
public void actionPerformed(ActionEvent e) {
boolean checkStatus = check.isSelected();
if(checkStatus == true) {
check.setEnabled(false);
check.setSelected(false);
} else {
check.setEnabled(true);
check.setSelected(true);
}
}
}
class CheckBox {
public JPanel getCheckBoxPanel() {
JPanel checkPanel = new JPanel();
JCheckBox check = new JCheckBox();
checkPanel.add(new JLabel("CheckBox"));
checkPanel.add(check);
return checkPanel;
}
}
This is not an appropriate use of updateUI(), which "Resets the UI property to a value from the current look and feel." Using revalidate(), as suggested in a comment, would be helpful only if components are added to, or removed from, the enclosing Container. Instead, invoke repaint() directly on the sub-panel instance. For greater flexibility, use the observer pettern suggested here.
Addendum: This example use Action to encapsulate the button's behavior. Because the checkbox's selected state is a bound property, the component is repainted automatically, but you can invoke repaint() explicitly if needed.
Addendum: Update to pass a reference as a parameter.
Addendum: In this variation, the parameter is a reference to the exported Action.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/a/14412516/230513 */
public class Example {
private void display() {
JFrame f = new JFrame("Example");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0, 1));
JPanel panel = new JPanel();
final JCheckBox check = new JCheckBox("Check");
Action checkAction = new AbstractAction("Update") {
#Override
public void actionPerformed(ActionEvent e) {
check.setSelected(!check.isSelected());
}
};
panel.add(check);
f.add(panel);
f.add(new SubPanel(checkAction));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class SubPanel extends JPanel {
public SubPanel(final Action action) {
this.add(new JButton(action));
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example().display();
}
});
}
}

How to display different components in a JFrame?

I am very new to Java AWT. My question header must seem ridiculous to you, sorry about that. In my application I have three buttons which display different threads when clicked on. Now I want to add maybe a button or checkboxes or choicelist, etc when clicked on a particular button. For eg, if I click on yes button, it should display a choice list, something like that. How do I achieve something like that? Here is my code so far:
import java.awt.Button;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class AppWindow extends Frame implements ActionListener{
String keymsg = "Test message";
String mousemsg = "Nothing";
int mouseX=30, mouseY=30;
String msg;
public AppWindow(){
//addKeyListener(new MyKeyAdapter(this));
//addMouseListener(new MyMouseAdapter(this));
addWindowListener(new MyWindowAdapter());
}
public void paint(Graphics g){
g.drawString(msg, 150, 100);
}
//Here the window is created:
public static void main(String args[]){
AppWindow appwin = new AppWindow();
appwin.setSize(new Dimension(300,200));
appwin.setTitle("My first AWT Application");
appwin.setLayout(new FlowLayout(FlowLayout.LEFT));
appwin.setVisible(true);
Button yes,no,maybe;
yes = new Button("yes");
no = new Button("no");
maybe = new Button("maybe");
appwin.add(yes);
appwin.add(no);
appwin.add(maybe);
yes.addActionListener(appwin);
no.addActionListener(appwin);
maybe.addActionListener(appwin);
}
#Override
public void actionPerformed(ActionEvent ae) {
// TODO Auto-generated method stub
String str = ae.getActionCommand();
if(str.equals("yes")){
msg = "You pressed Yes";
}
if(str.equals("no")){
msg = "You pressed No";
}
if(str.equals("maybe")){
msg = "You pressed Maybe";
}
repaint();
}
}
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent we){
System.exit(0);
}
}
Points describing what you should be doing :
As already mentioned by others, better to use Swing over AWT, since Swing is more advanced.
As much as possible, always try to Paint on top of a JPanel or a
JComponent, instead of Painting right on top of your JFrame, by
overriding the paintComponent(Graphics g) method of the said
JComponent/JPanel
Never call setVisible(true) on the JFrame until and unless it's
size has been established. So in general terms, this has to be the
last call, once you are done adding components to the JFrame and
the size of the JFrame has been realized by the LayoutManager.
Inside your actionPerformed(...), instead of writing all if
statement blocks, you should adhere to the if-else if statement
blocks. The benefit of this, over the former is that, at any given
time, only one event will be fired, hence once the said condition is
satisfied, you don't want your code to keep checking other
conditions, which in general is really not a good programming
practice, IMHO.
MOST IMPORTANT THING : Never make calls like pack()/setVisible(...) from within the main method, such calls belong
to the Event Dispatch Thread, and must be done on the same. Please
read Concurrency in Swing for more detail.
Have a look at the example program, for better understanding.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ComponentExample
{
private CustomPanel drawingBoard;
private JPanel contentPane;
private JButton yesButton;
private JButton noButton;
private JButton maybeButton;
private JComboBox cbox;
private ActionListener buttonAction = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
JButton button = (JButton) ae.getSource();
if (cbox.isShowing())
contentPane.remove(cbox);
if (button == yesButton)
{
drawingBoard.setText("You Pressed YES.");
contentPane.add(cbox, BorderLayout.PAGE_END);
}
else if (button == noButton)
drawingBoard.setText("You Pressed NO.");
else if (button == maybeButton)
drawingBoard.setText("You Pressed MAYBE.");
/*
* revalidate()/repaint() is needed
* when the JComponent is added or
* removed from the already
* visible Container.
*/
contentPane.revalidate();
contentPane.repaint();
}
};
public ComponentExample()
{
cbox = new JComboBox(
new String[]{"I GOT IT"
, "I STILL HAD DOUBT"});
}
private void displayGUI()
{
JFrame frame = new JFrame("Component Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel();
contentPane.setOpaque(true);
contentPane.setBackground(Color.DARK_GRAY);
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(5, 5));
JPanel buttonPanel = new JPanel();
buttonPanel.setOpaque(true);
buttonPanel.setBackground(Color.WHITE);
yesButton = new JButton("YES");
yesButton.addActionListener(buttonAction);
noButton = new JButton("NO");
noButton.addActionListener(buttonAction);
maybeButton = new JButton("MAY BE");
maybeButton.addActionListener(buttonAction);
buttonPanel.add(yesButton);
buttonPanel.add(noButton);
buttonPanel.add(maybeButton);
contentPane.add(buttonPanel, BorderLayout.PAGE_START);
drawingBoard = new CustomPanel();
contentPane.add(drawingBoard, BorderLayout.CENTER);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ComponentExample().displayGUI();
}
});
}
}
class CustomPanel extends JPanel
{
private String msg;
public CustomPanel()
{
msg = "";
setOpaque(true);
setBackground(Color.WHITE);
}
public void setText(String msg)
{
this.msg = msg;
repaint();
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(300, 300));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString(msg, getWidth() / 3, getHeight() / 3);
}
}
I don't know if I have understood the question well but... couldn't you create those elements and call their setVisible(boolean) methods to make them not visible at first, and them make them visible when user pushes buttons?

Categories