Java Swing Colour Chooser Throwing Error - java

So I'm trying to implement a colour chooser that will then take that colour and pass it to another class to be used, but it's throwing up the error
"Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException:
javax.swing.colorchooser.DefaultColorSelectionModel cannot be cast to
javax.swing.JColorChooser"
every time I click a colour.
The code I'm using is:
For the actual JColorChooser:
JColorChooser RGB = new JColorChooser(Color.GREEN);
RGB.getSelectionModel().addChangeListener(this);
RGB.setAlignmentX(newPolyButton.LEFT_ALIGNMENT);
RGB.setMinimumSize(new Dimension(50, 25));
RGB.setPreferredSize(new Dimension(125, 25));
And for the listener:
public void stateChanged(ChangeEvent c) {
JColorChooser RGB = (JColorChooser)c.getSource();
Color poly = RGB.getColor();
imagePanel.setColor(poly);
}
And in the other class, imagePanel, I use:
public void setColor(Color poly) {
ImagePanel.poly = poly;
}
Can anyone see where I'm going with this? I was previously using a combo box with some manually input colours to choose from.
Any help greatly appreciated, thanks!

From your code
RGB.getSelectionModel().addChangeListener(this);
RGB.setAlignmentX(newPolyButton.LEFT_ALIGNMENT);
You are adding the ChangeListener to the Selection Modal for your RGB instance.
javax.swing.JColorChooser.getSelectionModel() will return an instance of DefaultColorSelectionModel.
Hence, you get a ClassCastException in your call (JColorChooser)c.getSource();.
UPDATE
From How to Use Color Choosers Java Tutorial:
tcc.getSelectionModel().addChangeListener(this);
. . .
public void stateChanged(ChangeEvent e) {
Color newColor = tcc.getColor();
banner.setForeground(newColor);
}
When the state changes, you will want to get the new color as a property of the Color Chooser instead of attempting to get the Source of the ChangeEvent and cast it.
Hope this helps!

In your stateChanged method, c.getSource() returns a DefaultColorSelectionModel and not the reference to your JColorChooser.
However, JColorChooser is usually used to open a color dialog that returns a Color when closed using the OK button.
Color color = JColorChooser.showDialog(parent, title, initialColor);
if (color != null) {
// do something with the chosen color
}

Related

Why doesn't my Combobox update its color properly?

I am implementing a dark mode into my program and everything works just fine, except a Combobox, which doesn't want to change its color as I want.
(source: bilder-upload.eu)
So as you can see, the "popup" of the Combobox changes the color just fine, but the Combobox itself doesn't. Also the Foreground color of the Combobox changes, but the background not.
I guess, the Look and Feel might cause the issue.
In my main-class:
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
Where I change to Darkmode:
TeamInterface.userFilterComboBox.setBackground( darkBackgroundColor );
TeamInterface.userFilterComboBox.setForeground( fontColor );
SwingUtilities.updateComponentTreeUI( TeamInterface.userFilterComboBox );
I have to use the updateComponentTreeUI-Method, because otherwise the "popup" also remains white.
If I remove the look and feel in my main-class, the combobox looks good,as you can see in this picture,
(source: bilder-upload.eu)
but I doesn't want to get rid of the system look and feel, so I tried to manually edit the UI of the combobox to metal with this code :
userFilterComboBox.setUI( new MetalComboBoxUI() );
but.. the result is just awful, even thoe theoretically (at leats thats what I think) it should look the same as without look and feel
(source: bilder-upload.eu)
The Combobox not is a component only to the background and the foreground but is the complex component.
An example:JComboBox is composed to:
ArrowButton
List of itme
Border (and it have a color)
the item selected
So for change all you can add inside your UIManager, all constant or you can define a new UIComponent.
So an PersonalComboBoxUI can the following:
/**
* #contributor https://github.com/vincenzopalazzo
*/
public class PersonalComboBoxUI extends BasicComboBoxUI {
public static ComponentUI createUI (JComponent c) {
return new PersonalComboBoxUI ();
}
#Override
public void installUI (JComponent c) {
super.installUI (c);
JComboBox<?> comboBox = (JComboBox<?>) c;
comboBox.setBackground (UIManager.getColor ("ComboBox.background"));
comboBox.setForeground (UIManager.getColor ("ComboBox.foreground"));
comboBox.setBorder (UIManager.getBorder ("ComboBox.border"));
comboBox.setLightWeightPopupEnabled (true);
}
#Override
protected JButton createArrowButton () {
Icon icon = UIManager.getIcon ("ComboBox.buttonIcon");
JButton button;
if (icon != null) {
button = new JButton (icon);
}
else {
button = new BasicArrowButton (SwingConstants.SOUTH);
}
button.setOpaque (true);
button.setBackground (UIManager.getColor ("ComboBox.buttonBackground"));
button.setBorder (BorderFactory.createLineBorder(Color.black));
return button;
}
#Override
protected ListCellRenderer createRenderer() {
return new MaterialComboBoxRenderer();
}
}
You should be defined also the PersonalComboBoxRenderer
/**
* #contributor https://github.com/vincenzopalazzo
*/
public class PersonalComboBoxRenderer extends BasicComboBoxRenderer {
#Override
public Component getListCellRendererComponent (JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JComponent component = (JComponent) super.getListCellRendererComponent (list, value, index, isSelected, cellHasFocus);
component.setBorder (BorderFactory.createEmptyBorder (5, 5, 5, 5));
component.setForeground (UIManager.getColor ("ComboBox.foreground"));
component.setBackground (isSelected || cellHasFocus ?
UIManager.getColor("ComboBox.selectedInDropDownBackground") :
UIManager.getColor("ComboBox.background"));
return component;
}
}
ps: in this case, I'm using the UIManager.put("ComboBox.background", COLOR) for add and stratification inside the JComponent.
So I want to add two information regarding if you using the personal color inside the UIManager or the PersonalComboBoxUI the color should be defined with this code
Color PINK_400 = new ColorUIResource (236, 64, 122);
because when you go to remove look and feel the color couldn't remove but if you used ColorUIResource the look and feel should be removed correctly.
To finish, if you do not have needed the default look and feel, I want to suggest you use a library.
The material-UI-swing has a system theming for creating the personal timing in your app and the all theme is personalizable.
This is the repo vincenzoapalazzo/material-ui-swing and atarw/material-ui-swing are the same repository and the same developer so, the vincenzopalazzo/material-us-swing is the developer branch, an contains more fix and test.
An example of the library is
.
Ps: I am the designer of the MaterialTheming System.

Drawing Graphics3D in TeeChart

I have a problem using IGraphics3D in a tChart. I can draw any type of picture over the tChart, but when I try to export the image using getImage() to a file the drawings disappear. These pictures also disappears when I click with the mouse over the Chart. I'm using the "com.steema.teechart.tools.Annotation" also and that it works how I want. However I don't know why the Graphics3D have a different behaviour.
I copy the code that shows how I create the drawings:
IGraphics3D grafics = tChart.getGraphics3D();
grafics.getPen().setColor(liniaGrafica.getColorLinia());
Series serie = tChart.getSeries(liniaGrafica.getIndexSerie());
grafics.line(X1, Y, X2, Y);
Can anyone help me with that doubt.
Thank you in advance.
Note you have to call the custom drawing routines at the chartPainted event. Here you have an example:
private static void initializeChart() {
tChart1.getAspect().setView3D(false);
Area area1 = new Area(tChart1.getChart());
area1.fillSampleValues(100);
tChart1.addChartPaintListener(new ChartPaintAdapter() {
#Override
public void chartPainted(ChartDrawEvent e) {
IGraphics3D grafics = tChart1.getGraphics3D();
grafics.getPen().setColor(tChart1.getSeries(0).getColor());
grafics.line(0, 0, 100, 100);
}
});
}

JColorChooser: Save/restore recent colors in Swatches panel

I am using a JColorchooser at various places in an application. There can be multiple instances of the panel that can invoke a JColorChooser.
The "Swatches" panel in the chooser has an area of "recent" colors, which only persists within each instance of JColorChooser. I would like to (a) have the same "recent" colors in all my choosers in my application, and (b) to save the colors to disk so that these colors survive close and restart of the application.
(At least (a) could be solved by using the same single chooser instance all over the whole app, but that apears cumbersome because I would need to be very careful with attached changelisteners, and adding/removing the chooser panel to/from various dialogs.)
I did not find any method that lets me set (restore) these "recent" colors in the chooser panel. So to me, it appears that the only ways of achieving this would be:
serialize and save / restore the whole chooser (chooser panel?)
or
create my own chooser panel from scratch
Is this correct, or am I missing something?
BTW: I would also like to detect a double click in the chooser, but it seems hard to find the right place to attach my mouse listener to. Do I really need to dig into the internal structure of the chooser panel to do this? (No, it does not work to detect a second click on the same color, because the change listener only fires if a different color is clicked.)
As you noticed, there is no public api to access the recent colors in the DefaultSwatchChooserPanel, even the panel itself isn't accessible.
As you'll need some logic/bean which holds and resets the recent colors anyway (plus the extended mouse interaction), rolling your own is the way to go. For some guidance, have a look at the implementation of the swatch panel (cough ... c&p what you need and modify what you don't). Basically, something like
// a bean that keeps track of the colors
public static class ColorTracker extends AbstractBean {
private List<Color> colors = new ArrayList<>();
public void addColor(Color color) {
List<Color> old = getColors();
colors.add(0, color);
firePropertyChange("colors", old, getColors());
}
public void setColors(List<Color> colors) {
List<Color> old = getColors();
this.colors = new ArrayList<>(colors);
firePropertyChange("colors", old, getColors());
}
public List<Color> getColors() {
return new ArrayList<>(colors);
}
}
// a custom SwatchChooserPanel which takes and listens to the tracker changes
public class MySwatchChooserPanel ... {
ColorTracker tracker;
public void setColorTracker(....) {
// uninstall old tracker
....
// install new tracker
this.tracker = tracker;
if (tracker != null)
tracker.addPropertyChangeListener(.... );
updateRecentSwatchPanel()
}
/**
* A method updating the recent colors in the swatchPanel
* This is called whenever necessary, specifically after building the panel,
* on changes of the tracker, from the mouseListener
*/
protected void updateRecentSwatchPanel() {
if (recentSwatchPanel == null) return;
recentSwatchPanel.setMostRecentColors(tracker != null ? tracker.getColors() : null);
}
// the mouseListener which updates the tracker and triggers the doubleClickAction
// if available
class MainSwatchListener extends MouseAdapter implements Serializable {
#Override
public void mousePressed(MouseEvent e) {
if (!isEnabled())
return;
if (e.getClickCount() == 2) {
handleDoubleClick(e);
return;
}
Color color = swatchPanel.getColorForLocation(e.getX(), e.getY());
setSelectedColor(color);
if (tracker != null) {
tracker.addColor(color);
} else {
recentSwatchPanel.setMostRecentColor(color);
}
}
/**
* #param e
*/
private void handleDoubleClick(MouseEvent e) {
if (action != null) {
action.actionPerformed(null);
}
}
}
}
// client code can install the custom panel on a JFileChooser, passing in a tracker
private JColorChooser createChooser(ColorTracker tracker) {
JColorChooser chooser = new JColorChooser();
List<AbstractColorChooserPanel> choosers =
new ArrayList<>(Arrays.asList(chooser.getChooserPanels()));
choosers.remove(0);
MySwatchChooserPanel swatch = new MySwatchChooserPanel();
swatch.setColorTracker(tracker);
swatch.setAction(doubleClickAction);
choosers.add(0, swatch);
chooser.setChooserPanels(choosers.toArray(new AbstractColorChooserPanel[0]));
return chooser;
}
As to doubleClick handling: enhance the swatchChooser to take an action and invoke that action from the mouseListener as appropriate.
You can use the JColorChooser.createDialog method - one of the parameters is a JColorChooser. Use a static instance of the JColorChooser and make it the Dialog modal - that way, only one color chooser is displayed at a time.
The createDialog method also takes ActionListeners as parameters for the OK and Cancel button. Thus, don't really have to manage listeners. Of course, this doesn't persist the recent colors across invocations of the app, just persists recent colors in the current app.
Here's a workaround using reflection - it will work provided the underlying implementation doesn't change. Assuming you have a JColorChooser, add your recent colors to it like this:
final JColorChooser chooser = new JColorChooser(Color.white);
for (AbstractColorChooserPanel p : chooser.getChooserPanels()) {
if (p.getClass().getSimpleName().equals("DefaultSwatchChooserPanel")) {
Field recentPanelField = p.getClass().getDeclaredField("recentSwatchPanel");
recentPanelField.setAccessible(true);
Object recentPanel = recentPanelField.get(p);
Method recentColorMethod = recentPanel.getClass().getMethod("setMostRecentColor", Color.class);
recentColorMethod.setAccessible(true);
recentColorMethod.invoke(recentPanel, Color.BLACK);
recentColorMethod.invoke(recentPanel, Color.RED);
//add more colors as desired
break;
}
}

Creating custom JButton from images containing transparent pixels

Read edit 2 for what I'm actually missing to make it work
I'm currently trying to create some custom JButtons using images created in photoshop that have an alpha parameter.
So far, overriding the paint() method to draw the image has worked in the sense that the button is drawn showing the correct image. I'd like to improve it, though, by making its shape (clickable area) the same as the visible pixels on the image (right now if I draw the button's border, it's a square).
Is there an easy way to do that or do I have to parse the image and find the alpha pixels to make a custom border?
Which methods would I have to override to make it work the way I want?
Also, another question I'm going to have later: would it be better to use some kind of algorithm to change the images' colors to make it seem like it is being clicked when people click on it or am I better off creating a second image and drawing that one while the button is active?
Edit: I just read on some other question that I should redefine paintComponent() instead of paint(), I'd like to know why since redefining paint() works fine?
Edit 2: I changed everything to make sure my JButtons are created using the default constructor with an icon. What I'm trying to do is get the X and Y position of where the click was registered and grab the icon's pixel at that position and check its alpha channel to see if it is 0 (if it is, do nothing, else do the action it is supposed to do).
The thing is, the alpha channel always returns 255 (and blue, red and green are at 238 on transparent pixels). On other pixels, everything returns the value it should be returning.
Here's an example (try it with another image if you want) that recreates my problem:
public class TestAlphaPixels extends JFrame
{
private final File FILECLOSEBUTTON = new File("img\\boutonrondX.png"); //My round button with transparent corners
private JButton closeButton = new JButton(); //Creating it empty to be able to place it and resize the image after the button size is known
public TestAlphaPixels() throws IOException
{
setLayout(null);
setSize(150, 150);
closeButton.setSize(100, 100);
closeButton.setContentAreaFilled(false);
closeButton.setBorderPainted(false);
add(closeButton);
closeButton.addMouseListener(new MouseListener()
{
public void mouseClicked(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
System.out.println("Alpha value of pixel (" + e.getX() + ", " + e.getY() + ") is: " + clickAlphaValue(closeButton.getIcon(), e.getX(), e.getY()));
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
});
Image imgCloseButton = ImageIO.read(FILECLOSEBUTTON);
//Resize the image to fit the button
Image newImg = imgCloseButton.getScaledInstance((int)closeButton.getSize().getWidth(), (int)closeButton.getSize().getHeight(), java.awt.Image.SCALE_SMOOTH);
closeButton.setIcon(new ImageIcon(newImg));
}
private int clickAlphaValue(Icon icon, int posX, int posY)
{
int width = icon.getIconWidth();
int height = icon.getIconHeight();
BufferedImage tempImage = (BufferedImage)createImage(width, height);
Graphics2D g = tempImage.createGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
int alpha = (tempImage.getRGB(posX, posY) >> 24) & 0x000000FF;
return alpha;
}
public static void main(String[] args)
{
try
{
TestAlphaPixels testAlphaPixels = new TestAlphaPixels();
testAlphaPixels.setVisible(true);
testAlphaPixels.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
This is just a wild guess, but is it possible that when my image gets cast to an Icon, it loses its Alpha property and thus doesn't return the correct value? Anyway, I'd really appreciate it if someone could actually help me out and tell me what I should be changing to get the correct value.
I'm guessing that because when I try it with the original image, the alpha channel's value is fine, but I can't actually use that BufferedImage because I resize it, so I actually get the channel values of the image with the original size...
I think you are on the wrong way. You do not have to override neither paint() nor paintComponent() methods. JButton already "knows" to be shown with image only:
ImageIcon cup = new ImageIcon("images/cup.gif");
JButton button2 = new JButton(cup);
See the following tutorial for example: http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JButton.html
Moreover swing is fully customized. You can control opacity, border, color etc. You probably should override some mentioned methods to change functionality. But in most cases there is better and simpler solution.
Since there were good elements in multiple answers, but none of the answers were complete on their own, I'll answer my own question so other people that have the same problem can try something similar.
I created my buttons using a new class which extends JButton, with a new constructor that takes a BufferedImage as parameter instead of an icon. The reason for that is that when I did something like myButton.getIcon(), it would return an Icon, then I'd have to make various manipulations on it to make it a BufferedImage of the right size, and it ended up not working anyway because it seems like the first cast to Icon made it lose the alpha data in the pixels, so I couldn't check to see if the user was clicking on transparent pixels or not.
So I did something like this for the constructor:
public class MyButton extends JButton
{
private BufferedImage bufImg;
public MyButton(BufferedImage bufImg)
{
super(new ImageIcon(bufImg));
this.bufImg = bufImg;
}
}
Then I created an accessor for my bufImg that resized the image to fit the JButton using the getSize() method and then returned an image resized at the right size. I do the transformations in the getBufImg() accessor because the image size might change when the window gets resized. When you call the getBufImg(), it's usually because you clicked on the button and thus you're not currently resizing the window.
Something a little bit like this will return the image at the right size:
public BufferedImage getBufImg()
{
BufferedImage newImg = new BufferedImage(getSize().getWidth(), getSize().getHeight(), BufferedImage.TYPE_INT_ARGB); //Create a new buffered image the right size
Graphics2D g2d = newImg.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(bufImg, 0, 0, getSize().getWidth(), getSize().getHeight(), null);
g2d.dispose();
return newImg;
}
With that buffered image, you can then code a method like this:
private int clickAlphaValue(BufferedImage bufImg, int posX, int posY)
{
int alpha;
alpha = (bufImg.getRGB(posX, posY) >>24) & 0x000000FF; //Gets the bit that contains alpha information
return alpha;
}
That you call on the button that implements a MouseListener, like this:
myButton.addMouseListener(new MouseListener()
{
public void mouseClicked(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
if(clickAlphaValue(((myButton)e.getSource()).getBufImg(), e.getX(), e.getY()) != 0) //If alpha is not set to 0
System.exit(0); //Or other things you want your button to do
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
});
And voila! The button will only do the action if you clicked on non-transparent pixels.
Thanks for the help everyone, I couldn't have come up with this solutions on my own.
If you want to have shape-specific click points, you're better off using Shape and their contains method. If you want, you can create a shape when creating your custom button class as part of it, and implement a contains method by wrapping around the shape's contains method.
As for the custom JButton, create a class that extends JButton, like this:
import java.awt.*;
import javax.swing.*;
public class CustomButton extends JButton{
/** Filename of the image to be used as the button's icon. */
private String fileName;
/** The width of the button */
private int width;
/** The height of the button. */
private int height;
public CustomButton(String fileName, int width, int height){
this.fileName = fileName;
this.width = width;
this.height = height;
createButton();
}
/**
* Creates the button according to the fields set by the constructor.
*/
private void createButton(){
this.setIcon(getImageIcon(filename));
this.setPreferredSize(new Dimension(width, height));
this.setMaximumSize(new Dimension(width, height));
this.setFocusPainted(false);
this.setRolloverEnabled(false);
this.setOpaque(false);
this.setContentAreaFilled(false);
this.setBorderPainted(false);
this.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
}
}
Here's how you can load the ImageIcon, if you want to do it like this.
public ImageIcon getImageIcon(String fileName){
String imageDirectory = "images/"; //relative to classpath
URL imgURL = getClass().getResource(imageDirectory + fileName);
return new ImageIcon(imgURL);
}
This will give you a button that will at least look like your image.
I asked a similar question regarding Image-based events on click, and Shapes helped wonders.
I guess it comes down to how complex your button images are.
Here's reference anyway:
How can you detect a mouse-click event on an Image object in Java?
PS: Maybe look into generating shapes from images, that go around all the pixels that aren't transparent. No idea if this is possible, but it would mean that a button would only be "pressed" if the user clicks on the image part of it. Just a thought.
If you want your button layout to be that of the non-transparent pixels in your image, then you should redefine the paintComponent() method. It is the most correct way of doing it (overriding paint() worked in old times but is now discouraged).
However I think it is not exactly what you want: you want a click on the button to be detected only if it is on a non-transparent pixel, right? In that case you have to parse your image and when clicked compare mouse coordinates to the pixel alpha channel of your image as JButton does not have such a feature.
If you have a round button, this is exactly what you need:
public class RoundButton extends JButton {
public RoundButton() {
this(null, null);
}
public RoundButton(Icon icon) {
this(null, icon);
}
public RoundButton(String text) {
this(text, null);
}
public RoundButton(Action a) {
this();
setAction(a);
}
public RoundButton(String text, Icon icon) {
setModel(new DefaultButtonModel());
init(text, icon);
if(icon==null) return;
setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
setContentAreaFilled(false);
setFocusPainted(false);
initShape();
}
protected Shape shape, base;
protected void initShape() {
if(!getBounds().equals(base)) {
Dimension s = getPreferredSize();
base = getBounds();
shape = new Ellipse2D.Float(0, 0, s.width, s.height);
}
}
#Override public Dimension getPreferredSize() {
Icon icon = getIcon();
Insets i = getInsets();
int iw = Math.max(icon.getIconWidth(), icon.getIconHeight());
return new Dimension(iw+i.right+i.left, iw+i.top+i.bottom);
}
#Override public boolean contains(int x, int y) {
initShape();
return shape.contains(x, y);
//or return super.contains(x, y) && ((image.getRGB(x, y) >> 24) & 0xff) > 0;
}
}
JButton has a contains() method. Override it and call it on mouseReleased();
paintComponent() instead of paint() depends if you paint() inside XxxButtonUI or just override paintComponent(), but there exists the option JButton#setIcon.

Changing the background color of a selected JToggleButton

I am trying to change the color of a JToggleButton when it has been selected in a reliable, look and feel independent way.
If using the Metal L&F, then using the UIManager is an approach:
UIManager.put("ToggleButton.selected", Color.RED);
Note: Iyy pointed out that I had a typo in the property name above, but I will leave it above for people getting here, but the actual property name is supposed to be:
UIManager.put("ToggleButton.select", Color.RED);
However, this does not work in my current Look and Feel (currently Windows XP). After some further analysis, it appears that the system look and feel in Windows (still XP) does not use any of the Color-based UIManager properties for ToggleButton at all, or it at least does not supply them itself (there is a quick example online to find all property keys from the UIManager, which in the example is conveniently limited explicitly to Color properties).
I have tried setting the background color:
Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) { /* stuff */ }
};
JToggleButton button = new JToggleButton(action);
// tried with and without opaque true
button.setOpaque(true);
button.setBackground(Color.RED);
Not only does it not change the selected state, but that does not even effect the unselected state.
I have tried changing the background color only after receiving the action:
#Override
public void actionPerformed(ActionEvent e)
{
JToggleButton button = (JToggleButton)e.getSource();
if (button.isSelected()) // alternatively, (Boolean)getValue(Action.SELECTED_KEY)
{
button.setBackground(Color.RED);
}
}
None of that works. The only thing that I have found to work requires me to draw the button myself in the selected state (which leads to a working example, albeit non-standard looking):
private class ColoredToggleButton extends JToggleButton
{
ColoredToggleButton(Action action, Color color)
{
super(action);
setBackground(color);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (this.isSelected())
{
int w = getWidth();
int h = getHeight();
String s = getText();
// selected color
g.setColor(getBackground());
g.fillRect(0, 0, w, h);
// selected foreground color
g.setColor(SystemColor.controlText);
g.drawString(s,
(w - g.getFontMetrics().stringWidth(s)) / 2 + 1,
(h + g.getFontMetrics().getAscent()) / 2 - 1);
}
}
}
That is slightly modified from a comment in this Java bug report. Interestingly (amusingly?), in claims to have been fixed in 1998.
Does anyone know of a better, L&F independent way to set the background color of a selected JToggleButton?
JToggleButton btn = new JToggleButton(...);
btn.setUI(new MetalToggleButtonUI() {
#Override
protected Color getSelectColor() {
return Color.RED;
}
});
"ToggleButton.selected" is wrong, it require "ToggleButton.select".
And should be update to the component.
UIManager.put("ToggleButton.select", Color.WHITE);
SwingUtilities.updateComponentTreeUI(togglebuttonname);
You might see if setIcon() is sufficient for your purpose, but you can also override paint() in the ButtonUI delegate.
Addendum: #kleopatra's comment is well-taken: changing the UI delegate is not trivial. #mKorbel's recent example shows both the difficulty and versatility of the approach. Its essential advantage is look & feel independence.
Some less ambitious approaches are mentioned here.
When it using "Windows look and feel"; in Netbeans you have to do only two things.
Go to properties
Un-select 'contentAreaFilled'
Select 'opaque'
You can set a background color in properties or by hard coding
In other way,
jToggleButton.setContentAreaFilled(false);
jToggleButton.setOpaque(true);
jToggleButton.setBackground(Color.red); //Your color here
That's all.:-)
You can simply force background color before each repaint - for that you have to alter paintComponent, check if button is toggled, set background depending on toggle state and, at last, let super class do the actual paint job:
public class ColoredToggleButton extends JToggleButton
{
#Override
public void paintComponent(Graphics g)
{
Color bg;
if (isSelected()){
bg = Color.GREEN;
} else {
bg = Color.RED;
}
setBackground(bg);
super.paintComponent(g);
}
}
If you would rather use an action listener instead of overriding methods in a UI you can just change the UI to a UI without any selectColor properties.
Here is an example I used recently
private class FavouriteToggle extends JToggleButton {
public FavouriteToggle() {
setUI(new BasicToggleButtonUI()); //Removes selectColor
////Your Custom L&F Settings////
setBackground(new Color(255, 252, 92));
setForeground(Color.GRAY);
setText("Favourite");
setBorder(null);
setFocusPainted(false);
////Add your own select color by setting background////
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(((JToggleButton) e.getSource()).isSelected()) {
setForeground(Color.BLACK);
setBackground(new Color(255, 251, 0));
} else {
setBackground(new Color(255, 252, 92));
setForeground(Color.GRAY);
}
}
});
}
}

Categories