How to cancel a mouseclicker event in Java - java

I have a mouseclicker event added to some JLabels and, after one of them will be clicked, I want to remove the link between that JLabel and the mouseclicker event.
To add the mouseclicker event to JLabel I use this code:
JLabel.addMouseListener(this);
There is a way to remove the JLabel from being clicked after the effect is solved? How can I do this?
I searched something but I'm not sure to how I can describe the problem and search about it, so i didn't found results.

This may seem trivial, but you could simply do:
myLabel.removeMouseListener(this);
Option two is to leave the MouseListener in place, but make it smarter -- i.e., give it logic that allows it to ignore input if need be. This could be a simple if block such as
#Override
public void mousePressed(MouseEvent me) {
if (someBoolean) {
return;
}
// here have your usual code
}
and then in your code, when you want to de-activate the MouseListener, simply change the listener's someBoolean field to false. This use of a boolean switch or flag is useful for when you need to turn the listener on and off repeatedly.
As a side note, you're usually better off not using this for your listeners as that is giving the main GUI class a bit too much responsibility. Instead use anonymous inner classes for simple few line code or named class for more involved listener code.
For example:
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.border.Border;
public class TurnListenerOnAndOff extends JPanel {
private JLabel myLabel = new JLabel("My Label");
private JCheckBox listenerEnabledCheckBox = new JCheckBox("Listener Enabled", true);
public TurnListenerOnAndOff() {
// make label bigger with a border
Border outsideBorder = BorderFactory.createLineBorder(Color.black);
Border insideBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
myLabel.setBorder(BorderFactory.createCompoundBorder(outsideBorder, insideBorder));
// create and add MyMouseListener to my label
myLabel.addMouseListener(new MyMouseListener());
// add components to the GUI's main JPanel
add(myLabel);
add(listenerEnabledCheckBox);
}
private class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
// if the JCheckBox isn't checked...
if (!listenerEnabledCheckBox.isSelected()) {
return; // let's get out of here
}
// otherwise if the check box is checked, do following code
System.out.println("myLabel pressed!");
}
}
private static void createAndShowGui() {
TurnListenerOnAndOff mainPanel = new TurnListenerOnAndOff();
JFrame frame = new JFrame("On and Off");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Related

.add() in java AWT not working after actionPerformed

I am fairly new to coding and have encountered this issue within my code.
I create a button using the Java AWT import. I then check for a response using a while loop and wish to create another button after, however .add() seems to no longer function.
import java.awt.*;
import java.awt.event.*;
public class Main1
{
public static void main(String[] args)
{
Frame f = new Frame();
f.setSize(500, 500);
f.setVisible(true);
ButtonPanel bp = new ButtonPanel(f);
bp.x = null;
while (bp.x == null)
{
}
System.out.println(bp.x);
//THE ISSUE- THIS WILL NOT APPEAR AFTER BUTTON PRESS
f.add("South", new Button("REEE"));
}
}
class ButtonPanel extends Panel implements ActionListener
{
volatile String x;
public ButtonPanel(Frame f)
{
Button b = new Button("Hi");
b.addActionListener(this);
f.add("North", b);
}
public void actionPerformed(ActionEvent e)
{
x = e.getActionCommand();
}
}
I have been trying solutions for this for the last day or so and nothing seems to be working. I've seen in other posts people have said to use Wait/Notify however I am not too sure how those work and I would like to know explicitly what is going wrong in my program (though I am still open to using Wait/Notify in my solution).
Any help would be appreciated, thank you very much
So, they're a number of issues at play here.
The first is the fact that layout managers are generally lazy. This means that you can add and/or remove a number of components quickly and then do a single layout and paint pass.
To do this, you need to revalidate the Container which was updated.
Next, AWT (and Swing by extension) is based on Model-View-Controller concept, one aspect of this is the "observer pattern". This is basically a callback concept that allows you to be notified when something of interest happens.
Button makes use of an ActionListener to generate events when the button is "actioned". This is the "observer pattern" in action.
Why is this important? You really want to think about what information is needed to be passed where and who's actually responsible for doing what.
For example, is it really the ButtonPanel's responsibility to update the frame? Is giving ButtonPanel unfettered control over the frame really a good idea?
Instead, ButtonPanel "should" be providing some kind of notification when some action has occurred and then any interested parties should be able to do what ever they need to.
As a "basic" example...
import java.awt.Button;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import javax.swing.event.EventListenerList;
public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
public Test() {
Frame f = new Frame();
f.setPreferredSize(new Dimension(500, 500));
f.pack();
ButtonPanel bp = new ButtonPanel(f);
bp.addObsever(new Observer() {
#Override
public void hiWasPerformed() {
f.add("South", new Button("REEE"));
f.revalidate();
}
});
f.setVisible(true);
}
public interface Observer extends EventListener {
public void hiWasPerformed();
}
class ButtonPanel extends Panel {
private EventListenerList eventListener = new EventListenerList();
public ButtonPanel(Frame f) {
Button b = new Button("Hi");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Observer[] listeners = eventListener.getListeners(Observer.class);
for (Observer observer : listeners) {
observer.hiWasPerformed();
}
}
});
f.add("North", b);
}
public void addObsever(Observer observer) {
eventListener.add(Observer.class, observer);
}
public void removeObsever(Observer observer) {
eventListener.remove(Observer.class, observer);
}
}
}
It looks like nothing is happening because the buttons are being added below the bottom of the window. You should consider using a layout manager to solve this issue.
However, in the meantime the simple solution is to move this line f.add("South", new Button("REEE")); inside the action event and to make use of Frame.pack();:
public class Main1
{
public static void main(String[] args)
{
Frame f = new Frame();
//set minimums rather than a fixed size
f.setMinimumSize(new Dimension(500, 500));
f.setVisible(true);
CustomButton b = new CustomButton(f);
//Add this line to update/size/show the UI
f.pack();
//Don't place any more code inside the main method. Future events should be triggered by interacting with the UI/buttons
}
}
Then for the button we don't need to extend Panel, we can do something like this:
class CustomButton implements ActionListener
{
Frame parentFrame;
public CustomButton(Frame f)
{
parentFrame = f;
Button b = new Button("Hi");
b.addActionListener(this);
f.add("North", b);
}
public void actionPerformed(ActionEvent e)
{
//Add button here instead of the main class
parentFrame.add("South", new Button("REEE"));
//The buttons are being added below the bottom of your window, this will force them to be shown.
//Using a layout manager will solve this ploblem and you will not need to do this:
parentFrame.pack();
}
}
Note: clicking on the "Hi" button multiple times will have interesting results of the "REEE" buttons overlapping or doing odd things if you resize the window.

Can I change an unique MouseListener methods with several JButton in JAVA?

Goal
What I want to do is to set a MouseListener on a Panel when click on a Button1.
Then I want to click on another Button that changes the MouseListener code to do something else.
Example of application
Click on JButton1 -> add MouseListener that change a JLabel background color to red.
Click on JButton2 -> DOESNT ADD a new MouseListener, but change the first one to set the JLabel text to "hello world"
What I can't do
I don't know how to modify an UNIQUE MouseListener.
What I tried
I tried to set an jButton.actionPerformed( new jLabel1.addMouseListener()) for each button, but they create two instance of MouseListener.
I don't want to set one MouseListener for several JButtons, but several JButton changing the status of my MouseListener.
Thanks alot :)
Better to give the JLabel a MouseListener from the get-go, but give it boolean if-blocks that will turn on or off functionality depending on the state of class boolean fields. In your button ActionListeners, simply change the state of these boolean fields. For example in the code below, the boolean flag labelListenerOn is toggled on or off in the first JButton's ActionListener. The JLabel's MouseListener checks the state of this variable and changes the labels background color if the flag is true only. Similarly for the other boolean flag and other ActionListener:
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
public class ButtonListener extends JPanel {
private static final String TURN_ON_MOUSE = "Turn On Mouse";
private static final String TURN_OFF_MOUSE = "Turn Off Mouse";
private JButton button1 = new JButton(TURN_ON_MOUSE);
private JButton button2 = new JButton("Button 2");
private JLabel label1 = new JLabel("Label 1");
private MouseListener labelListener = new LabelListener();
private boolean labelListenerOn = false;
private boolean labelChangeText = false;
public ButtonListener() {
label1.setOpaque(true);
label1.addMouseListener(labelListener);
button1.addActionListener(e -> {
if (labelListenerOn) {
labelListenerOn = false;
((JButton) e.getSource()).setText(TURN_ON_MOUSE);
} else {
labelListenerOn = true;
((JButton) e.getSource()).setText(TURN_OFF_MOUSE);
}
});
button2.addActionListener(e -> {
labelChangeText = true;
});
add(button1);
add(button2);
add(label1);
}
private class LabelListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
Color labelColor = label1.getBackground();
if (labelListenerOn) {
if (labelColor.equals(Color.RED)) {
label1.setBackground(null);
} else {
label1.setBackground(Color.RED);
}
// label1.repaint(); // per Rob Camick's comment, this is not necessary
}
if (labelChangeText) {
label1.setText("Hello World");
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
ButtonListener mainPanel = new ButtonListener();
JFrame frame = new JFrame("ButtonListener");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
If you want to get fancy, look up M-V-C for "model-view-controller", where you separate the program logic (here the state of the boolean flags) from the program view code (the Swing GUI code), usually in their own classes, and then use a master class to hook all the components up. This would add an additional layer of indirection and complexity, and would be over-kill in this situation, but in large programs, and especially in programs that are likely going to be updated, changed and grown, this will actually reduce complexity in the long run, and make the program much more "scalable" -- easier to grow and modify. Again, I do not recommend that you do this here, but do look it over for possible future use.

Text Box not working properly

I wrote a program for an applet that is supposed to display different text in a text box when you push a button. My program has no errors when I compiled it, but the text box doesn't display correctly. I don't know what is wrong with it. Here is my code
import java.awt.*;
import java.awt.event.*;
public class colors{
Button button1;
Button button2;
Button button3;
Label label1;
TextField objTextField1;
public static void main (String args[]){
colors c = new colors();
}
public colors() {
Frame f = new Frame ("Colors");
Button button1 = new Button("Blue");
button1.setBounds(10,305,120,75);
button1.addMouseListener(new MyMouseListener1());
Button button2 = new Button("Red");
button2.setBounds(140,305,120,75);
button2.addMouseListener(new MyMouseListener2());
Button button3 = new Button("Yellow");
button3.setBounds(270,305,120,75);
button3.addMouseListener(new MyMouseListener3());
f.add(button1);
f.add(button2);
f.add(button3);
label1 = new Label("Click a Button to Reveal Text");
label1.setBounds(20,105,200,25);
f.add(label1);
objTextField1 = new TextField("Which Color?", 15);
objTextField1.setBounds(20,75,125,50);
f.add(objTextField1);
f.add(label1);
f.add(objTextField1);
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
f.setSize(400,400);
f.setVisible(true);
}
public class MyMouseListener1 extends MouseAdapter{
public void mouseClicked(MouseEvent me){
objTextField1.setText("Blue");
}
}
public class MyMouseListener2 extends MouseAdapter{
public void mouseClicked(MouseEvent me){
objTextField1.setText("Red");
}
}
public class MyMouseListener3 extends MouseAdapter{
public void mouseClicked(MouseEvent me){
objTextField1.setText("Yellow");
}
}
}
When a Button is clicked it fires an ActionEvent.
You should use an ActionListener instead of a MouseListener.
public void actionPerformed(ActionEvent e) {
...//code that reacts to the action...
}
AND don't forget to add
button.addActionListener(instance);
I have tested your code and it's working as expected but I have noticed some of the points in your code as mentioned below:
Use setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) instead of System.exit(0) and adding WindowListener to close the window.
Use frame.pack() instead of frame.setSize() that fits the components as per component's preferred size.
Don't use null layout and never use absolute positioning via calling setBounds() instead use a proper Layout Manager that suits as per your application design.
Read more How to Use Various Layout Managers
Use SwingUtilities.invokeLater() or EventQueue.invokeLater() to make sure that EDT is initialized properly.
Read more
Why to use SwingUtilities.invokeLater in main method?
SwingUtilities.invokeLater
Should we use EventQueue.invokeLater for any GUI update in a Java desktop application?
Follow Java Naming convention
Keep the instance members private
This is already addressed by #TAsk that you should be using ActionListener instead of MouseListener if you are interested in only mouseClicked() method.
You should be using Swing components instead of AWT components as already mentioned by #peeskillet
To make an applet you should extend javax.swing.JApplet class & override init() method.
To change the color, you must write your logics in actionPerformed() of ActionListener. But it's an interface. So, you can make use of Anonymous Inner class & implement actionPerformed() in it.
So, when you call addActionListener() on a JButton, I recommend you to do that by using Anonymous Inner class. It would be more clear through following code.
My Suggestion: Whenever you write code, always keep OOD principles in your mind. This isn't right place to discuss that, but your code has a Code smell which is Duplication in code.
Below is the best way to do what you want & we're also using DRY Principle.
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class ColorChanger extends javax.swing.JApplet {
private JPanel mainPanel;
private JButton btnRed;
private JButton btnGreen;
private JButton btnBlue;
#Override
public void init() {
super.init();
mainPanel = new JPanel();
btnRed = new JButton("Red");
btnGreen = new JButton("Green");
btnBlue = new JButton("Blue");
this.add(mainPanel);
mainPanel.add(btnRed);
mainPanel.add(btnGreen);
mainPanel.add(btnBlue);
bindActionEvent(btnRed, Color.RED);
bindActionEvent(btnGreen, Color.GREEN);
bindActionEvent(btnBlue, Color.BLUE);
}
private void bindActionEvent(JButton b1, Color color) {
b1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
mainPanel.setBackground(color);
//Write setText() for your TextField here.
}
});
} //END Of Helper Method
}

How to make a JList "refresh" method in a JPanel class

I'm a beginner at java and want to make a JFrame with tabs containing a seperate JPanel. One panel has a list where it displays things that you select in a different panel, so I want this panel to always display a list of stuff that you have selected in a different panel (I hope that makes sense). To do this, I need to make a method to refresh the JList. This is the Farthest that I've gotten on that:
public class PanelClass extends JPanel {
private JList list;
private DefaultListModel listModel = new DefaultListModel();
private ArrayList<SomeOtherClass> objectArray = new ArrayList<SomeOtherClass>();
public PanelClass() {
list.setModel(listModel);
}
public void refresh() {
updateListModel();
list.setModel(listModel);
}
public void updateListModel() {
if (objectArray.isEmpty()) {
System.out.println("No Objects In Array!");
} else {
listModel.clear();
for (SomeOtherClass SOC : objectArray) {
// SOC.getName() just returns a string
listModel.addElement(SOC.getName());
}
}
}
public void addObjectToArray(SomeOtherClass SOC) {
objectArray.add(SOC);
}
}
Could someone please tell me how to make a "refresh" method to constantly keep the JList up to date?
The AWT/Swing event model is based upon the widgets being event sources (in the MVC paradigm, they are both view and controller). Different widgets source different event types.
Look at the java.awt.event (primarily), and javax.swing.event packages for the listener interfaces you'll need to implement and register in order to produce your desired effect.
Basically, you write a Listener implementation, and register it with Widget1. When Widget1 detects an event, it will notify you, and you can then use the information it provides to update Widget2.
For instance, if a button being clicked would add an object to your list, you might have something like below (I usually put this code in the encompassing JFrame class, and make it implement the listener interfaces; but you can choose to use inner classes or separate listener classes):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame implements ActionListener {
private JButton button = new JButton("Click me!");
private DefaultListModel<String> listModel = new DefaultListModel<String>();
private JList<String> list = new JList<String>(listModel);
private int counter = 1;
public MyFrame() {
setTitle("Test Updates");
JTabbedPane tabs = new JTabbedPane();
add(tabs, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(list);
tabs.add("Selections", panel);
panel = new JPanel();
button.addActionListener(this);
panel.add(button);
tabs.add("Options", panel);
pack();
}
#Override
public void actionPerformed(final ActionEvent event) {
if (button.equals(event.getSource())) {
listModel.addElement("Item " + counter++);
}
}
/* Test it! */
public static void main(String[] args) {
final MyFrame frame = new MyFrame();
frame.addWindowListener(new WindowAdapter() {
#Override public void windowClosing(final WindowEvent e) {
frame.setVisible(false);
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}
This code sample is minimal, but it should give you an idea of how to go about implementing what you want.
You can do it in two way. First : Write it in infinite thread loop so that it will constantly update JList. Second : You can call refresh() method whenever new SOC objects are added in your ArrayList. It means you can call refresh() method from addObjectToArray() method which ultimately call the refresh method only when you have some change in your ArrayList.
FYI : I did it in my project and I went for second option.

Clicking JPanel with inner components

I have a main JPanel class (not exact code):
class Panel extends JPanel {
public void initGUI() {
setLayout(...);
JTabbedPane tabbedPane = new JTabbedPane();
JPanel boxPanel = new JPanel(...);
tabbedPane.addTab("test", boxPanel);
JLabel label = new JLabel("Label")
boxPanel.add(label);
add(tabbedPane);
}
}
I want to be able to click anywhere on the Panel or its inner components and return the Panel.
public class PanelMouseAdapter extends MouseAdapter {
public void mouseReleased(MouseEvent e) {
Panel panel = (Panel)e.getSource();
//do other stuff
}
}
And for each Panel I'm adding this mouse listener.
But it only works around the edges of the Panel, any inner components are ignored. I need it to be able to click anywhere in that Panel.
I need to maintain that anywhere I click it will return the Panel object (as in the mouse listener).
Thanks for any feedback.
Not sure I understand the question. Your demo code only shows a single panel, so why do you care what parent panel is clicked on? The better your explanation of the requirement the better the solution we can provide.
Anyway, check out Global Event Listeners. This will allow you to listen for a mousePressed event (which is a better then listening for a mouseClicked).
Next you need to create a custom panel (MyCustomPanel) that you use for the top level panel.
Now, whenever a mousePressed is generated you can get the source of the event and then use:
MyCustomPanel panel = SwingUtilties.getAncestorOfClass(MyCustomPanel.class, (Component)event.getSource());
You can use Container#getComponents() for this case. For example consider the code snippet given below (look for addListeners(Container) method):
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
class SPanel extends JPanel
{
public void init()
{
this.add(new JButton("Button"));
this.add(new JLabel("Click"));
JPanel pan = new JPanel();
pan.add(new JButton("PanButton"));
pan.add(new JTextField(29));
add(pan);
addListeners(this);
}
public void addListeners(Container comp)
{
Component[] components = comp.getComponents();
for (Component component : components)
{
if (component instanceof Container)
{
Component[] child = ((Container)component).getComponents();
if (child != null && child.length > 0)
{
addListeners((Container)component);
}
}
component.addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent evt)
{
System.out.println(evt.getSource().getClass());
}
});
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater( new Runnable()
{
#Override
public void run()
{
SPanel sp = new SPanel();
sp.init();
JFrame frame = new JFrame("Frame");
frame.getContentPane().add(sp);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
Solved issue.
Initially I was going to open a popup menu once I had the mouse listener in place.
But now I added JComponent.setComponentPopupMenu as Polum suggested, not to the Panel but to the tabbedPane.
Then I added a listener to the popup menu, got the source object via event in popupMenuWillBecomeVisible method, then the component via source.getInvoker(), then get the parent of the invoker component and check if its an instance of PairBox.

Categories