JButtons MouseEvents - java

I want my buttons to change color when mouse is on them (hover), when they are pressed (active) and stay this way until user will choose other options. So one of them will be always choosen.
I have three buttons - with cricle, square and traingle. My code:
private static MouseListener ButtonMouseListener = new MouseAdapter () {
public void mouseEntered(MouseEvent evt) {
Component source = evt.getComponent();
source.setBackground(new Color(91, 90, 90));
}
public void mouseExited(MouseEvent evt) {
Component source = evt.getComponent();
source.setBackground(new Color(64, 64, 64));
}
public void mousePressed(MouseEvent evt) {
Component source = evt.getComponent();
source.setBackground(new Color(46, 46, 46));
}
};
So I want buttons to change color when hovering over them (mouseEntered), and again change color to default when someone stops hovering (that's why I have mouseExited). The next thing is that I want them to change color when they are choosen, so mousePressed . The problem is that when I move the cursor outside the button it changes to another color because of mouseExited and I don't want that. It has to stay the 'pressed color' until user chooses another of three buttons. I have no idea how to achieve that, I tried different options but nothing works the way I want.

For entry color change you need to implement the Event->Mouse->mouseEntered. Make sure you are implementing it on mouseExited
On mouse pressed color change you need to implement Event->Action. Inside actionPerformed, you can set the button color. For example :
jButton7.setBackground(new Color(11, 118, 219));
jButton1.setBackground(new Color(15,44,123));
jButton8.setBackground(new Color(15,44,123));
jButton9.setBackground(new Color(15,44,123));

You can use JToggleButton instead of JButton since they have their own UI property for selection (pressed) background. You can override it like this:
UIManager.put("ToggleButton.select", Color.GREEN);
An SSCCE of what I would do:
public class ToggleButtonsExample extends JFrame {
private static final Color PRESSED_COLOR = Color.BLUE;
private static final Color HOVER_COLOR = Color.RED;
public ToggleButtonsExample() {
super("Example");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
JToggleButton button1 = new JToggleButton("button1");
JToggleButton button2 = new JToggleButton("button2");
JToggleButton button3 = new JToggleButton("button3");
final Color defaultBackgroundColor = button1.getBackground();
MouseListener hoverColorMouseListener = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
Component component = e.getComponent();
component.setBackground(HOVER_COLOR);
}
#Override
public void mouseExited(MouseEvent e) {
Component component = e.getComponent();
component.setBackground(defaultBackgroundColor);
}
};
List<AbstractButton> buttons = Arrays.asList(button1, button2, button3);
buttons.forEach(this::add);
buttons.forEach(b -> b.addMouseListener(hoverColorMouseListener));
setLocationByPlatform(true);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
UIManager.put("ToggleButton.select", PRESSED_COLOR);
new ToggleButtonsExample().setVisible(true);
});
}
}
And a preview image:

Related

Background color wont be applied to JButton

I have a simple program with a jcolorchooser some textfields and a button.
When i press the button the jcolorchooser appears and then i select a color.
Now lets say i want to take the background color i choosed and apply it to my button like this:
public class Slide extends JFrame{
Color bgColor;
JButton colorButton=new JButton();
JColorChooser colorPicker=new JColorChooser();
public Slide(){
JPanel panel=new JPanel();
panel.setLayout(new MigLayout("", "[][][][][]", "[][][][][][]"));
colorButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
JColorChooser.showDialog(null, "title", null);
bgColor=colorPicker.getBackground();
colorButton.setBackground(bgColor);
}
});
colorButton.setText("Pick a color");
panel.add(colorButton, "cell 0 5");
this.setSize(400, 400);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String args[]){
new Slide();
}
}
The problem is that my bgcolor won't be applied to my colorButton.Any ideas?
The color the user has selected from the JColorChooser dialog is returned to you as the return value of the showDialog() method.
To update the JButton with the selected color from the dialog, you should change your code to:
colorButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Color color = JColorChooser.showDialog(null, "title", null);
if (color != null) {
colorButton.setBackground(color);
}
}
});
Note that the method showDialog() will return null if the user has canceled, that's why we need to check it's value before assigning the color.
The method getBackground() is a method from the Component class, so the previous code bgColor=colorPicker.getBackground() was simply returning the actual colour of the JColorChooser dialog component.

Two buttons changing panel color to red or blue

my first post here. I'm currently in school and usually spend my time here on Stackoverflow looking for answers to homework, this time i'd thought that perhaps i'll put my code here and maybe i'll get help more precis and quicker! Anyways, my problem is that i've written a code which you can see below, and I'm new to swing, studied it for a few hours only. My problem is that I'm not quite sure how to proceed with my problem, I have 2 buttons, what i want is when you click on first button the panel will change to Red, second button the panel changes to blue, so far only Red works and I don't know how to implement it so that blue works aswell.
Would greatly appreciate your help! (Don't be shy about pointing out a few errors or help along the way that doesn't have with the buttons to do, as I said, I'm new :P)
public class FirstProgram extends JFrame {
public FirstProgram() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel();
panel.setBackground(Color.yellow);
getContentPane().add(panel);
panel.setLayout(null);
JButton Colorbutton = new JButton("Red");
Colorbutton.setBounds(50, 60, 80, 30);
Colorbutton.setToolTipText("Panel changes to red");
Colorbutton.setBackground(Color.green);
JButton Colorrbutton = new JButton("Blue");
Colorrbutton.setBounds(1, 30, 90, 30);
Colorrbutton.setToolTipText("Panel changes to blue");
Colorrbutton.setBackground(Color.orange);
Colorbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.red);
}
});
panel.add(Colorbutton);
panel.add(Colorrbutton);
setTitle("Time to change colors");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
FirstProgram ex = new FirstProgram();
ex.setVisible(true);
}
});
}
}
you need another ActionListener. right now you just have one and it has just one behavior. create another one and tie to the 'Blue" button
JButton RedColorbutton = new JButton("Red");
RedColorbutton .setBounds(50, 60, 80, 30);
RedColorbutton.setToolTipText("Panel changes to red");
RedColorbutton.setBackground(Color.green);
JButton BlueColorbutton = new JButton("Blue");
BlueColorrbutton.setBounds(1,30,90,30);
BlueColorrbutton.setToolTipText("Panel changes to blue");
BlueColorrbutton.setBackground(Color.orange);
RedColorbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.red);
}
});
BlueColorbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.blue);
}
});
You've set an action listener for your Colorbutton, but not for Colorrbutton
Add this next to your other ActionListener
Colorrbutton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
panel.setBackground(Color.blue);
}
});
You are missing an ActionListener for the blue JButtton.
Similar to how you added the ActionListener to your ColorButton, your ColorrButton needs to have one registered. By the way, you may wish to change the ColorButton to redButton and the ColorrButton to blueButton or something like that to make things stick out better.
example:
Colorrbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.blue);
}
});
For the sake of reducing duplicate code, you can simplify the logic even further by having your class implement ActionListener.
public class FirstProgram extends JFrame implements ActionListener {
Then, when you are instantiating your buttons, add a listener like so:
redButton.addActionListener(this);
blueButton.addActionListener(this);
And then in your implementation of actionPerformed you could do something like:
public void actionPerformed(ActionEvent e) {
switch (e.getSource()) {
case redButton:
panel.setBackground(Color.red);
break;
case blueButton:
panel.setBackground(Color.blue);
break;
}
}
Anytime the red or blue buttons performs an action, the actionPerformed will be triggered, and then the logic to determine which button was the source will take over from there. This will add a little bit of length to your code, but as(if?) your program grows, it will reduce complexity greatly

JRootpane - setting glasspane to visible doesnt intercept mouse events

I have a JFrame and a JPanel hierarchy inside it, i want to implement an inner panel that i can make it look "disabled"(while other panels dont change), that is, to cover it by a semi transparent gray layer and intercept all mouse and perhaps even keyboard events that are dispatched to this panel. ive been searching for a solution and didnt really find a good one yet.
The closest i got to a solution was when i used JRootPane, whenever i want it disabled i make its glasspane visible. the glasspane had been set to be opaque and with semi transparent background.
A simple example of my attempt :
public class Test extends JFrame {
private final JPanel jPanel;
public Test() {
jPanel = new JPanel();
final JButton jButton = new JButton("Hidden");
jButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("hidden is clicked!");
}
});
final JRootPane jRootPane = new JRootPane();
jPanel.add(jRootPane);
final JPanel glassPane = new JPanel();
final JButton jButton2 = new JButton();
jButton2.addActionListener(new ActionListener() {
private boolean visible = true;
#Override
public void actionPerformed(ActionEvent e) {
glassPane.setVisible(visible = !visible);
}
});
jPanel.add(jButton2);
jRootPane.getContentPane().add(new JScrollPane(jButton));
glassPane.setBackground(new Color(0.5f, 0.5f, 0.5f, 0.2f));
glassPane.setOpaque(true);
jRootPane.setGlassPane(glassPane);
glassPane.setVisible(true);
getContentPane().add(jPanel);
}
public static void main(String[] strings) {
final Test test = new Test();
test.pack();
test.setVisible(true);
}
}
But the problem is that even when the glass is visible on top of the content, it doesnt intercepts events from getting to the content as it should, as documented here.
In your test class your glasspane doesn't intercept events, because you didn't tell it to intercept events (intercepting events is not a default behavior).
In the documentation link, it says
The glass pane
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane.
You can intercept Mouse Events this way:
glassPane.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
e.consume();
}
#Override
public void mousePressed(MouseEvent e)
{
e.consume();
}
});
You can intercept KeyBoard Events this way:
glassPane.setFocusable(true);
glassPane.addKeyListener(new KeyListener()
{
#Override
public void keyTyped(KeyEvent e)
{
e.consume();
}
#Override
public void keyReleased(KeyEvent e)
{
e.consume();
}
#Override
public void keyPressed(KeyEvent e)
{
e.consume();
}
});
Note: The JPanel has to be focasable to intercept the keyboard events.

how do you change the color of a jbutton after it is clicked?

I am making a jFrame that represents a go board. I want a click of a given button to change the color to represent placing a piece on the board. In my code below, I show a method that should be able to change the color of a button (it only changes the background of the whole frame). First question: Why is the button color not changing (this is not my bigger problem about changing color after click occurs, my preliminary issue is that the button color will not change). I do not get any errors, the button color just never changes.
public static void showBoard()
{
JFrame frame2 = new JFrame("Go Board");
frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
for(int i = 19*19; i > 0; i--)
{
JButton firstButton = new JButton("");
firstButton.setBackground(Color.blue);
firstButton.setVisible(true);
firstButton.setContentAreaFilled(true);
firstButton.setOpaque(true);
firstButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run()
{
System.out.println("ddsd");
//int[] arr = findMove(0);
}
});
}
});
frame2.getContentPane().add(firstButton);
}
frame2.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
frame2.setLayout(new GridLayout(19,19));
frame2.pack();
frame2.setVisible(true);
}
My second problem, getting the button to change color after being clicked, is presumably affected by the fact that I am not able to even change the button color. To get the button to change color after a click, I plan to put the button color change code inside the action listener.
So in summation, how can I change the color of the button after a click?
ANSWER:
The problem was the look and feel of my mac. Look to the checked answer for how to fix this if you have similar problem on your mac.
You don't need to call SwingUtilities.invokeLater inside your ActionListener, as the actionPerformed(ActionEvent) method will be invoked on the Event Thread already.
The following example demonstrates how to change a Button's background color when it's clicked on:
public class ChangeButtonColor implements Runnable {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
} catch (UnsupportedLookAndFeelException e) {
System.err.println("Cannot set LookAndFeel");
}
SwingUtilities.invokeLater(new ChangeButtonColor());
}
#Override
public void run() {
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
JButton button1 = new JButton("click me");
JButton button2 = new JButton("click me too");
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof Component) {
((Component)source).setBackground(Color.RED);
}
}
};
button1.addActionListener(listener);
button2.addActionListener(listener);
frame.add(button1);
frame.add(button2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Please note that the ActionListener used here can be used for all buttons. There is no need to create a new instance of it for every button.

java delete a component

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().

Categories

Resources