Java Swing - Redrawing from handler class

So I'll start off with putting my code here for my two classes.

SquareSimp.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SquareSimp
{

    public static void main( String[] args )
    {
        FilledFrame frame = new FilledFrame();

        frame.setVisible( true );
    }
}

class FilledFrame extends JFrame
{
    int size = 400;

    public FilledFrame()
    {
        JButton butSmall   = new JButton("Small");
        JButton butMedium  = new JButton("Medium");
        JButton butLarge   = new JButton("Large");
        JButton butMessage = new JButton("Say Hi!");

        SquarePanel panel = new SquarePanel(this);
        JPanel butPanel = new JPanel();

        butSmall.addActionListener(new ButtonHandler1(this, 200){
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                size = 200;
                panel.repaint();
            }
        });

        butMedium.addActionListener(new ButtonHandler1(this, this.size){
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                size = 300;
                panel.repaint();
            }
        });

        butLarge.addActionListener(new ButtonHandler1(this, this.size){
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                size = 400;
                panel.repaint();
            }
        });



        butPanel.add(butSmall);
        butPanel.add(butMedium);
        butPanel.add(butLarge);
        butPanel.add(butMessage);
        add(butPanel, BorderLayout.NORTH);
        add(panel, BorderLayout.CENTER);

        setSize( size+100, size+100 );
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        // Exercise 2.
        //Anonymous implementations of listeners are very efficient when you do not need to pass parameters to the
        // constructor of the implemented listener.
        butMessage.addActionListener(new ActionListener()
                // An anonymous function. Creates an actionListener that shows a dialog.
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                JOptionPane.showMessageDialog(null, "Hiiii");
            }
        });

    }

}

class SquarePanel extends JPanel
{
    FilledFrame theApp;

    SquarePanel(FilledFrame app)
    {
        theApp = app;
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.green);
        g.fillRect(20, 20, theApp.size, theApp.size);
    }
}

ButtonHandler1.java

package Lab2;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
// This is a class whose object will handle the event.
public class ButtonHandler1 implements ActionListener{
    private FilledFrame theApp;
    private int theSize;
    ButtonHandler1(FilledFrame app, int size){
        theApp = app;
        theSize = size;
    }

    public void actionPerformed(ActionEvent actionEvent) {
    }

}

So far, it all works, which is great. However, as requirement I was asked to make one button handler for each class. Can someone explain to me what my buttonHandler is actually doing here? As I feel like instead of making anonymous functions, and overriding the actionPerformed event, I could have done it a better way (creating the event in the buttonhandler class and affecting the size from there based on what button is pressed). I do not know how to do this, so any help with an explanation would be great!

Thanks very much!

Brandon

Any handler of a *Listener is used to handle events generated from the object which is being listened too. In the main program, it appears that you have several buttons which alter the size of the window.

In the case of your class which implements buttonHandler, you aren't doing anything because your actionPerformed method is not doing anything.

And anonymous classes are an acceptable way of implementing listeners. However, I prefer to use inner classes because the are cleaner (imho) and still have access to the state of the enclosing class.

Here is how your handler class should look:

// This is a class whose object will handle the event.
class ButtonHandler1 implements ActionListener {
   private FilledFrame theApp;
   private int         theSize;

   ButtonHandler1(FilledFrame app, int size) {
      theApp = app;
      theSize = size;
   }

   public void actionPerformed(ActionEvent actionEvent) {
      theApp.size = theSize;
      theApp.repaint();
   }
}

And here are the calls that add that handler to your buttons.

      butSmall.addActionListener(new ButtonHandler1(this, 200));
      butMedium.addActionListener(new ButtonHandler1(this, 300));
      butLarge.addActionListener(new ButtonHandler1(this, 400));

Swing / AWT / SWT. Graphics basics - redrawing Hi - taking a break from C/C++ So I've done bits of Java previously, s in the button handlers as an example

I am not sure if I understood the question but there are 2 ways to refactor your code:

  1. Remove your ButtonHandler1 class altogether and implement all of the logic in the anonymous class:
    //FilledFrame.java

    butSmall.addActionListener(new ActionListener(){
                @Override
                public void actionPerformed(ActionEvent actionEvent) {
                    FilledFrame.this.size = 200;
                    panel.repaint();
                }
            });

  1. You can add some getter and setter methods on your FilledFrame class and call these in ButtonHandler1.actionPerformed to implement the logic there like the following:
    package Lab2;

    import javax.swing.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    // This is a class whose object will handle the event.
    public class ButtonHandler1 implements ActionListener{
        private FilledFrame theApp;
        private int theSize;
        ButtonHandler1(FilledFrame app, int size){
            theApp = app;
            theSize = size;
        }

        public void actionPerformed(ActionEvent actionEvent) {
            theApp.setSizeMember(200); //do not use theApp.setSize(), create a method with a different name
            theApp.getSquarePanel().repaint();
        }

    }

I leave creating getters/setters on FilledFrame to you.

At the heart of the data transfer mechanism is the TransferHandler class. As its name suggests, the TransferHandler provides an easy mechanism for transferring data to and from a JComponent — all the details are contained in this class and its supporting classes. Most components are provided with a default transfer handler.

ButtonHandler1 is not really used because the parameters passed to it are never used, and its single method is overridden when you construct it. So this:

     butSmall.addActionListener(new ButtonHandler1(this, 200){
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                size = 200;
                panel.repaint();
            }
      });

Can be written without constructing ButtonHandler1:

    butSmall.addActionListener(new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            size = 200;
            panel.repaint();
        }
    });

Or by using a lambda expression :

    butSmall.addActionListener(actionEvent -> {
        size = 200;
        panel.repaint();
    });

There are many ways you could achieve the functionality you want. Based on what you wrote, you could define ButtonHandler1 like so:

class ButtonHandler1 implements ActionListener{
    private final FilledFrame theApp;
    private final int theSize;
    ButtonHandler1(FilledFrame app, int size){
        theApp = app;
        theSize = size;
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        theApp.size = theSize; //better use a setter in FilledFrame
        theApp.repaint();
    }
}

And use it like so:

    butSmall.addActionListener(new ButtonHandler1(this, 200));

    butMedium.addActionListener(new ButtonHandler1(this, 300));

    butLarge.addActionListener(new ButtonHandler1(this, 400));

Making ButtonHandler1 an inner class in FilledFrame makes things simpler:

class ButtonHandler1 implements ActionListener{
    private final int theSize;
    ButtonHandler1(int size){
        theSize = size;
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        size = theSize;
        repaint();
    }
}

Use it by:

    butSmall.addActionListener(new ButtonHandler1(200));

    butMedium.addActionListener(new ButtonHandler1(300));

    butLarge.addActionListener(new ButtonHandler1(400));

Source is responsible for providing information of the occurred event to it's handler. Java provide us with classes for the source object. Listener − It is also known as event handler. The listener is responsible for generating a response to an event. From the point of view of Java implementation, the listener is also an object.

Event Handling S2C Home « Event Handling. In previous lessons in the section we have created different types of Swing components which all share one thing in common; when we have interacted with a component, by for instance clicking a button, the only thing that happens is that the look of the component changes when is is depressed and reverts back when released.

This class is used to handle the transfer of a Transferable to and from Swing components. The Transferable is used to represent data that is exchanged via a cut, copy, or paste to/from a clipboard. It is also used in drag-and-drop operations to represent a drag from a component, and a drop to a component.

However, it also means that the handlers must execute quickly to keep the GUI responsive. In v 1.3, another Timer class was added to the Java platform: java.util.Timer. Both it and javax.swing.Timer provide the same basic functionality, but java.util.Timer is more general and has more features.

Comments
  • Please see https://stackoverflow.com/help/someone-answers
  • How would you say I should alter the code? Would you say I should make ButtonHandler1 an inner class within SquareSimp?
  • Thank you, that helps. There are a number of ways I could do this, although I was asked to provide a separate buttonhandler that can handle all three of the buttons. Would you say I should use an inner class to create the button handler ?
  • If you used an inner class you would not have to pass a reference to access the size field. But the way you did it is fine.
  • And one more note, unrelated to your actual problem. It is considered bad practice to extend JFrame unless you are overriding something. It is usually best to put a JPanel in JFrame and override that and do your painting, etc in that panel. Instead of extending JFrame, just use an instance of it.
  • @WJS of course. I think the OP is required to use a separate class. It might be a false assumption. I also assume that the comment about extending JFrame is aimed at the OP.
  • @c0der Yes! It is possible that is what the OP was taught.