I have a loop that creates a series of JButtons. This code is buried deep inside a class that is primarily concerned with multi-threading, so it uses Executors, Callables, Futures, etc. I'm trying to keep this class fairly encapsulated, so I want to move the work of setting up the JButton to its own class. This is the body of my loop where it creates a single button. It works just fine:
JButton imageButton = new JButton(new ImageIcon(image));
imageButton.setMinimumSize(imageSize);
imageButton.setPreferredSize(imageSize);
imageButton.setMaximumSize(imageSize);
imageButton.setVisible(true);
imageButton.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(java.awt.event.MouseEvent mouseEvent) {
// do a bunch of stuff }
}
#Override
public void mouseMoved(java.awt.event.MouseEvent mouseEvent) {}
});
imagesPanel.add(imageButton);
This is only going to get messier, so here is my attempt to move it to a separate class:
ImageButton imageButton = new ImageButton(image, imageSize);
imageButton.addMouseMotionListener();
imagesPanel.add(imageButton);
And this is my class:
public class ImageButton extends JButton {
JButton button;
static final long serialVersionUID = 1;
public ImageButton(Image image, Dimension imageSize) {
button = new JButton(new ImageIcon(image));
button.setMinimumSize(imageSize);
button.setPreferredSize(imageSize);
button.setMaximumSize(imageSize);
button.setVisible(true);
}
public void addMouseMotionListener() {
button.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(java.awt.event.MouseEvent mouseEvent) {
// do a bunch of stuff
}
#Override
public void mouseMoved(java.awt.event.MouseEvent mouseEvent) {}
});
}
}
This all compiles without error, for whatever that is worth. The buttons layout in their proper sizes and proper places. However, the images do not appear (the buttons are blank) and the mouse listener is not functioning. Can anyone see what I am doing wrong and how to make this work?
Your ImageButton class is wrong. You're holding an unnecessary instance to JButton inside.
So, the implementation should be:
public class ImageButton extends JButton {
static final long serialVersionUID = 1;
public ImageButton(Image image, Dimension imageSize) {
super(new ImageIcon(image));
this.setMinimumSize(imageSize);
this.setPreferredSize(imageSize);
this.setMaximumSize(imageSize);
this.setVisible(true);
}
public void addMouseMotionListener() {
this.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(java.awt.event.MouseEvent mouseEvent) {
// do a bunch of stuff
}
#Override
public void mouseMoved(java.awt.event.MouseEvent mouseEvent) {}
});
}
}
This way, you're setting the parameters to the class instead to a member, and all instances of ImageButton will have the same configuration.
You extending JButton AND you create another JButton inside your class.
Probably you wanted to do something like this:
public static class ImageButton extends JButton {
JButton button; // Remove me
static final long serialVersionUID = 1;
public ImageButton(Image image, Dimension imageSize) {
super(new ImageIcon(image));
setMinimumSize(imageSize);
setPreferredSize(imageSize);
setMaximumSize(imageSize);
setVisible(true);
// Dont see why there should be separate method for the addMouseMotionListeners
addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(java.awt.event.MouseEvent mouseEvent) {
// do a bunch of stuff
}
#Override
public void mouseMoved(java.awt.event.MouseEvent mouseEvent) {}
});
}
}
Related
I got this code but when I run it the actionListener is not working.
Code
public class MenuPrincipal extends javax.swing.JFrame implements ActionListener {
public MenuPrincipal() {
initComponents();
this.setVisible(true);
this.setLocationRelativeTo(null);
this.addListener();
this.jButton1 = new JButton();
this.jButton2 = new JButton();
}
public static void main(String args[]) {
new MenuPrincipal();
}
private void addListener() {
this.jButton1.addActionListener(this);
this.jButton2.addActionListener(this);
JOptionPane.showMessageDialog(null, "Activado");
}
#Override
public void actionPerformed(ActionEvent event) {
if(event.getSource().equals(this.JButton1){
// do something
}
if(event.getSource().equals(this.JButton2){
// do something
}
}
}
I'm using Netbeans to make the interface, thus I'm not pasting here the generated code.
You should write something in the method of the handler:
#Override
public void actionPerformed(ActionEvent event) {
System.out.println("button pressed!");
}
and your class should implement the ActionListener interface
Alternatively you can use the java8 lambdas:
btn.addActionListener(e -> {System.out.println("button pressed!)});
remove this 2 lines from the constructor
this.jButton1 = new JButton();
this.jButton2 = new JButton();
Since addLsiteners method didnt throw any exception, that means you have already instantiated those JButtons. if you re instantiated then those fields will have the reference to different instances than the instance you added the action listener .
I want to call another applet by clicking a button; the old applet will then be closed or reloaded to the new applet.
My Action Listener doesn't have anything yet.
public class ConImage extends JApplet implements ActionListener {
Button btn;
Applet second;
public void init()
{
setSize(1600,900);
setLayout(null);
btn=new Button("Replace with other applet");
add(btn);
btn.addActionListener(this);
}
public void paint(Graphics g)
{
super.paint(g);
btn.setLocation(100, 100);
btn.setSize(100, 50);
}
public void actionPerformed(ActionEvent e)
{ second=null;
second= getAppletContext().getApplet("SecondClass");
if (second!=null)
{
if(e.getSource()==Time)
{
SecondClass ma= (SecondClass) second;
}
}
}
}
I'm pretty sure this isn't possible because of Java's security system. The best way to so it is to have a master class, which has an array of JApplet. On that master applet I would create a method that sets the visible applet from the array, calls init() and when a render is requested call paint() of that applet.
Like so:
public class MasterApplet extends JApplet {
private int index = 0;
private JApplet[] applets;
public void init(){
JApplet appletA = new AppletA();
JApplet appletB = new AppletB();
applets = new JApplet[]{appletA, appletB};
setViewing(index);
}
public void paint(Graphics g){
applets[index].paint(g);
}
public void setViewing(int idex){
index = idex;
applets[idex].init();
revalidate();
repaint();
}
Pretty much if you want to change the applet add it to the array of applets, and then call setViewing() with the index of that applet.
I have three classes, Main, DrawingPanel, and ToolboxPanel. ToolboxPanel contains all my buttons, including an Undo button. DrawingPanel is where I draw objects. I want the undo button to become enabled when an object is drawn on the screen, and disabled when there are no more objects left on the screen. Main creates an instance of DrawingPanel and of ToolboxPanel. I can get my undo button to work correctly if I use static methods and call, say, Main.setUndoStatus(false); from drawingPanel. The setUndoStatus then calls a setter in toolboxPanel. However, I've been reading about the Observer pattern and listeners and think I'm probably not doing it in a best-practice way.
How should I go about this using the observer pattern and/or mouse listeners correctly? (Or any "better" way of doing it).
Here's some code somewhat similar to what I'm doing.
public class Main
{
DrawingPanel drawingPanel;
ToolboxPanel toolboxPanel;
public Main()
{
drawingPanel = new DrawingPanel();
toolboxPanel = new ToolboxPanel(drawingPanel);
}
}
//A static method here to setUndoStatus, but I feel like I shouldn't have it
public static void setUndoStatus(boolean b)
{
{
toolboxPanel.setUndoStatus(b);
}
}
public class ToolboxPanel
{
JButton undoButton;
public ToolboxPanel(DrawingPanel drawingPanel)
{
undoButton = new JButton("Undo");
undoButton.setEnabled(false);
undoButton.addActionListener
(
new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
drawingPanel.undo();
undoButton.setEnabled(drawingPanel.getUndoStatus());
}
}
);
}
public void setUndoStatus(boolean status)
{
undoButton.setEnabled(status);
}
}
public class DrawingPanel
{
public DrawingPanel()
{
addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent e)
{
//Some code here that's unrelated
if(objectsExist == true) //If something gets drawn, whatever
{
Main.setUndoStatus(true); //Don't like this
}
}
});
}
}
I'm trying to make clean and OOP code for a java swing GUI.
So I made a class that implements Runnable and should handle all the actions.
All the data and components i stored in a data class full of getters and setters.
public class UserInterface{
...
public void foo(){
PanelActions panelActions = new PanelActions();
Thread tProgressbar = new Thread(panelActions, "Update progressbar");
tProgressbar.start();
}
}
public class PanelActions implements Runnable{
GUIdata data = new GUIdata();
public void run(){
//submitButton
data.getSubmitButton().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt) {
//Some code
}
});
//Browse Button
data.getBrowseButton().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt) {
//Some code
}
});
};
}
and the getter and setter class:
public class GUIdata{
private JButton submitButton;
private JButton browseButton;
GUIdata(){
submitButton = new JButton();
browseButton = new JButton();
}
public JButton getSubmitButton() {
return submitButton;
}
public void setSubmitButton(JButton submitButton) {
this.submitButton = submitButton;
}
public JButton getBrowseButton() {
return browseButton;
}
public void setBrowseButton(JButton browseButton) {
this.browseButton = browseButton;
}
}
But this way the code in the actionperformed isn't working. The thread starts and the run method is working great. But probably it doesn't like to add an ActionListener to a get methode. Even I tried this:
JButton browse = data.getBrowseButton();
browse.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt){
//Some code
}
});
data.setBrowseButton(browse);seButton(browse);
But even that isn't the right way.
So does anybody know how to add an ActionListener to an Button from another class?
Thanks :)
To execute your button actions in separate thread DO NOT put creation of action listeners into method run, put actions you want to perform in method run.
Remove from PanelActions any runnable:
public class PanelActions {
GUIdata data = new GUIdata();
//submitButton
data.getSubmitButton().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt) {
//Some code
}
});
//Browse Button
data.getBrowseButton().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt) {
//Some code
}
});
}
In actionPerformed create a Runnable or Thread and start it execution
#Override
public void actionPerformed(ActionEvent evt) {
Thread thread = new Thread() {
#Override
public void run() {
//Some code
}
};
thread.start();
}
"Update progressbar" gives me the impression you might need invokeLater:
data.getBrowseButton().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt) {
EventQueue.invokeLater(new Runnable() {
//Some code
});
}
});
This lets the event handling thread handle the button click (actionPerformed). And only a bit later the code is executed and responsive, repainting the progressbar.
Another software design might be cleaner. You might use Action (extending AbstractAction). Have some actions and put them into JButtons.
Is there a way I can disable mouse click ? In the panel there are different components and for some of the Button Click events, I want to disable the mouse click. I mean the click of the mouse doesn't have any effect on the components. I can disable using the setEnabled() function but I don't want to do that way.
Is there any way I can disable the mouse click ?
Situation :
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
//..disable the mouse click on each component present inside the panel
}
You can add an extended ActionListener to all the buttons like this:
public abstract class ExtendedActionListener implements ActionListener{
private static boolean disabled = false;
public static void setDisabled(boolean disabled){
ExtendedActionListener.disabled = disabled;
}
#Override
public final void actionPerformed(ActionEvent e){
if(disabled)
return;
doSomething;
}
}
And now just disable all the ActionListeners by calling the method setDisabled(false). The Button visual behavior doesn't change at all, but nothing happens, when you click on it.
If the visual click behaviour doesn't matter, then you can just remove the MouseListeners.
You can create a button group like this:
public class SingleSelectionButtonGroup {
private final List<JButton> buttons;
public static SingleSelectionButtonGroup group(List<JButton> buttons) {
return new SingleSelectionButtonGroup(buttons);
}
public static SingleSelectionButtonGroup group(JButton...buttons) {
return new SingleSelectionButtonGroup(Arrays.asList(buttons));
}
private SingleSelectionButtonGroup(List<JButton> buttons) {
this.buttons = new ArrayList<JButton>(buttons);
setupListener();
}
private void setupListener() {
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
SingleSelectionButtonGroup.this.disableAllExcept((JButton) e.getSource());
}
};
for (JButton button : buttons) {
button.addActionListener(listener);
}
}
private void disableAllExcept(JButton clickedButton) {
for (JButton button : buttons) {
if (!clickedButton.equals(button)) {
button.setEnabled(false);
}
}
}
}
And then uses it with a collection of buttons that you want to group:
public class Application {
public void run() {
final JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(400, 300));
final JPanel pane = new JPanel();
List<JButton> buttons = new ArrayList<JButton>();
String[] texts = {"A", "B", "C"};
for (String text : texts) {
JButton button = new JButton(text);
buttons.add(button);
pane.add(button);
}
SingleSelectionButtonGroup.group(buttons);
frame.getContentPane().add(pane);
frame.setVisible(true);
}
public static void main(String[] args) {
new Application().run();
}
}
you should use one common class of your listener and have static method for turn listener turn on and off
public abstract class BaseMouseListener implements ActionListener{
private static boolean active = true;
public static void setActive(boolean active){
BaseMouseListener.active = active;
}
protected abstract void doPerformAction(ActionEvent e);
#Override
public final void actionPerformed(ActionEvent e){
if(active){
doPerformAction(e);
}
}
}
your listeners would have to implements doPerformedAction()
Add empty mouse listener. This will "disable" the click because it will not have any effect.