First off - sorry for the wall of code but it's not too horrendous, just a framework for what I'm trying to explain. It runs without errors.
The goal
I'm making a reuseable button class for my GUI and each button object needs to have a different handler when it's clicked. I want to to assign a ClickHandler object to each new button. Then, the button would call init() on the handler, and be on its way. Unfortunately, there's a typing problem, since each handler class would have a different name.
Current progress
Right now, the handler is typed as HandlerA, but I'd like to have it handle any name, like "SettingsHandler" or "GoToTheWahWah" etc.
I've tried messing about with generic types, but since I'm new to this, and from a webdev background, there seems to be a conceptual hurdle I keep knocking over. Is this the right way to approach the problem?
The code
ReuseableButton.java is a reuseable class, the only thing that changes is the action when it's clicked:
package gui;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class ReuseableButton extends JButton implements ActionListener {
private static final long serialVersionUID = 1L;
// I want a generic type here, not just HandlerA!
private HandlerA ClickHandler;
// Assemble generic button
public ReuseableButton(Container c, String s) {
super(s);
addActionListener(this);
c.add(this);
}
// Once again, generic type, not just HandlerA!
public void SetClickHandler(HandlerA ch) {
ClickHandler = ch;
}
// Call init() from whatever class has been defined as click handler.
public void actionPerformed(ActionEvent e) {
ClickHandler.init();
}
}
Controller.java fires the frame and assembles buttons as needed (right now, only one button).
package gui;
import javax.swing.*;
import java.awt.*;
public class Controller extends JFrame {
private static final long serialVersionUID = 1L;
public Controller() {
JFrame frame = new JFrame("Handler Test GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = frame.getContentPane();
pane.setLayout(new FlowLayout());
ReuseableButton b = new ReuseableButton(pane,"Reuseable Button A");
// THE QUESTION IS HERE: Pass a generic object?
b.SetClickHandler(new HandlerA());
frame.pack();
frame.setSize(200,200);
frame.setVisible(true);
}
public static void main(String args[]) {
new Controller();
}
}
HandlerA.java is a sample of a random handler for the button click. Later, there could be HandlerB, HandlerC, etc.
package gui;
// A random handler
public class HandlerA {
public void init() {
System.out.println("Button clicked.");
}
}
Thanks very much in advance!
All of you handlers should implement an interface like Clickable or something. That way the interface specifies the existence of the init function:
public interface Clickable
{
public void init();
}
Making the HandlerA definition:
public class HandlerA implements Clickable {
public void init() {
System.out.println("Button clicked.");
}
}
I recommend to work with inheritence in this case:
public abstract class AbstractHandler {
public abstract void init();
}
Then:
public class ConcreteHandlerA extends AbstractHandler {
#Override
public void init() {
// do stuff...
}
}
Controller
public class ReuseableButton extends JButton implements ActionListener {
// I want a generic type here, not just HandlerA!
private AbstractHandler ClickHandler;
public Controller() {
//...
ReuseableButton b = new ReuseableButton(pane,"Reuseable Button A");
AbstractHandler handlerA = new ConcreteHandlerA();
b.SetClickHandler(handlerA);
// ...
}
}
Not sure if this is what you're looking for...
BTW: You can define the AbstractHandler as an interface as well, but you may want to implement some common logic here as well - shared across handlers.
You should use an interface for the handler.
public interface ClickHandler() {
void init();
}
ReuseableButton b = new ReuseableButton(pane,"Reuseable Button A");
b.SetClickHandler(object which implements the ClickHandler interface);
This is the same concept as the normal JButton. There you have the ActionListener interface and the actionPerformed method in it.
P.S. If I don't understand your question, please correct me.
Related
I have a problem working with instances of different objects and this is what happens:
I have been developing a small game in Java (Swing & AWT) for a while and I have the following classes:
App.java
Play.java
Event.java
GameScene.java
MenuScene.java
Timer.java
Where:
App extends JFrame and is a frame with the main function of the application (main), this class creates the game window, and only exists this JFrame
The MenuScene and GameScene classes are scenes of the application, for example when you see the menu and you want to see the highest score, it is a scene, the levels of game are a scene, etc., but in this case I have only two scenes and I have represented them in JPanels: MenuScene extends JPanel and creates the game menu (buttons, images, etc.), the same applies to the GameScene class, this also extends JPanel and creates the game.
The other classes (Play, Event, Timer) are simple classes, they have the "logic of the game", keyboard control, timers, game operation and are instantiated in three global variables of the GameScene class.
Everything starts with App, creates an instance of it and in its constructor calls a method to "create" the menu (MenuScene.java). Now the menu has a JButton that when pressed "creates" the game (GameScene.java) and this class has a JButton to return to the menu at any time ... It is here where I have problems because if I am playing and I return to the menu Game still exists and I can lose, it does not make sense, it is as if you play but instead of seeing the game you see the menu, interestingly the graphic part works excellent, ie if I press a button it removes what I have and draws the scene that I want it quickly. It is because Play, Timer and Event are instantiated or "exist" in memory if I am not mistaken. So if I press again the "create game" JButton I would recreate a second instance of GameScene? And so infinitely for MenuScene and GameScene. Is there a solution to this? How do you think I should structure the application?
I give you an outline of the most important classes:
App.java
public class App extends JFrame {
private JPanel rootPanel;
public App() {
//Define frame
...
runScene(new MenuScene(this));
}
public void runScene(JPanel scene) {
destroyScene();
rootPanel.setBackground(scene.getBackground());
rootPanel.add(scene);
rootPane.validate();
rootPanel.repaint();
}
private void destroyScene() {
rootPanel.removeAll();
rootPanel.revalidate();
rootPanel.repaint();
}
public static void main(String[] args) { //Main
new App();
}
}
MenuScene.java
public class MenuScene extends JPanel {
private App app;
public MenuScene(App app) {
this.app = app;
//Define JPanel
...
buttonStart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
app.runScene(new GameScene(app));
}
});
}
}
GameScene.java
public class GameScene extends JPanel {
private App;
private Play;
private Timer;
private Event; //Define controls (keyboard)
public GameScene(App app) {
this.app = app;
//Define JPanel, Play, Timer and Event
...
buttonBackMenu.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
app.runScene(new MenuScene(app));
}
});
}
}
Play.java
public class Play {
private JLabel[][] x;
public Play(JLabel[][] x) { //This matrix is important (is an reference), is instanced in GameScene, this is an problem?
this.x = x;
//Define others variables
}
}
I appreciate any help.
I have found a somewhat peculiar solution, but I do not know if it is the best:
The best way is that since the GC does not select the active timers then it is better to stop them and match the other objects to null. Using the Singleton pattern I have a single instance of a Frame, that same instance would be used in any class (Scene) that wants to run another scene, here an implementation:
App.java
public class App extends JFrame {
private JPanel rootPanel;
private static App app;
private App() {
super("x");
createApp();
}
public static App getInstance() {
if (app == null) {
app = new App();
}
return app;
}
private void createApp() {
//Define JFrame, rootPanel, buttons, etc ...
}
public void runScene(JPanel scene) {
rootPanel.removeAll();
rootPanel.add(scene);
rootPanel.revalidate();
rootPanel.repaint();
}
public static void main(String[] args) { //Main
getInstance().runScene(new MenuScene());
}
}
GameScene.java
public class GameScene extends JPanel {
private Play p;
private Timer t;
private Event e; //Define controls (keyboard)
private JLabel[][] mat;
public GameScene() {
//Define JPanel, Matrix, Play, Timer and Event
...
buttonBackMenu.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent x) {
This method is useful to create another scene for example from another instance other than this (GameScene)
changeScene(new MenuScene());
}
});
}
public void changeScene(JPanel scene) {
e.removeKeyDispatcher(); //You must create a method that allows you to move the event key dispatcher
t.stopAllTimers(); //You must create a method to stop all timers, or any object that is active.
t = null;
e = null;
p = null;
//If you have more active objects and work with other instances of other classes they should be "broken" or "stopped" and then match their instance to null
App.getInstance().runScene(scene);
}
//Optional...
public JLabel[][] getMat() {
return mat;
}
}
Play.java, Event.java, Timer.java (X)
public class X {
private GameScene g;
private JLabel[][] mat;
public X(GameScene g) {
this.g = g;
//I would use the instance of the class I need to access the variables I'm going to use, for example:
this.mat = g.getMat();
}
}
I'm trying to do a simple calculator program by building my swing interface on netbeans.
I want to have 3 Classes:
GUI Class - which holds the codes for building the interface
Listener Class - holds all the listener in the GUI interface
Boot Class - this will start the application
For simplicity, I will post my code for a single button. My goal here is to change the Buttons visible text from "1" to "11" to test my design. After verifying that my design works I will continue on working on other buttons.
calculatorGUI.class
import javax.swing.JButton;
public class calculatorGUI extends javax.swing.JFrame {
public calculatorGUI() {
initComponents();
}
private void initComponents() {
oneBtn = new javax.swing.JButton();
oneBtn.setText("1");
}
private javax.swing.JButton oneBtn;
public JButton getOneBtn() {
return oneBtn;
}
public void setOneBtn(String name) {
oneBtn.setText(name);
}
}
Listener.class
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Listener {
class oneBtnListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent ev) {
calculatorGUI g = new calculatorGUI();
g.setOneBtn("11");
}
}
}
Boot.class
public class Boot {
public static void main(String[] args) {
calculatorGUI gui = new calculatorGUI();
Listener listen = new Listener();
Listener.oneBtnListener oneListen = listen.new oneBtnListener();
gui.getOneBtn().addActionListener(oneListen);
gui.setVisible(true);
}
}
The problem is, nothing happens when I click the button. It seems that the actionListener is not being registered to the button. Can I ask for your help guys on which angle I missed?
The issue I am seeing is how you are initializing calculatorGUI twice, once with the default value and another with the changed value. Take out the initialization of calculatorGUI within your Listener class and pass it from your Boot class and it should work fine.
Although if I were you, I would add the GUI implementations within the GUI class, having it within the listener class that is using within the main function is not something I have seen before and would probably not advise.
Modify your code accordingly,
class Listener {
class oneBtnListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent ev) {
if(ev.getActionCommand() == "1")
{
JButton btn = (JButton)ev.getSource();
btn.setText("11");
}
}
}
}
class calculatorGUI extends javax.swing.JFrame {
public calculatorGUI() {
initComponents();
}
private void initComponents() {
oneBtn = new javax.swing.JButton();
oneBtnListener btnListener = new Listener().new oneBtnListener();
oneBtn.setText("1");
oneBtn.setBounds(100,100,100,25);
oneBtn.addActionListener(btnListener);
add(oneBtn);
setLayout(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
}
private javax.swing.JButton oneBtn;
public JButton getOneBtn() {
return oneBtn;
}
public void setOneBtn(String name) {
oneBtn.setText(name);
}
}
You can change now other part according to your requirement, I just
gave you "1" -> "11", but you can do more.
Best of Luck.
Hello I've just started programming and now i'm making a university project where I must get a gwtcontainer from another class and let it see in a popup window, don't know exactly how I can call it
This is a part of my code:
import com.is.lap.client.gui.Login;
public class StartRU extends TabPanel {
private static class MyPopup extends PopupPanel {
public MyPopup() {
super(true);
// Is here where i have the trouble don't know exactly how to do it
setWidget( (Widget) new Login().getLayoutData());
center();
}
}
public StartRU() {
Button LoginButton =new Button("Login");
LoginButton.setWidth("100px");
LoginButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// Instantiate the popup and show it.
new MyPopup().show();
}
});
If Login class extends Widget, you can simply
setWidget(new Login());
Are there any benefits or drawbacks to creating a nested class that implements ActionListener:
public class Foo{
Foo(){
something.addActionListener(new ButtonListener());
}
//...
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
//...
}
}
}
versus implementing ActionListener in the main class itself:
public class Foo implements ActionListener{
Foo(){
something.addActionListener(this);
}
//...
public void actionPerformed(ActionEvent e){
//...
}
}
I've seen both examples quite often, and just want to know if there's a 'best practice.'
#Ankur, you can still use anonymous inner classes as your listeners and have a separate free-standing control class and thus have code that's quite maintainable, a technique I like to use a bit. For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnonymousInnerEg {
private static void createAndShowUI() {
GuiPanel guiPanel = new GuiPanel();
GuiControl guiControl = new GuiControl();
guiPanel.setGuiControl(guiControl);
JFrame frame = new JFrame("AnonymousInnerEg");
frame.getContentPane().add(guiPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class GuiPanel extends JPanel {
private GuiControl control;
public GuiPanel() {
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (control != null) {
control.startButtonActionPerformed(e);
}
}
});
JButton endButton = new JButton("End");
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (control != null) {
control.endButtonActionPerformed(e);
}
}
});
add(startButton);
add(endButton);
}
public void setGuiControl(GuiControl control) {
this.control = control;
}
}
class GuiControl {
public void startButtonActionPerformed(ActionEvent ae) {
System.out.println("start button pushed");
}
public void endButtonActionPerformed(ActionEvent ae) {
System.out.println("end button pushed");
}
}
I think first approach is better, as your class will have a separate code for handling action. And usually also composition is better than inheritance so a class should extend a class or implement a interface only if it truly is-a super type.
Also for maintainability, let us say Foo class has a new requirement to listen for another different type of events and then perform action, in that case also first class can be easily modified.
If I am not worried about maintainability I would rather go for a anonymous class.
If the class Foo has no other responsibility than encapsulating this button, then the first solution is sort of ok.
However, as soon as Foo gets more "somethings" that it has to listen to then it gets messy. I prefer the second solution since it is more explicit and has a better scalability.
An even better solution may be to create an anomymous inner class.
public class Foo{
Foo(){
something.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
//...
}
});
}
}
Usually you want to use a nested or even anonymous class rather than exposing ActionListener to the API of the enclosing class. (public class Foo implements ActionListener -> Javadoc will state that Foo is an ActionListener, though this is usually just an implementation detail -> bad)
I am making a user interface which shows graphs and manipulates graphs. The class extends JFrame implements ActionListener. The ActionListener then calls different classes to manipulate graphs depending on the action. This worked while the class had few ActionListeners; however, now the class is becoming unmanageable.
I know that in the interest of encapsulation, it would be best to have the ActionListener within the user interface class because it needs to access non-static components of the interface. However, it seems like there is a conflict between encapsulation and readability.
What I am proposing is breaking the class into one class for the interface and a second for the ActionListener and accessing the interface components statically. What I want to know is does this follow basic design conventions? And, if this is an acceptable approach would you place the main class in the user-interface class or the ActionListener class?
Not a duplicate question... but my answer should help with your question.
Short summery, my preference would be to have the JFrame class not implement ActionListener and then have a number of named inner classes withing the JFrame that do implement the ActionListener.
I would place the main in a class unto itself... and call it Main.
Here is some sample code for the way I like to do it:
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Main
{
private Main()
{
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
final FooFrame frame;
frame = new FooFrame();
frame.setupGUI();
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
and then the GUI:
import java.awt.FlowLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class FooFrame
extends JFrame
{
private final JButton incrementBtn;
private final JButton decrementBtn;
private int value;
{
incrementBtn = new JButton("++");
decrementBtn = new JButton("--");
}
private class IncrementListener
implements ActionListener
{
public void actionPerformed(final ActionEvent evt)
{
increment();
}
}
private class DecrementListener
implements ActionListener
{
public void actionPerformed(final ActionEvent evt)
{
decrement();
}
}
public void setupGUI()
{
final LayoutManager layout;
layout = new FlowLayout();
setLayout(layout);
setupListeners();
addComponents();
}
private void setupListeners()
{
incrementBtn.addActionListener(new IncrementListener());
decrementBtn.addActionListener(new DecrementListener());
}
private void addComponents()
{
add(incrementBtn);
add(decrementBtn);
}
private void increment()
{
value++;
System.out.println("value = " + value);
}
private void decrement()
{
value--;
System.out.println("value = " + value);
}
}