Override Swing look and feel for a single component - java

I'm writing a plugin for a Swing application which I don't own or have access to the source code for. In parts of my UI, I want to use specific colors in order to match my icons.
In this case, I want to create a JPanel with a specific background color.
final JPanel panel = new JPanel();
panel.setBackground(new Color(101, 102, 103));
It appears that no matter what color I use, I get the same result. I suspect it's the look and feel that is changing the color on me.
All of the solutions I've found discuss changing the look and feel or setting new defaults. I don't want to take this approach because:
It's very dependent on the current look and feel
It would affect all panels in the application, and not just the one I'm interested in
The application supports several different themes (look and feels), so even if I were to use the UIManager to figure out exactly what they are, this would break as soon as they added a new theme.
I'm not too experienced with Swing, but I feel like the look and feel should set the defaults, but anything I set manually should still take effect. Is there any way to set the panel's background to a specific color regardless of the look and feel?

I'm chalking this up to a bug (or maybe a feature) in the application's custom look and feel. If I load a new look and feel the panel is displayed correctly.

As a work around you could create a custom JPanel that overrides paintComponent(Graphics g) to draw the background color.
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, getWidth(), getHeight());
}

Are you getting the problem while using Nimbus Look-and-Feel. Then please check my answer for more or less same problem at
Changing the Look and Feel changes the color of JTextPane?

Related

How to make a JFrame one colour?

I'm trying to add some polish to a small game I made and, every time a round finishes, I'd like the whole JFrame to flash white and quickly lose opacity until you can see the game again. How would I do this?
Note: I'm thinking about hiding all the components and adding a JPanel on top that loses opacity quickly but this doesn't seem right (and I'd like to be able to see the components behind the white flash as it goes from opaque to transparent).
You could probably use the JLayer class. Take a look at the section from the Swing tutorial on How to Decorate Components with the JLayer Class.
The tutorial has examples that:
paint translucent layers
do animation
Put the examples together and you should have a solution.
You can use fading out image to achieve the same. AlphaComposite is used for fading effect.
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
Refer Fade Out Image to access the sample code.

Drawing a graph with Graphics2D using WindowBuilder

So I have a JPanel called displayPane and I want to make it a drawing area for a graph (I am making a graphing calculator). I am using WindowBuilder and this is the generated code for the JPanel:
JPanel displayPane = new JPanel();
displayPane.setBackground(Color.WHITE);
displayPane.setBounds(173, 33, 455, 432);
frame.getContentPane().add(displayPane);
After that I want to draw the axis of the graph but I have no idea how.
I've searched everywhere about it but everyone constructs a member class or something in the main class and adds the paintComponent(Graphics g) but that confuses me. What is that trying to accomplish ? Or just give me your way of doing it I don't really care as long as I understand it.
Any help is appreciated :)
Since this is homework, I'm going to give you general guidance without code, but first and foremost, please read this link on performing custom painting with Swing. Next you should put the Window Builder software to the side and work on creating your own code from scratch, at least do this til you're comfortable coding with Swing.
Next suggestions:
Have your DrawingPanel extend JPanel
Override paintComponent(Graphics g)
Call the super's method in your override, super.paintComponent(g) as this will refresh the graphics and erase old "dirty" pixels.
Play with drawing lines using g.drawLine(...)`
keep doing this and you'll get the idea of what you'll need.
Custom painting is achieved by overriding the paintComponent method of a JComponent based class (like JPanel).
This gives you access to the drawing surface onto which content is drawing and eventually shown on screen
See Custom painting and Painting in AWT and Swing for more details.
The Graphics API (or more specifically, the Graphics2D API) is a power abstract toolkit which provides with the means to actually paint stuff to the screen.
At the basic level, this provides you with the ability to specify colors and draw basic shapes and text. At a more complex level, you can define you own shapes, perform more complex coloring effects, including gradient fills and transformations of the basic context
See the 2D Graphics Trail for more details.

JButton background images

I'm writign a POS system(point of sale) for fun. A typical feature of a POS system is buttons that have different background colors for different products. But I don't mean the background behind the button's image, i mean like in this random picture I got off google images:
Edit: Note I changed the look and feel to the system one
I need to do something like THAT with my buttons. I know a few ways this COULD be possible:
Creating a look and feel for my buttons?
Completely overriding the paintComponenet method in my JButtons(But that's a pretty pathetic way to do it... and the border + text isn't drawn when I override that... obviously a bad idea)
Using button.setContentAreaFilled(false);, and putting a JPanel of the same size as the button behind the button.
I don't really know how to create my own look and feel, and it sounds like a pain, especially just for 1 button, and I heard something about breaking the look and feel which scared me away from that idea. The 3rd way sounds plausible, and not extremely difficult, but I what is the very best way to do what I am trying to do?
Right now my code for creating butons is this:
JButton b = new JButton(text);
b.addActionListener(this);
b.setFont(Main.f);
b.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
buttons.add(b);
return b;
I've messed around with this code(Mostly for fun, not practicality):
JButton b = new JButton(text){
public void paintComponent(Graphics g){
super.paintComponent(g);
Color bg = getBackground();
int borderchange = -50;
g.setColor(new Color(
Math.max(0,bg.getRed()+borderchange),
Math.max(bg.getGreen()+borderchange,0),
Math.max(bg.getBlue()+borderchange,0)));
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(getBackground());
int border = 4;
g.fillRect(border,border,getWidth()-border,getHeight()-border);
g.setColor(Color.BLACK);
g.setFont(getFont());
g.drawString(getText(),getWidth()/2,getHeight()/2);
}
};
Creating a look and feel for my buttons?
Look and Feel is something like as theme,
by default this ColorScheme has a one, two, three Colors, this theme is applied for all Swing JComponents,
then all Swing JComponents have got the same Color, ColorScheme
not something that you looking for
Completely overriding the paintComponenet method in my JButtons(But
that's a pretty pathetic way to do it... and the border + text isn't
drawn when I override that... obviously a bad idea)
JButton has array of Colors
you can to override paintComponent, fills whole area, Rectangle with one Color (not something that you looking for) or to use GradientPaint
you can to override BasicButtonUI
override proper key in UIManager and put there arrays of Colors
Using button.setContentAreaFilled(false);, and putting a JPanel of
the same size as the button behind the button.
this could be easiest of ways, prepare Icons (or download set of Icons)
use proper methods, implemented (Mouse & Key & KeyBindings) events
in the JButton API
override ButtonModel (by using ChangeListener)
Have you tried:
yourButton.setBackground(COLOR)
?

Swing: Resizing RadioButton

I need to implement font size switching in my app. But when I increase font's size RadioButtons remain same size and on small screen with high resolution my customer just can't hit it easily. Is there a way to resize RadioButton's round thing programmatically without diging into L&F and redrawing Icons manually (it's complicated since app targets multiple platforms with different UIs and each of them must have 7 icons).
Perfect solution could look like this:
Extraction of native UI icon.
Resizing it
Setting resized icon as component's icon.
How to implement step 1? Is it possible?
EDIT: this is what i tried so far
public class IconImageSaver extends JFrame{
public IconImageSaver() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(0,0,100,100);
setVisible(true);
JRadioButton rad1 = new JRadioButton();
rad1.setBounds(10,10,40,40);
add(rad1);
Icon icon = UIManager.getIcon("RadioButton.icon");//(1) trying to get icon
int w = icon.getIconWidth(),h = icon.getIconHeight();
Image i = rad1.createImage(w, h);
Image i2 = rad1.createImage(w,h);
Graphics g = i.getGraphics();
Graphics g2 = i2.getGraphics();
g.setColor(Color.CYAN);
g.fillRect(0, 0, w, h);
rad1.setIcon(new ImageIcon(i));//setting icons
g2.setColor(Color.RED);
g2.fillRect(0, 0, w, h);
rad1.setPressedIcon(new ImageIcon(i2));//setting icons
}
public static void main(String[] args) {
new IconImageSaver();
}
}
At position (1) i'm trying to get icon image, but it returns only background color.
Can't understand why.
Setting icons for various states works as intended.
Some L&Fs (e.g. Nimbus, Aqua) support a large JComponent.sizeVariant, as discussed in Resizing a Component and Using Client Properties.
Addendum: I must use pure native L&F.
The rendering of a JRadioButton is determined by its associated ButtonUI delegate. The internals of delegates supplied by the native L&F are generally inaccessible and rely on host platform APIs. You have to use the available feature(s) of the user's chosen L&F or supply your own. If you can explain more about the underlying problem, it may help to suggest better alternatives.
Addendum: Absent developing a complete L&F, it may be possible to work with the radio button's parent, JToggleButton. Such buttons work well in a ButtonGroup, as shown here, and they can be decorated arbitrarily, as outlined here.
is very L&F sensitive, by default you can
use proper L&F (only Nimbus has implemented auto_whatever) but we talking about Custom L&F
to override keys in UIManager, but these keys can, could (be presented or with value) or missing in compare with another L&F
create own (J)Component, to overide important methods and
a) put to the UIManger (one def. valid for whole JVM instace)
b) add to the selected, desired or part of (J)Components, e.i. .... in the visible GUI
notice for (I need to implement font size switching in my app) there is very important to test if is required to change (we'll talking about) Font or FontUIResources, part of implemented methods for part of (J)Components to pretty ignore Font and required FontUIResources, now not sure if vice versa too
IMPORTANT NOTE: This was only tested with the default 'Metal' look and feel. I do not guarantee that this will work for any other look and feel. Also I am not entirely sure how it works because it is admittedly a bit of a hack.
I was able to solve this a little bit differently.
I Was scaling my font globally using the UIManager defaults and so I wanted my radio buttons to scale with the font.
I found I could do this by extracting the Icon for the radio button from the UIManager, buffering them, re-sizing them and then deriving a new icon from the graphics of the buffered icons.
I ended up with this function:
public static void scaleRadioButtonIcon(JRadioButton rb){
boolean previousState = rb.isSelected();
rb.setSelected(false);
FontMetrics boxFontMetrics = rb.getFontMetrics(rb.getFont());
Icon radioIcon = UIManager.getIcon("RadioButton.icon");
BufferedImage radioImage = new BufferedImage(
radioIcon.getIconWidth(), radioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
);
Graphics graphics = radioImage.createGraphics();
try{
radioIcon.paintIcon(rb, graphics, 0, 0);
}finally{
graphics.dispose();
}
ImageIcon newRadioImage = new ImageIcon(radioImage);
Image finalRadioImage = newRadioImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
rb.setSelected(true);
Icon selectedRadioIcon = UIManager.getIcon("RadioButton.icon");
BufferedImage selectedRadioImage = new BufferedImage(
selectedRadioIcon.getIconWidth(), selectedRadioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
);
Graphics selectedGraphics = selectedRadioImage.createGraphics();
try{
selectedRadioIcon.paintIcon(rb, selectedGraphics, 0, 0);
}finally{
selectedGraphics.dispose();
}
ImageIcon newSelectedRadioImage = new ImageIcon(selectedRadioImage);
Image selectedFinalRadioImage = newSelectedRadioImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
rb.setSelected(previousState);
rb.setIcon(new ImageIcon(finalRadioImage));
rb.setSelectedIcon(new ImageIcon(selectedFinalRadioImage));
}
What it does is get the size of the font from the radiobuttons's font metrics. Using those metrics, it derives a new icon based on the icon found in the 'Look and Feel' and sizing it to the font's height.
One thing that I am not able to explain is how the icon for the radiobutton coming out of the UIManager changes to the 'selected' icon when I am accessing the same property to get both icons.
I start by saving the state of the control so I can restore it at the end. This is done because in order for the icons to be set properly, the state needs to be unchecked when you first request the icon from the UIManager and then it will need to be checked when you request the icon the second time to get the 'selected' icon.
Again, I am not entirely sure how the UIManager works or why the icon changes when we call the same property just by setting the 'selected' value of a single radiobutton, but that is what is required in order to get both the necessary icons.
If you did not want to use the font to size the controls, you could easily just pass in the height and width as parameters and use them instead of the font's height when setting the buffered image size.
I might mention that this same methodology works with checkboxes

Java Swing: Ghost text showing up when updating text on a JTextArea with partially transparent background

So here's the deal:
I've got a JPanel and a JTextArea inside that one. The JPanel has a background color which has an alpha value of 200, ie. you can paritally see the background image through the JPanel. Ain't that called partial transparency? Anyway, then I've set the JTextArea non-opaque, so that I can fully see through that one:
JPanel p = new JPanel();
p.setBackground(new Color(237, 234, 215, 200);
JTextArea jta = new JTextArea("Blahblahblahblah");
jta.setOpaque(false);
p.add(jta);
Ok, so when I hit a button, the text will be changed like this:
jta.setText("new BlahBlah...");
Then it happens: the first text remains back there with a new partially transparent film on it. And the text I added, comes on top of course, but right there behind you can see the previous one. When I change the text some few times more, the ghost disappears.
The screenshot as a link.
Translation (the screenshot has 3 shots on a row): Left one: "Question # 1 out of 8: (a political question)? (My comment: OK)"Center: "Question # 2 out of 8: (another question, never mind)? (My comment: The ghost is there! [and the arrow pointing it out])"Right-hand side: "Question # 8 out of 8: (another question)? (My comment: OK)"
If I reduce the amount of questions this program swaps, from 8 to 3, for example, the last one looks usually good, the ghost is gone. But sometimes it sticks on no matter what I do. Could it possibly have something to do with not enough memory (I hardly swallow that, though)?
So, please help me out, dudes! I've got the deadline in 48 hrs.
PS. In case you wonder, that language is Finnish. I'm working on a school project: It's gonna be a comparing machine that can have a variety of applications: For example, if you have a public election coming, the press/media may use this kind of machine on the web to get the candidate's opinions on whatever issues, and then voters may enter their opinions too, and the machine calculates which candidates match the voter's thoughts best. See my homepage, ie. the project blog (Finnish) for more screenshots in case you're interested.
an55i
p.setBackground(new Color(237, 234, 215, 200);
Swing does not support transparent backgrounds.
Swing expects a component to be either:
opaque - which implies the component will repaint the entire background with an opaque color first before doing custom painting, or
fully transparent - in which case Swing will first paint the background of the first opaque parent component before doing custom painting.
The setOpaque(...) method is used to control the opaque property of a component.
In either case this makes sure any painting artifacts are removed and custom painting can be done properly.
If you want to use tranparency, then you need to do custom painting yourself to make sure the background is cleared.
The custom painting for the panel would be:
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
panel.setOpaque(false); // background of parent will be painted first
Similar code would be required for every component that uses transparency.
Or, you can check out Background With Transparency for custom class that can be used on any component that will do the above work for you.
Finally I got it showing up right! It's just that:
Both the container (p in this case) and the component (jta) inside must be setOpaque(false);
The container must always clear itself by grabbing the inner component's background color, which - actually - is the color that the inner component kind of gets from it's ancestor, ie. the container itself.
Aren't I somehow correct? Well, at least the code does it's trick.
Class fields:
private JTextArea jta;
private JPanel p;
Later on:
jta = new JTextArea("BlahBlahBLAH");
jta.setBackground(new Color(237, 234, 215, 200));
p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
if(getContentPane().isAncestorOf(jta)) {
g.setColor(jta.getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
};
p.setOpaque(false);
jta.setOpaque(false);
p.add(ta);
And that's it. I even put some Borders and stuff before adding "jta" to "p". And what's coolest, I actually learnt something about this. Thanks for support!

Categories