Working on a homework assignment and I'm having issues with figuring out how to print a line of text when a mouse cursor enters and exits a certain colored area (a JPanel called panel in this case) while using the MouseListener interface.
I choose a color from the bottom panel (either Red, blue, or yellow) and then when I move to the upper panel it should be able to print which color the mouse has entered in while the mouse is in the panel and which color I exited from when my mouse finds itself outside of said panel...
Hopefully that makes sense. Here's a code snippet of what I have so far. This is for the color RED:
class RedButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
panel.setBackground(Color.RED);
class RedMouseListener implements MouseListener
{
public void mouseEntered(MouseEvent event)
{
}
public void mouseExited(MouseEvent event)
{
}
public void mousePressed(MouseEvent event) { }
public void mouseReleased(MouseEvent event) { }
public void mouseClicked(MouseEvent event) { }
}
}
}
ActionListener redListener = new RedButtonListener();
bRed.addActionListener(redListener);
Here's a relevant question from Stack Overflow Mouse moved event within JPanel
I'd recommend once you ensure that triggers are being correctly listened to (try printing "Hello World") From there you need to get the communication of the color state within the mouse event. If everything is within the same instance you can just access the variables needed within the event listener.
Here are the docs on MouseEvent http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html
Make sure you added the mouse listener try the following
panel.addMouseListener(new RedMouseListener());
start simple making the following work
public void mouseEntered(MouseEvent event)
{
System.out.println("Hello World!");
}
if you need to access the color of the panel within the event listener try the following snippet
panel.getBackground();
This returns a Color object.
Its worth mentioning the extra class declaration can be avoided by using an anonymous inner class. see How are Anonymous (inner) classes used in Java? These overridden methods are essentially a sub class of MouseListener but we don't need to call it by name.
panel.addMouseListener(new MouseListener(){
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
});
Introduction
Since this is such an old question, I thought I'd put together a simple Swing GUI to illustrate how a MouseListener works.
Here's the GUI before I do anything.
The main panel in the center will take on the selector color when the mouse is moved into the selection area. The main panel will return to it's original color when the mouse is moved out of the selection area.
Here's the GUI when my mouse is in the blue selection area.
Explanation
If you're not familiar with Java Swing, Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay close attention to the Concurrency in Swing and the Laying Out Components Within a Container sections.
When I create a Swing GUI, I use the model/view/controller (MVC) pattern. This pattern allows me to separate my concerns and focus on one part of the application at a time.
The MVC pattern implies that you create the model first, then the view, then the controller. This is more of an iterative process than a waterfall.
In Java Swing, the MVC pattern means:
The view reads information from the model.
The view may not update the model.
The controller updates the model and repaints / revalidates the view.
The model consists of one or more plain Java getter/setter classes.
The view consists of a JFrame and however many JPanels it takes to create the GUI.
There's usually not one controller "to rule them all". Each listener acts as an independent controller to manage its part of the model and view.
This is a simple application, so it consists of two model classes, one view class, and one controller class. The model is not updated at all in this example.
I did not code this entire application at one time. I wrote a few lines of code and ran tests. I made lots of changes to the code before I was satisfied with how it worked.
Model
The ColorSelection class is a plain Java getter/setter class that holds the color name, background color, and foreground color.
The MouseMovementModel class is a plain Java getter/setter class that holds the ColorSelection instances. The GUI builds the selection JPanel based on this information. If you want to add another selection color, you would add it here.
View
The view consists of a JFrame, a selection JPanel, and the main JPanel.
The JFrame has a default BorderLayout. The selection JPanel goes into the NORTH section and the main JPanel goes into the CENTER section. Only one component can be placed in a section. That component is usually a JPanel.
The selection JPanel uses a FlowLayout to hold the color selection JPanels. The color selection JPanels are created based on the number of ColorSelection instances in the application model.
A color selection JPanel is a simple JPanel created to use the information from a ColorSelection instance.
The main JPanel is a simple JPanel that will show a background color. The controller will be responsible for changing the background color.
Controller
The ColorListener class extends a MouseAdapter. The MouseAdapter class implements the MouseListener, MouseMotionListener, and MouseWheelListener interfaces. Using the MouseAdapter class allows me to implement just the mouse listener methods I'm writing code for.
The mouseEntered method sets the main JPanel to the ColorSelection color. The code is really simple. It updates the view with the ColorSelection background color.
The mouseExited method sets the main JPanel back to its original color.
Code
Here's the complete runnable code. I made the additional classes inner classes so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseMovementExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MouseMovementExample());
}
private final JPanel mainPanel;
private final JPanel[] colorPanel;
private final MouseMovementModel model;
public MouseMovementExample() {
this.model = new MouseMovementModel();
this.mainPanel = createMainPanel();
this.colorPanel = new JPanel[model.getSelections().length];
}
#Override
public void run() {
JFrame frame = new JFrame("Mouse Movement Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createSelectionPanel(), BorderLayout.NORTH);
frame.add(mainPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createSelectionPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
ColorSelection[] selections = model.getSelections();
for (int index = 0; index < selections.length; index++) {
ColorSelection selection = selections[index];
ColorListener listener = new ColorListener(this, selection);
colorPanel[index] = createColorPanel(selection, listener);
panel.add(colorPanel[index]);
}
return panel;
}
private JPanel createColorPanel(ColorSelection selection, ColorListener listener) {
JPanel panel = new JPanel(new BorderLayout());
panel.setBackground(selection.getBackgroundColor());
panel.addMouseListener(listener);
panel.setPreferredSize(new Dimension(200, 100));
JLabel label = new JLabel(selection.getColorName());
label.setFont(panel.getFont().deriveFont(Font.BOLD, 36f));
label.setForeground(selection.getForegroundColor());
label.setHorizontalAlignment(JLabel.CENTER);
panel.add(label, BorderLayout.CENTER);
return panel;
}
private JPanel createMainPanel() {
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200, 200));
return panel;
}
public Color getMainPanelBackground() {
return this.mainPanel.getBackground();
}
public void setMainPanelBackground(Color color) {
this.mainPanel.setBackground(color);
}
public class ColorListener extends MouseAdapter {
private final Color originalBackgroundColor;
private final ColorSelection selection;
private final MouseMovementExample view;
public ColorListener(MouseMovementExample view, ColorSelection selection) {
this.view = view;
this.selection = selection;
this.originalBackgroundColor = view.getMainPanelBackground();
}
#Override
public void mouseEntered(MouseEvent e) {
view.setMainPanelBackground(selection.getBackgroundColor());
}
#Override
public void mouseExited(MouseEvent e) {
view.setMainPanelBackground(originalBackgroundColor);
}
}
public class MouseMovementModel {
private final ColorSelection[] selections;
public MouseMovementModel() {
this.selections = new ColorSelection[3];
this.selections[0] = new ColorSelection("Red", Color.RED, Color.WHITE);
this.selections[1] = new ColorSelection("Green", Color.GREEN, Color.BLACK);
this.selections[2] = new ColorSelection("Blue", Color.BLUE, Color.WHITE);
}
public ColorSelection[] getSelections() {
return selections;
}
}
public class ColorSelection {
private final Color backgroundColor, foregroundColor;
private final String colorName;
public ColorSelection(String colorName, Color backgroundColor, Color foregroundColor) {
this.colorName = colorName;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public Color getForegroundColor() {
return foregroundColor;
}
public String getColorName() {
return colorName;
}
}
}
Related
I'm working on a game which consists entirely of menus/screens which you interact with using buttons, essentially a text-based game but without the typing. To do this I have been working with Swing to create a basic UI, following this video series.
In order to have actions performed in one panel affect the state of another, I have followed the tutorial and created a UIListener interface, which extends EventListener. When a button is pressed in one JPanel, the fireUIEvent method of the panel is called, which in turn calls the sole method of the interface, uiEventOccurred, which is implemented in an anonymous class inside the main JFrame class. Then the JFrame can do whatever it wants with the event, and modify other JPanels it contains accordingly.
For example, I have a panel that represents the town. It has a button you click to travel to the dungeon. When this button is clicked, the town panel is replaced by the dungeon panel, which has a button you can click to return to the town.
I'll post the relevant classes:
the main frame class
public class GameMainFrame extends JFrame{
public JPanel rightPanel;
public GameMainFrame(String title) {
super(title);
/* Setting The Overall Layout */
setLayout(new BorderLayout());
/* Creating Individual UI Panels */
UIPanel uip_town = new Town_UI();
UIPanel uip_dung = new Dungeon_UI();
/* Creating A Nested Panel */
rightPanel = new JPanel();
rightPanel.setLayout(new BorderLayout());
rightPanel.add(uip_text, BorderLayout.WEST);
rightPanel.add(uip_town, BorderLayout.NORTH);
/* Creating A Listener To React To Events From The UI Panels */
uip_town.addUIListener(new UIListener() {
public void uiEventOccurred(UIEvent event) {
System.out.println("event text: " + event.getText());
if (event.getText().equals("goto_dungeon")) {
rightPanel.remove(uip_town);
rightPanel.add(uip_dung, BorderLayout.NORTH);
validate();
} else if (event.getText().equals("goto_town")) {
rightPanel.remove(uip_dung);
rightPanel.add(uip_town, BorderLayout.NORTH);
validate();
}
}
});
/* Adding Panels To The Content Pane Of The Frame */
Container c = getContentPane();
c.add(uip_info, BorderLayout.WEST);
c.add(rightPanel, BorderLayout.CENTER);
}
}
UIPanel class
public class UIPanel extends JPanel {
private EventListenerList listenerList;
public UIPanel() {
listenerList = new EventListenerList();
}
public void fireUIEvent(UIEvent event) {
Object[] listeners = listenerList.getListenerList();
for (int i = 0; i < listeners.length; i += 2) {
if (listeners[i] == UIListener.class) {
((UIListener) listeners[i + 1]).uiEventOccurred(event);
}
}
}
public void addUIListener(UIListener listener) {
listenerList.add(UIListener.class, listener);
}
public void removeUIListener(UIListener listener) {
listenerList.remove(UIListener.class, listener);
}
}
Town_UI class
public class Town_UI extends UIPanel {
public Town_UI() {
Dimension size = getPreferredSize();
size.height = 466;
setPreferredSize(size);
setBorder(BorderFactory.createTitledBorder("Town"));
JButton btn_dungeon_enter = new JButton("Enter the dungeon");
add(btn_dungeon_enter);
btn_dungeon_enter.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireUIEvent(new UIEvent(this, "goto_dungeon"));
}
});
}
}
Dungeon_UI class
public class Dungeon_UI extends UIPanel {
public Dungeon_UI() {
Dimension size = getPreferredSize();
size.height = 466;
setPreferredSize(size);
setBorder(BorderFactory.createTitledBorder("Dungeon"));
JButton btn_town_return = new JButton("Return to town");
add(btn_town_return);
btn_town_return.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireUIEvent(new UIEvent(this, "goto_town"));
}
});
}
}
UIEvent object
public class UIEvent extends EventObject {
private String text;
public UIEvent(Object source, String text) {
super(source);
this.text = text;
}
public String getText() {
return text;
}
}
UIListener interface
public interface UIListener extends EventListener {
public void uiEventOccurred(UIEvent e);
}
I have two problems with this. Number one, it is currently bugged. When I run the application, the Town_UI panel appears with its button "Enter the dungeon", and upon clicking on it the frame correctly updates, replacing the Town_UI panel with the Dungeon_UI panel. However, clicking on the "Return to town" button on the dungeon panel doesn't do anything. When trying to debug this I found that the cause was in the UIPanel method fireUIEvent. When the "Return to town" button is pressed, this method is correctly called, but when it creates the Object array using getListenerList, the array is empty, so it skips the for-loop and no action is performed. Because I am unfamiliar with ActionEvents and EventListeners in Java, though, I am not sure how to fix this.
My other problem is that all of the behaviors that occur when a button is pressed are handled in the anonymous class in the GameMainFrame class. This means that if I want to have a bunch of different buttons all do different things (which I do plan on implementing), I'll need a whole bunch of conditionals in the anonymous class to determine what button is pressed and perform the corresponding behavior. I feel like it would be a lot cleaner if the button behavior could be implemented in the anonymous ActionListener class of each button, but I'm not sure how I should restructure my code so that I can do this but also allow any action on any panel able modify any other panel.
In the tutorial I watched he claimed that this implementation of EventListeners was what you should do in order to avoid making your code a rat's nest, but it seems like that is where my code is heading if I use this implementation for what I am trying to do.
Is it possible to add more than 1 mouselistener to a JButton? You know when I click on the button it should change color and text, and do something (e.g system.out.println), and when I click it again it should go back to the previous state, and print something else.
What I've tried:
JButton b = new JButton("First");
b.setBackground(Color.GREEN);
b.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
b.setBackground(Color.RED);
b.setText("Second");
System.out.println("You've clicked the button");
}
if(b.getModel.isPressed){
b.setBackground(Color.GREEN);
b.setText("Second");
System.out.println("You're back");
}
The problem is that the button doesn't go back to the previous state with the color (green) and text, and I don't how to handle that.
First of all, you shouldn't be using a MouseListener to do these things, because a better listener, ActionListener, was built specifically to be used with JButtons and similar entities to notify programs that a button has been pressed.
Having said that, sure you can add multiple ActionListeners (or MouseListeners) to a JButton, or you can have an ActionListener change its behaviors depending on the state of the program (usually meaning the values held by fields of the class).
A problem with your code and question is that I don't see when you expect or want the button to change its color back to green. If after a certain period of time, then have your ActionListener start a Swing Timer that changes the button's color back to green after x milliseconds.
Edit: I see, you want to toggle color -- then use a boolean field that you toggle or check the button's current color and base the listener's response based on that color.
example
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class ToggleColor extends JPanel {
public ToggleColor() {
JButton button = new JButton(new MyButtonAction());
button.setBackground(Color.GREEN);
add(button);
}
private static void createAndShowGui() {
ToggleColor mainPanel = new ToggleColor();
JFrame frame = new JFrame("ToggleColor");
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(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class MyButtonAction extends AbstractAction {
// !! parallel arrays being used below -- avoid if possible
private static final String[] TEXT = {"First", "Second", "Third"};
private static final Color[] COLORS = {Color.GREEN, Color.RED, new Color(108, 160, 220)};
private int index = 0;
public MyButtonAction() {
super(TEXT[0]);
}
#Override
public void actionPerformed(ActionEvent e) {
index++;
index %= TEXT.length;
putValue(NAME, TEXT[index]);
Component c = (Component) e.getSource();
c.setBackground(COLORS[index]);
}
}
This uses an AbstractAction class which is like an ActionListener but on "steroids"
You should only register one lister, but that listener will maintain some state regarding the number for mouse clicks. A simple if/else block will change the actions and change the text on the button label.
I am a beginner in Java programming so I do not know if I may be using the correct terms here. Basically, I have an assignment to program a little applet that changes the color of the background to whatever of the 4 color buttons is pressed. I was given a sample code with ActionListener and was told to use MouseListener to implement it.
I was able to successfully program it to work and then the requirements changed. Below is my current code that works (before the requirements changed).
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ButtonPanel extends JPanel implements MouseListener{
private JButton abutton, bbutton, cbutton, dbutton;
public ButtonPanel(){
abutton = new JButton("Cyan");
bbutton = new JButton("Orange");
cbutton = new JButton("Magenta");
dbutton = new JButton("Yellow");
add(abutton);
add(bbutton);
add(cbutton);
add(dbutton);
/* register the specific event handler into each button */
abutton.addMouseListener(this);
bbutton.addMouseListener(this);
cbutton.addMouseListener(this);
dbutton.addMouseListener(this);
}
/* implementation for the Mouse Event */
public void mouseClicked(MouseEvent evt){
Object source = evt.getSource();
if (source == abutton) setBackground(Color.cyan);
else if (source == bbutton) setBackground(Color.orange);
else if (source == cbutton) setBackground(Color.magenta);
else if (source == dbutton) setBackground(Color.yellow);
repaint();
}
public void mousePressed(MouseEvent evt){
}
public void mouseEntered(MouseEvent evt){
}
public void mouseReleased(MouseEvent evt){
}
public void mouseExited(MouseEvent evt){
}
}
class ButtonFrame extends JFrame{
public ButtonFrame(){
setTitle("Low-level Mouse Event to Set Color");
setSize(50, 50);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){ System.exit(0);}
});
Container contentPane = getContentPane();
contentPane.add(new ButtonPanel());
}
}
public class ME_SetColor {
public static void main(String[] args) {
JFrame frame = new ButtonFrame();
frame.pack();
frame.setSize(400, 250);
frame.setVisible(true);
}
}
The new requirement is to exclude extends JPanel and any other extensions for class ButtonPanel. So the modified class has to be
class ButtonPanel implements MouseListener{
private JButton abutton, bbutton, cbutton, dbutton;
Without JPanel, the ButtonPanel class would not be a component and therefore it can not be added to contentPane. Is there another way to make this ButtonPanel a component so it can be added to contentPane? Or is there any other ways to implement this program?
Without JPanel, the ButtonPanel class would not be a component
You could extend JComponent. JComponent is the base class for Swing components. JPanel itself is a simple extension of JComponent (with one minor difference: a JPanel's opaque property is true by default, whereas it's false by default for JComponent).
But if your requirement is to exclude any extensions for ButtonPanel, you're right, you can't actually make it a component that can be added to a container.
However, you could include a component as a field of ButtonPanel:
class ButtonPanel implements ... {
private JPanel panel;
private JButton abutton, bbutton, cbutton, dbutton;
...
public JPanel getPanel() { return panel; }
}
Then in ButtonFrame:
add(new ButtonPanel().getPanel());
You don't need to call getContentPane() and contentPane.add by the way, as a frame's own add methods automatically do this.
I have a JPanel with n number of JXTitledPanels. The user should be able to click the JXTitledPanel and hit a remove button to remove it.
My question is how do I know what JXTitlePanel the user has selected.
here is a screen from my program basically I want a user to click "Hospitals", click remove and the Hospitals Table will disappear.
I'd probably add a "remove" control into the right decoration position. This way you could pass a reference to the control of the JXTiltedPane
titledPane.addRightDecoration(new MyRemoveControl(titkedPane));
Or such
#madprogrammer probably has the simplest answer, but if you don't want to change the look of the application, you could combine your button's actionListener with a mouseListener for the panels.
The mouseListener portion saves the last panel clicked, and the actionListener just removes the panel that was registered by the mouseListener.
Here's a quick sample I cooked up - it doesn't use JXTitledPane but that shouldn't matter because they're all in the same hierarchy.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TempProject extends JFrame{
public TempProject(){
Box mainContent = Box.createVerticalBox();
//Create Button
JButton removePanel = new JButton("RemovePanel");
RemoveListener listener = new RemoveListener(mainContent);
removePanel.addActionListener(listener);
mainContent.add(removePanel);
//Create Panels
mainContent.add(getPanel(Color.red, listener));
mainContent.add(getPanel(Color.orange, listener));
mainContent.add(getPanel(Color.pink, listener));
mainContent.add(getPanel(Color.magenta, listener));
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setContentPane(mainContent);
pack();
setVisible(true);
}
public JPanel getPanel(Color color, RemoveListener l){
JPanel result = new JPanel();
result.setBackground(color);
result.add(new JLabel(color.toString()));
result.addMouseListener(l);
return result;
}
public static void main(String args[])
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new TempProject();
}
});
}
public static class RemoveListener extends MouseAdapter implements ActionListener{
Component lastSelectedComponent = null;
Container master; //The panel containing the ones being listened to
public RemoveListener(Container master){
this.master = master;
}
#Override
public void mouseClicked(MouseEvent arg0) {
lastSelectedComponent = (Component)arg0.getSource();
}
#Override
public void actionPerformed(ActionEvent e) {
if(lastSelectedComponent != null){
master.remove(lastSelectedComponent);
master.repaint();
}
}
}
}
Current I can add a bunch of customed component objects to the JPanel by pressing "add" JButton. I also got a "delete" JButton which I wish to do the opposite of "add".
My intention is that I can select a component with a mouse and click the delete button and pressto!, the component is gone.
I hook a MouseListener to the panel, and use MouseEvent, e.getComponent() to get w/e current component the mouse clicks on. So if it returns a custom component then a variable "private myComponent current" (already set to null) will point to that component. Then I can just click on "delete" button to remove it. An actionListener already added in "delete" button and in the body it calls this.remove(current) (if current is not null).
However, this doesn't work as I can't remove a component! Any pointer?
If there is an elegant way to managing add/remove components please suggest!
public class MainDisplayPanel extends JPanel implements ActionListener, MouseListener{
private JButton newClassButton;
private JButton deleteButton;
private Resizable current;
private Resizable resizer;
public MainDisplayPanel(LayoutManager layout) {
super(layout);
newClassButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addResizer();
}
});
deleteButton = new JButton("Delete");
deleteButton.addActionListener(this);
this.addMouseListener(this);
this.add(newClassButton);
this.add(deleteButton);
}
public void addResizer() {
//JPanel panel = new JPanel();
//panel.setBackground(Color.white);
resizer = new Resizable( new ClassBox());
this.add(resizer);
this.revalidate();
this.repaint();
}
public void actionPerformed(ActionEvent e) {
if(current!=null)
{
this.remove(current);
this.revalidate();
this.repaint();
}
}
public void mouseClicked(MouseEvent e) {
System.out.println(e);
Component component = e.getComponent();
if(component instanceof Resizable)
current= (Resizable) e.getComponent();
}
public static void main(String[] args) {
JFrame jframe = new JFrame();
jframe.add(new MainDisplayPanel(null));
jframe.setSize(new Dimension(600,400));
jframe.setVisible(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Doh!
Now, in the addResizer() method. Every time I press the add button to add a new Resizable object, what'd happen to the previously added objects? I'm certain that they become null because resizer variable no longer referring to it them??? Even if this is the case, they are still displayed on the panel...And if I pressed delete only the newly added Resizable object gets removed. So am I on the right track here?
Edit: to sum up my problem, I hooked the MouseListener to wrong object. It should be Resizable object instead of the panel. Therefore, variable current is always null.
Your problem is your MouseLisetener. You are listening to the MainDisplayPanel, and so when you click on the JPanel, the MouseEvent#getComponent method returned by, e, in your mousePressed method will return the MainDisplayPanel instance since that is what is being listened to, not the Resizable instance that is under the mouse.
Solutions include:
creating one MouseListener object and adding this same object to each Resizable as a MouseListener for the Resizable, or
using your current set up, but hold your Resizable's in an ArrayList and then iterating through the array list in the mousePressed method to see if any Resizable has been clicked by using the componentAt(...) method.
Note that I had to create my own SSCCE to solve this. Again in the future, please do us all a favor and do this for us as it really is in your and our best interest, and shows that you respect our time and our help.
Edit 1
My SSCCE:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class MainDisplayPanel extends JPanel {
private static final int RESIZABLE_COUNT = 40;
private JButton deleteButton;
private Resizable current;
private Resizable resizer;
private List<Resizable> resizableList = new ArrayList<Resizable>();
public MainDisplayPanel(LayoutManager layout) {
super(layout);
deleteButton = new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
deleteButtonActionPerformed(e);
}
});
this.addMouseListener(new MyMouseAdapter());
this.add(deleteButton);
for (int i = 0; i < RESIZABLE_COUNT; i++) {
addResizer();
}
}
private void deleteButtonActionPerformed(ActionEvent e) {
if (current != null) {
this.remove(current);
resizableList.remove(current);
current = null;
this.revalidate();
this.repaint();
}
}
public void addResizer() {
resizer = new Resizable();
this.add(resizer);
resizableList.add(resizer);
this.revalidate();
this.repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
current = null;
Component c = getComponentAt(e.getPoint());
for (Resizable resizable : resizableList) {
if (resizable == c) {
current = resizable;
resizable.setFill(true);
} else {
resizable.setFill(false);
}
}
}
}
public static void main(String[] args) {
JFrame jframe = new JFrame();
// !! jframe.add(new MainDisplayPanel(null));
jframe.add(new MainDisplayPanel(new FlowLayout()));
jframe.setSize(new Dimension(600, 400));
jframe.setVisible(true);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
#SuppressWarnings("serial")
class Resizable extends JPanel {
private static final int RESIZE_WIDTH = 50;
private static final int RESIZE_HEIGHT = 40;
private static final int THICKNESS = 5;
private static final Color FILL_COLOR = Color.pink;
public Resizable() {
Random rand = new Random();
// different color border so we can see that it was the clicked one that was deleted.
Color color = new Color(
rand.nextInt(255),
rand.nextInt(255),
rand.nextInt(255));
setBorder(BorderFactory.createLineBorder(color, THICKNESS));
}
#Override // so we can see it
public Dimension getPreferredSize() {
return new Dimension(RESIZE_WIDTH, RESIZE_HEIGHT);
}
public void setFill(boolean fill) {
Color fillColor = fill ? FILL_COLOR : null;
setBackground(fillColor);
repaint();
}
}
it very crazy idea, but everything is possible, but
1) in case that you Layed JComponent by using some of LayoutManager you can remove JComponents from Container, and thenafter you must/have to call revalidate() + repaint(), but this actions has side effect -> ReLayout Container and then Container's contents could be look very ***
2) in case that you layed Container with AbsoluteLayout, that should be maybe nicest but question is what with emtpy space inside Container
there is very easy way how to do it, you need to add JPopupMenu to the Container,
on RightMouseClick you have to finding JComponent under the MouseCursor
then call Container#remove(myComponent), thenafter you have to call revalidate() + repaint() for refresh GUI
or is same for me
call myComponent.setVisible(false), no re-layout, no revalidate + repaint, JComponent waiting on same place for (eventually) reusing
excelent thread about how to LayoutManagers add/remove JComponents + revalidate + repaint
I believe the problem is you need to force Swing to layout the components again after removing one. After you remove(current), call revalidate().