I am really new to GUI, got a little problem when I was trying to study it.
Ok here is my code.
public class Sample implements ActionListener{
public void go() {
JButton button = new JButton("Click");
JFrame frame = new JFrame();
frame.getContentPane().add(button);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(100,100);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
button.setText("Hello");
}
});
}
It keeps telling me that The method addActionListener(ActionListener) in the type AbstractButton is not applicable for the arguments (new ActionListener(){}). I don't get it because I remember I did it before and it could work.
......
I don't get an error but the action listener won't work because the action performed method of the ActionListener Interface needs to overriden.
button.addActionListener(new ActionListener() {
// add the annotation below
#Override
public void actionPerformed(ActionEvent e) {
button.setText("hello");
}
});
And typically you would build the JFrame in the main method. Later they added an Invoke Later runner that when the class extends JFrame it would create the window in a more object oriented manner.
public class App extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new App();
frame.setVisible(true);
} catch (Exception e){
e.printStackTrace();
}
}
});
}
public App(){
JButton button = new JButton("Click");
getContentPane().add(button);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(100,100);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
button.setText("hello");
}
});
}
}
Related
I'm trying to change button action in a subclass because the form is pretty much exactly the except one asks for an ID. What I i tried doing was making a ActionListener object and instantiating it to an object of an anonymous class like so:
class ParentClass extends JPanel{
JButton button;
ActionListener buttonAction;
ParentClass{
button = new JButton("Parent Action");
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the parent class");
}
};
button.add(buttonAction);
add(button);
}
}
class ChildClass extends ParentClass{
JButton button;
ActionListener buttonAction;
ChildClass{
super();
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the child class");
}
};
}
}
public static void main(String[] args){
JFrame frame = new JFrame;
frame.add(new ChildClass());
frame.setSize(600, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
I was trying to use this method but the actionPerformed of buttonAction is never called. How can I make the button action different for the parent class and the subclass?
You can let parent class implement ActionListener, then use button.addActionListener(this) in order to add the action to button. Then in the subclass #Override actionPerformed method:
class ParentClass extends JPanel implements ActionListener
{
ParentClass()
{
JButton button = new JButton("something");
button.addActionListener(this);
add(button);
}
#Override
public void actionPerformed(ActionEvent event)
{
System.out.println("I am the parent.");
}
}
class SubClass extends ParentClass
{
SubClass()
{
super();//initialize button
}
#Override
public void actionPerformed(ActionEvent event)
{
System.out.println("I am the child.");
}
}
Another way is to add the ActionListener and inside it, only call a method. Something like buttonPressed. Then in subclass #Override buttonPressed method.
A complete example:
public class Test extends JFrame {
public Test() {
super("test");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new GridLayout(2, 1));
add(new ParentPanel());
add(new ChildPanel());
pack();
setLocationByPlatform(true);
}
private class ParentPanel extends JPanel implements ActionListener {
public ParentPanel() {
super(new BorderLayout());
JButton button = new JButton("My Class:" + getClass());
button.addActionListener(this);
add(button);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Parent");
}
}
private class ChildPanel extends ParentPanel {
public ChildPanel() {
super();
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Child");
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Test().setVisible(true));
}
}
I the method I posted works. The issue is if you don't remove and add the button to the subclass it doesn't change the action that will run
class ParentClass extends JPanel{
JButton button;
ActionListener buttonAction;
ParentClass{
button = new JButton("Parent Action");
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the parent class");
}
};
button.add(buttonAction);
add(button);
}
}
So in the subclass what you would do is this:
class ChildClass extends ParentClass{
JButton button;
ActionListener buttonAction;
ChildClass{
super();
buttonAction = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button was clicked by the child class");
}
};
button.removeActionListener(button.getActionListeners()[0]);
button.addActionListener(buttonAction);
}
}
I, however, do not know why but would like an explanation as to why buttonAction had to be re-registered.
I am having difficulty when trying to return to previous JFrame. In FirstFrame, it has a parameter. In secondFrame, how can I back to firstFrame since it does not has parameter ?
I am pulling my hair out of this. Any help would be appreciated.
FirstFrame.java
public class FirstFrame extends JFrame
{
public FirstFrame(final String name)
{
goToSecondFrame.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
SecondFrame sec= new SecondFrame();
sec.createAndShowGui();
sec.setVisible(true);
setVisible(false);
dispose();
}
});
}
}
SecondFrame.java
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
static void createAndShowGui() {
JFrame frame = new JFrame("Second Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Second());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public Second()
{
back.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
FirstFrame back = new FirstFrame(); // Getting error
back.setVisible(true);
setVisible(false);
dispose();
}
});
}
Define your frame first in the top of the class:
JFrame frame = new JFrame("Delete Admin");
and then do like this:
back.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
staffManagment back = new staffManagment("");
back.setVisible(true);
setVisible(false);
frame.dispose();
}
});
I've got class 'Frame' which extends JFrame and separetad JPanels: MainMenu and SinglePanel
I am using CardLayout, but I've got problem when switching back to panels using buttonSingle and powrot buttons. So my question is how can I change/swap between cards using these buttons?
My Frame class:
public class Frame extends JFrame{
CardLayout cl = new CardLayout();
final MainMenu menuPanel = new MainMenu();
final SinglePanel singlePanel = new SinglePanel();
public Frame(){
setLayout(cl);
add(menuPanel,"menu");
add(singlePanel,"single");
setSize(200, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
setEnabled(true);
swapView("menu");
}
public void swapView(String view){
cl.show(getContentPane(),view);
}
}
my MainMenu class:
public class MainMenu extends JPanel{
public MainMenu(){
setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
add(Box.createVerticalGlue());
JButton buttonSingle = new JButton("Single");
buttonSingle.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonSingle.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
}
});
add(buttonSingle);
add(Box.createVerticalGlue());
JButton buttonMulti = new JButton("Multiplayer");
buttonMulti.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonMulti.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
});
add(buttonMulti);
add(Box.createVerticalGlue());
JButton buttonExit = new JButton("Wyjście");
buttonExit.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonExit.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
add(buttonExit);
add(Box.createVerticalGlue());
}
}
my SinglePanel class
public class SinglePanel extends JPanel{
SinglePanel(){
setLayout(new FlowLayout());
JButton powrot = new JButton("Wróć do menu");
powrot.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
}
});
add(powrot);
}
}
Main class:
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
/*MainMenu mM = new MainMenu();*/
Frame f = new Frame();
}
}
You need a reference to the CardLayout of the JFrame inside your panel classes. What you can do is pass the Frame to the JPanel classes as reference, then you can use the CardLayout of the Frame in those classes to show or next etc. Something like
public class MainMenu {
private CardLayout layout;
private Frame frame;
public MainMenu(final Frame frame) {
this.frame = frame;
this.layout = (CardLayout)frame.getLayout();
JButton buttonSingle = new JButton("Single");
buttonSingle.setAlignmentX(Component.CENTER_ALIGNMENT);
buttonSingle.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
layout.show(frame, "single");
}
});
}
}
When you create the MainPanel, you need to pass Frame.this to it, referencing the current Frame
MainMenu menuPanel = new MainMenu(Frame.this);
EDIT
I just noticed your swapView method. So instead of use the CardLayout directly in the panel class, you can actually just call swapView in the actionPerformed
frame.swapView("single");
Or better yet, as to not expose the Frame class, you can have the Frame class implement an interface say SwapInterface that has a method swapView you need to override. And pass the SwapInterface to the panel classes. Something like
public interface SwapInterface {
public void swapView(String view);
}
public Frame extends JFrame implements SwapInterface {
MainMenu mainPanel = new MainMenu(Frame.this);
....
#Override
public void swapView(String view) {
cl.show(getContentPane(), view);
}
}
public class MainMenu extends JPanel {
private SwapInterface swap;
public MainMenu(SwapInterface swap) {
this.swap = swap;
...
public void actionPerfomed(ActionEvent e) {
swap.swapView("single");
}
}
}
Side Note
As HovercraftFullOfEels pointed out in his comment, you should make use of String contants for the String card values so there's no mistakes. Something like
private static final String SINGLE_CARD = "single";
Then in places where you use "single", use SINGLE_CARD instead
When I pressed the ENTER my JTextArea starts a new row and I only want do to the doClick() method nothing else.
How should I do that?
textarea.addKeyListener(new KeyListener(){
#Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
button.doClick();
}
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
});
Use .consume():
Consumes this event so that it will not be processed in the default
manner by the source which originated it.
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
e.consume();
button.doClick();
}
}
Documentation
You should use KeyBindings with any JTextComponent in question. KeyListeners are way too low level from Swing's perspective. You are using the concept which was related to AWT, Swing uses KeyBindings to do the same task with more efficiency and provides desired results :-)
A small program for your help :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class KeyBindingExample {
private static final String key = "ENTER";
private KeyStroke keyStroke;
private JButton button;
private JTextArea textArea;
private Action wrapper = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
button.doClick();
}
};
private void displayGUI() {
JFrame frame = new JFrame("Key Binding Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(new BorderLayout(5, 5));
textArea = new JTextArea(10, 10);
keyStroke = KeyStroke.getKeyStroke(key);
Object actionKey = textArea.getInputMap(
JComponent.WHEN_FOCUSED).get(keyStroke);
textArea.getActionMap().put(actionKey, wrapper);
button = new JButton("Click Me!");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.format("Button Clicked :-)%n");
}
});
contentPane.add(textArea, BorderLayout.CENTER);
contentPane.add(button, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new KeyBindingExample().displayGUI();
}
};
EventQueue.invokeLater(r);
}
}
I want to dispose the frame 3 seconds after I type a key.
Here is my code:
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
Timer t = new Timer(3000, null);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("test");
frame.dispose();
}
});
t.start();
}
}
I can see from the console the printed string but the frame is not closing.
I've seen a similar thread and use the Timer seemed to be the solution but it's not working for me.
frame.dispose() isn't guarenteed to execute immediately. I've found calling frame.setVisible(false) first helps speed up the disposing process.
EDIT
Also, you might want to look at using Key Bindings instead of key listeners for triggering your event. Key Listeners are complicated and generally not very useful (they require focus on the item you're interacting with, they tend to consume events so you don't see them).
EDIT 2
After further examination of your code, the problem seems to be that you need to set the timer to not repeat (before you call start):
t.setRepeats(false);
This example works for me - let me know if you're still experiencing a problem (and if so, please post a runnable example of the problem you're experiencing - I can only guess at any additional code that could cause problems):
import java.awt.event.*;
import javax.swing.*;
public class QuickTest {
public QuickTest(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
Timer t = new Timer(3000, null);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("test");
frame.dispose();
}
});
t.setRepeats(false);
t.start();
}
});
}
public static void main(String[] args){
new QuickTest();
}
}
Seems to work fine for me.
Make sure that the setDefaultCloseOperation is not set to DO_NOTHING as it will, do nothing
public class TestCloseFrame {
public static void main(String[] args) {
new TestCloseFrame();
}
public TestCloseFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
JButton close = new JButton("Close");
close.addActionListener(new CloseAction(frame, close));
frame.add(close);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class CloseAction implements ActionListener {
private JButton button;
private JFrame frame;
private int count = 0;
public CloseAction(JFrame frame, JButton button) {
this.button = button;
this.frame = frame;
}
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
count++;
button.setText(Integer.toString(4 - count));
if (count > 3) {
frame.dispose();
Timer timer = (Timer) e.getSource();
timer.stop();
}
}
});
timer.setInitialDelay(0);
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
}
}