Painters odd behavior - java

I'm trying to customise some UI by code using a BackgroundPainter but I'm encountering odd and unexpected results:
public class TabView extends Form {
private Tabs tabs;
public TabView() {
super("Radio Web", new BorderLayout());
tabs = new Tabs(Component.BOTTOM);
addComponent(BorderLayout.CENTER, tabs);
tabs.setSwipeActivated(false);
Component component = null;
Button playButton = new Button(FontImage.createMaterial(FontImage.MATERIAL_PLAY_ARROW, UIManager.getInstance().getComponentStyle("Title"), 10));
playButton.getAllStyles().setBorder(RoundBorder.create().color(0x94170C));
playButton.getAllStyles().setMarginBottom(0);
playButton.getAllStyles().setMarginLeft(0);
playButton.getAllStyles().setMarginTop(0);
Label mediaInfoLabel = new Label("Artist - Title");
mediaInfoLabel.getAllStyles().setPaddingTop(2);
mediaInfoLabel.getAllStyles().setPaddingBottom(2);
Slider volumeSlider = new Slider();
volumeSlider.setMinValue(0);
volumeSlider.setMaxValue(100);
volumeSlider.setEditable(true);
Container box = GridLayout.encloseIn(1, new Container(), volumeSlider, mediaInfoLabel);
Container south = new Container(new FlowLayout(Component.LEFT, Component.BOTTOM));
south.getAllStyles().setBgPainter(new BackgroundPainter(south) {
#Override
public void paint(Graphics g, Rectangle rect) {
int color = g.getColor();
int alpha = g.getAlpha();
g.setColor(0xD12115);
g.setAlpha(255);
int y = rect.getHeight() / 2;
g.fillRect(0, y, rect.getWidth(), rect.getHeight() - y);
g.setColor(color);
g.setAlpha(alpha);
}
});
south.add(playButton).add(box);
component = BorderLayout.south(south);
component.getAllStyles().setBgPainter(new BackgroundPainter(component) {
#Override
public void paint(Graphics g, Rectangle rect) {
int color = g.getColor();
int alpha = g.getAlpha();
g.setColor(0x150100);
g.setAlpha(255);
g.fillRect(0, 0, rect.getWidth(), rect.getHeight());
g.setColor(color);
g.setAlpha(alpha);
}
});
tabs.addTab("", FontImage.MATERIAL_AUDIOTRACK, 5, component);
BrowserComponent sito = new BrowserComponent();
sito.setURL("https://www.codenameone.com");
tabs.addTab("", FontImage.MATERIAL_HTTP, 5, sito);
BrowserComponent fb = new BrowserComponent();
fb.setURL("https://www.facebook.com");
tabs.addTab("", FontImage.MATERIAL_FACE, 5, fb);
}
}
As a result, I can see that "component" paints its own blackish background while "south" doesn't(it should be half red). Am I doing it wrong? Furthermore, the GridLayout doesn't take correctly care of margin/padding, I have to increase the label padding to avoid it to be cut.
Thanks.

I encountered a similar problem in the past and had to ditch BackgroundPainter for making 2 colours.
From the code you posted, similar style could be achieved by doing below:
Just copy and paste this and it should work, you can also replace BP on component to use the added method
public class TabView extends Form {
private Tabs tabs;
public TabView() {
super("Radio Web", new BorderLayout());
tabs = new Tabs(Component.BOTTOM);
addComponent(BorderLayout.CENTER, tabs);
tabs.setSwipeActivated(false);
Component component = null;
Button playButton = new Button(FontImage.createMaterial(FontImage.MATERIAL_PLAY_ARROW, UIManager.getInstance().getComponentStyle("Title"), 10));
playButton.getAllStyles().setBorder(RoundBorder.create().color(0x94170C));
playButton.getAllStyles().setMarginBottom(0);
playButton.getAllStyles().setMarginLeft(0);
playButton.getAllStyles().setMarginTop(0);
Label mediaInfoLabel = new Label("Artist - Title");
mediaInfoLabel.getAllStyles().setPaddingTop(2);
mediaInfoLabel.getAllStyles().setPaddingBottom(2);
Slider volumeSlider = new Slider();
volumeSlider.setMinValue(0);
volumeSlider.setMaxValue(100);
volumeSlider.setEditable(true);
Container box = GridLayout.encloseIn(1, new Container(), volumeSlider, mediaInfoLabel);
Container south = new Container(new FlowLayout(Component.LEFT, Component.BOTTOM));
south.add(playButton).add(box);
paintBackgroundRect2Colors(south);
component = BorderLayout.south(south);
component.getAllStyles().setBgPainter(new BackgroundPainter(component) {
#Override
public void paint(Graphics g, Rectangle rect) {
int color = g.getColor();
int alpha = g.getAlpha();
g.setColor(0x150100);
g.setAlpha(255);
g.fillRect(0, 0, rect.getWidth(), rect.getHeight());
g.setColor(color);
g.setAlpha(alpha);
}
});
tabs.addTab("", FontImage.MATERIAL_AUDIOTRACK, 5, component);
BrowserComponent sito = new BrowserComponent();
sito.setURL("https://www.codenameone.com");
tabs.addTab("", FontImage.MATERIAL_HTTP, 5, sito);
BrowserComponent fb = new BrowserComponent();
fb.setURL("https://www.facebook.com");
tabs.addTab("", FontImage.MATERIAL_FACE, 5, fb);
}
public static void paintBackgroundRect2Colors(Component cmp) {
Image i = Image.createImage(cmp.getPreferredW(), cmp.getPreferredH(), 0xffffff);
Graphics g = i.getGraphics();
g.setAntiAliased(true);
boolean antiAliased = g.isAntiAliased();
int y = i.getHeight() / 2;
// Top half
g.setAlpha(255); //Change this to 0 if you want top half to be transparent
g.setColor(0x150100); // Change this to any color you want, I used "component" color just to blend the look and feel
g.fillRect(0, 0, i.getWidth(), y);
// Bottom half
g.setAlpha(255);
g.setColor(0xD12115);
g.fillRect(0, y, i.getWidth(), i.getHeight());
g.setAntiAliased(antiAliased);
// Set background image and make sure it fills
cmp.getAllStyles().setBgImage(i, true);
cmp.getAllStyles().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL, true);
}
}

Related

Redrawing a JLabel to get a Gradient Painted Text

I am trying to create a gradient paint for text that goes from the top of the word to the bottom, not from left to right. I was actually able to achieve this from the help of this link here. They took the shape of the text, and painted it on the panel. I simply edited their code and was able to apply the affect I am looking for. Here is what I edited their paint method to (where s is a Shape):
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.translate(100, 150);
Rectangle2D r = s.getBounds2D();
int x = (int) r.getX();
int y = (int) r.getY();
int h = (int) r.getHeight();
GradientPaint gp = new GradientPaint(x, y, Color.MAGENTA, x, h, Color.ORANGE);
g2.setPaint(gp);
g2.fill(s);
}
This worked, but this approach is overriding a paintComponent method of a JPanel. I am trying to recreate this by a new GradientLabel Class that extends JLabel. The issue I am having is that the g2d.fill(s) method is drawing the shape somewhere above the label, seemingly out of reach. I don't understand why it is doing this. Perhaps its from casting Graphics2D g.create();? I have had to add the g2.translate(x,y) method to pull the shape down into a viewable location.
I guess I have 2 questions.
Why doesn't the g2.fill(s) draw the shape over the text that was drawn by the JLabel super method? Could this be because of my layout manager?
Is this approach even the way I should go? Is there an easier way to apply a vertical paint gradient to text?
Here is the minimal code for testing:
public class test extends JFrame {
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
test frame = new test();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 516, 360);
contentPane = new JPanel();
contentPane.setBorder(null);
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[]{0, 0};
gbl_contentPane.rowHeights = new int[]{0, 100, 0};
gbl_contentPane.columnWeights = new double[]{1.0, Double.MIN_VALUE};
gbl_contentPane.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE};
contentPane.setLayout(gbl_contentPane);
Component verticalStrut = Box.createVerticalStrut(20);
GridBagConstraints gbc_verticalStrut = new GridBagConstraints();
gbc_verticalStrut.insets = new Insets(0, 0, 5, 0);
gbc_verticalStrut.gridx = 0;
gbc_verticalStrut.gridy = 0;
contentPane.add(verticalStrut, gbc_verticalStrut);
GradientLabel lblTest = new GradientLabel("TEST");
lblTest.setHorizontalAlignment(SwingConstants.CENTER);
lblTest.setGradientColors(Color.GREEN, Color.WHITE);
lblTest.setFont(new Font("Tahoma", Font.PLAIN, 70));
GridBagConstraints gbc_lblTest = new GridBagConstraints();
gbc_lblTest.fill = GridBagConstraints.BOTH;
gbc_lblTest.gridx = 0;
gbc_lblTest.gridy = 1;
contentPane.add(lblTest, gbc_lblTest);
}
public class GradientLabel extends JLabel {
private Color c1;
private Color c2;
public GradientLabel(String text) {
setText(text);
this.setOpaque(false);
}
public void setGradientColors(Color c1, Color c2) {
this.c1 = c1;
this.c2 = c2;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Font f = getFont();
GlyphVector v = f.createGlyphVector(getFontMetrics(f).getFontRenderContext(), getText());
Shape s = v.getOutline();
Rectangle2D r = s.getBounds2D();
int x = (int) r.getX();
int y = (int) r.getY();
int h = (int) r.getHeight();
int w = (int) r.getWidth();
//without this the shape is drawn almost out of view
g2d.translate(x, h);
g2d.drawRect(x, y, w, h);
//for some reason using only h as the second y doesn't show much of the second color.
//Subtracting 60 arbitrarily showed more of the second color in the gradient.
//Bonus points for an explanation on why that happens.
GradientPaint gp = new GradientPaint(x, y, c1, x, h - 60, c2);
g2d.setPaint(gp);
g2d.fill(s);
}
}
}
Well I was able to answer my own question! First time for everything I guess.
I tracked the code on the JLabel back to the class where it was actually being drawn on the screen to the BasicLabelUI Class. I studied and determined that if I could build a new class that extends this class, I could simply override the painting portion of this class. After testing and determining the best gradient that fully paints both colors from the top of the text to the bottom, this is what I came up with:
public class SBLabelUI extends BasicLabelUI {
#Override
protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
if (l instanceof GradientLabel) {
GradientLabel gl = (GradientLabel) l;
Graphics2D g2d = (Graphics2D) g;
Font f = gl.getFont();
int h = gl.getFontMetrics(f).getHeight();
GradientPaint gp = new GradientPaint(textX, textY, gl.c2, textX, Math.abs(textY-h), gl.c1);
g2d.setPaint(gp);
g2d.drawString(s, textX, textY);
} else {
super.paintEnabledText(l, g, s, textX, textY);
}
}
}
And in my Constructor for the gradient Label, i simply set the UI:
public GradientLabel(String text) {
setText(text);
this.setOpaque(false);
setUI(new SBLabelUI());
}
It works charmingly:

How should I make the RoundedBorder background transparent? [duplicate]

The following screenshot shows a test of TextBubbleBorder1. I would like to make the corners of the component that are outside the rectangle to be entirely transparent & show whatever component is beneath it. I found a way to restrict the BG color of a label to 'inside the border' by setting a Clip (representing the area outside the rounded corners) on the Graphics2D instance and calling clearRect(). That can be seen in Label 1.
However you can see the downside of this approach when there is a red BG (or any non-standard color) on the parent panel. The corners default to the default panel color (easiest to see in Panel 2).
Ultimately I would like this to work for a non-standard color in the parent container, but it was partly inspired by What do I need to do to replicate this component with gradient paint?
Does anybody know a way to get those corners transparent?
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;
public class BorderTest {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JPanel gui = new JPanel(new GridLayout(1,0,5,5));
gui.setBorder(new EmptyBorder(10,10,10,10));
gui.setBackground(Color.RED);
AbstractBorder brdr = new TextBubbleBorder(Color.BLACK,2,16,0);
JLabel l1 = new JLabel("Label 1");
l1.setBorder(brdr);
gui.add(l1);
JLabel l2 = new JLabel("Label 2");
l2.setBorder(brdr);
l2.setBackground(Color.YELLOW);
l2.setOpaque(true);
gui.add(l2);
JPanel p1 = new JPanel();
p1.add(new JLabel("Panel 1"));
p1.setBorder(brdr);
p1.setOpaque(false);
gui.add(p1);
JPanel p2 = new JPanel();
p2.add(new JLabel("Panel 2"));
p2.setBorder(brdr);
gui.add(p2);
JOptionPane.showMessageDialog(null, gui);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
class TextBubbleBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private int pointerSize = 7;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
RenderingHints hints;
TextBubbleBorder(
Color color) {
new TextBubbleBorder(color, 4, 8, 7);
}
TextBubbleBorder(
Color color, int thickness, int radii, int pointerSize) {
this.thickness = thickness;
this.radii = radii;
this.pointerSize = pointerSize;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness / 2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + pointerSize + strokePad;
insets = new Insets(pad, pad, bottomPad, pad);
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
#Override
public void paintBorder(
Component c,
Graphics g,
int x, int y,
int width, int height) {
Graphics2D g2 = (Graphics2D) g;
int bottomLineY = height - thickness - pointerSize;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0 + strokePad,
0 + strokePad,
width - thickness,
bottomLineY,
radii,
radii);
Polygon pointer = new Polygon();
// left point
pointer.addPoint(
strokePad + radii + pointerPad,
bottomLineY);
// right point
pointer.addPoint(
strokePad + radii + pointerPad + pointerSize,
bottomLineY);
// bottom point
pointer.addPoint(
strokePad + radii + pointerPad + (pointerSize / 2),
height - strokePad);
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
Area spareSpace = new Area(new Rectangle(0, 0, width, height));
spareSpace.subtract(area);
g2.setClip(spareSpace);
g2.clearRect(0, 0, width, height);
g2.setClip(null);
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
}
While the TextBubbleBorder was devised for Internal padding for JTextArea with background Image (& ended up using a JLabel since the text area was a mess for the reasons mentioned above), by specifying a pointerSize of 0 we end up with a 'rounded rectangle' instead.
N.B. There is a clipping bug in this code, which is fixed in the accepted answer to paintComponent() is drawing on other components. This should only be considered as a solution if the 'clipping bug fix' is incorporated.
// Paint the BG color of the parent, everywhere outside the clip
// of the text bubble.
See this point in the code for the source that shows correctly as:
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;
public class BorderTest {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JPanel gui = new JPanel(new GridLayout(2,0,5,5));
gui.setBorder(new EmptyBorder(10,10,10,10));
gui.setBackground(Color.RED);
AbstractBorder brdrLeft = new TextBubbleBorder(Color.BLACK,2,16,16);
AbstractBorder brdrRight = new TextBubbleBorder(Color.BLACK,2,16,16,false);
JLabel l1 = new JLabel("Label 1");
l1.setBorder(brdrRight);
gui.add(l1);
JLabel l2 = new JLabel("Label 2");
l2.setBorder(brdrLeft);
l2.setBackground(Color.YELLOW);
l2.setOpaque(true);
gui.add(l2);
JPanel p1 = new JPanel();
p1.add(new JLabel("Panel 1"));
p1.setBorder(brdrRight);
p1.setOpaque(false);
gui.add(p1);
JPanel p2 = new JPanel();
p2.add(new JLabel("Panel 2"));
p2.setBorder(brdrLeft);
gui.add(p2);
JOptionPane.showMessageDialog(null, gui);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
class TextBubbleBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private int pointerSize = 7;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
private boolean left = true;
RenderingHints hints;
TextBubbleBorder(
Color color) {
this(color, 4, 8, 7);
}
TextBubbleBorder(
Color color, int thickness, int radii, int pointerSize) {
this.thickness = thickness;
this.radii = radii;
this.pointerSize = pointerSize;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness / 2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + pointerSize + strokePad;
insets = new Insets(pad, pad, bottomPad, pad);
}
TextBubbleBorder(
Color color, int thickness, int radii, int pointerSize, boolean left) {
this(color, thickness, radii, pointerSize);
this.left = left;
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
#Override
public void paintBorder(
Component c,
Graphics g,
int x, int y,
int width, int height) {
Graphics2D g2 = (Graphics2D) g;
int bottomLineY = height - thickness - pointerSize;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0 + strokePad,
0 + strokePad,
width - thickness,
bottomLineY,
radii,
radii);
Polygon pointer = new Polygon();
if (left) {
// left point
pointer.addPoint(
strokePad + radii + pointerPad,
bottomLineY);
// right point
pointer.addPoint(
strokePad + radii + pointerPad + pointerSize,
bottomLineY);
// bottom point
pointer.addPoint(
strokePad + radii + pointerPad + (pointerSize / 2),
height - strokePad);
} else {
// left point
pointer.addPoint(
width - (strokePad + radii + pointerPad),
bottomLineY);
// right point
pointer.addPoint(
width - (strokePad + radii + pointerPad + pointerSize),
bottomLineY);
// bottom point
pointer.addPoint(
width - (strokePad + radii + pointerPad + (pointerSize / 2)),
height - strokePad);
}
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
// Paint the BG color of the parent, everywhere outside the clip
// of the text bubble.
Component parent = c.getParent();
if (parent!=null) {
Color bg = parent.getBackground();
Rectangle rect = new Rectangle(0,0,width, height);
Area borderRegion = new Area(rect);
borderRegion.subtract(area);
g2.setClip(borderRegion);
g2.setColor(bg);
g2.fillRect(0, 0, width, height);
g2.setClip(null);
}
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
}
Try this:
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension arcs = new Dimension(15,15); //Border corners arcs {width,height}, change this to whatever you want
int width = getWidth();
int height = getHeight();
Graphics2D graphics = (Graphics2D) g;
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//Draws the rounded panel with borders.
graphics.setColor(getBackground());
graphics.fillRoundRect(0, 0, width-1, height-1, arcs.width, arcs.height);//paint background
graphics.setColor(getForeground());
graphics.drawRoundRect(0, 0, width-1, height-1, arcs.width, arcs.height);//paint border
}
};
With my test:
JFrame f = new JFrame();
f.setLayout(null);
f.setDefaultCloseOperation(3);
f.setSize(500, 500);
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension arcs = new Dimension(15,15);
int width = getWidth();
int height = getHeight();
Graphics2D graphics = (Graphics2D) g;
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//Draws the rounded opaque panel with borders.
graphics.setColor(getBackground());
graphics.fillRoundRect(0, 0, width-1, height-1, arcs.width, arcs.height);//paint background
graphics.setColor(getForeground());
graphics.drawRoundRect(0, 0, width-1, height-1, arcs.width, arcs.height);//paint border
}
};
p.setBounds(10,10,100,30);
p.setOpaque(false);
f.getContentPane().setBackground(Color.red);
f.add(p);
f.show();
the result is:
Thanks #BackSlash, nice and simple. I expanded upon this so it's more reusable. This also allows setting a background color in the constructor. And I show how you can make a circular panel for fun.
import java.awt.*;
import javax.swing.*;
public class RoundedPanelExample extends JFrame
{
public RoundedPanelExample()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Rounded Panel Example");
setResizable(true);
setDefaultLookAndFeelDecorated(true);
setSize(500, 500);
Container pane = getContentPane();
pane.setLayout(null);
pane.setBackground(Color.LIGHT_GRAY);
JPanel p1 = new RoundedPanel(10, Color.CYAN);
p1.setBounds(10,10,100,60);
p1.setOpaque(false);
pane.add(p1);
JPanel p2 = new RoundedPanel(15, Color.RED);
p2.setBounds(150,10,50,50);
p2.setOpaque(false);
pane.add(p2);
JPanel p3 = new RoundedPanel(30);
p3.setBounds(230,10,100,150);
p3.setOpaque(false);
pane.add(p3);
JPanel p4 = new RoundedPanel(20);
p4.setBounds(10,200,100,100);
p4.setBackground(Color.GREEN);
p4.setOpaque(false);
pane.add(p4);
JPanel p5 = new RoundedPanel(200);
p5.setBounds(150,200,200,200);
p5.setBackground(Color.BLUE);
p5.setOpaque(false);
pane.add(p5);
}
public static void main(String[] args)
{
RoundedPanelExample gui = new RoundedPanelExample();
gui.setVisible(true);
}
class RoundedPanel extends JPanel
{
private Color backgroundColor;
private int cornerRadius = 15;
public RoundedPanel(LayoutManager layout, int radius) {
super(layout);
cornerRadius = radius;
}
public RoundedPanel(LayoutManager layout, int radius, Color bgColor) {
super(layout);
cornerRadius = radius;
backgroundColor = bgColor;
}
public RoundedPanel(int radius) {
super();
cornerRadius = radius;
}
public RoundedPanel(int radius, Color bgColor) {
super();
cornerRadius = radius;
backgroundColor = bgColor;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension arcs = new Dimension(cornerRadius, cornerRadius);
int width = getWidth();
int height = getHeight();
Graphics2D graphics = (Graphics2D) g;
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//Draws the rounded panel with borders.
if (backgroundColor != null) {
graphics.setColor(backgroundColor);
} else {
graphics.setColor(getBackground());
}
graphics.fillRoundRect(0, 0, width-1, height-1, arcs.width, arcs.height); //paint background
graphics.setColor(getForeground());
graphics.drawRoundRect(0, 0, width-1, height-1, arcs.width, arcs.height); //paint border
}
}
}
Possible cheaper alternative
public class RoundedLabel extends JLabel {
private final Rectangle rv = new Rectangle();
#Override
public void updateUI() {
super.updateUI();
setBorder(new EmptyBorder(1, 3, 1, 3));
}
#Override
protected void paintComponent(Graphics g) {
getBounds(rv);
var g2 = (Graphics2D) g;
g2.setColor(getBackground());
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillRoundRect(rv.x, rv.y, rv.width, rv.height, 8, 8);
super.paintComponent(g);
}
}

java JDialog draw called double

I've got a problem which makes me go crazy. I call a Method via this line of code:
private void btnGetFolderMouseClicked(MouseEvent e) {
MessageController.showAlert(AlertBox.AlertType.OK);
}
and this method is called:
public class MessageController {
public static void showAlert(AlertBox.AlertType alertType) {
AlertBox alertBox = new AlertBox("Test12345678910dfkjsdgmdgbu<xdfg<bdxgj ghfhftz rgdx", alertType);
alertBox.getRootPane().setOpaque(false);
//alertBox.getContentPane ().setBackground (new Color(0, 0, 0, 0));
//alertBox.setBackground (new Color(0, 0, 0, 0));
alertBox.setVisible(true);
// BDialog dialog = new BDialog();
// dialog.setVisible(true);
System.out.println("Nach Box");
//alertBox.invalidate();
}
}
And here is my JDialog class:
public class AlertBox extends JDialog {
private ImageIcon downSide = new ImageIcon(getClass().getResource("/AlertBox/Down_Side.png"));
private ImageIcon leftDownCorner = new ImageIcon(getClass().getResource("/AlertBox/Left_Down_Corner.png"));
private ImageIcon leftSide = new ImageIcon(getClass().getResource("/AlertBox/Left_Side.png"));
private ImageIcon leftUpCorner = new ImageIcon(getClass().getResource("/AlertBox/Left_Up_Corner.png"));
private ImageIcon rightDownCorner = new ImageIcon(getClass().getResource("/AlertBox/Right_Down_Corner.png"));
private ImageIcon rightSide = new ImageIcon(getClass().getResource("/AlertBox/Right_Side.png"));
private ImageIcon rightUpCorner = new ImageIcon(getClass().getResource("/AlertBox/Right_Up_Corner.png"));
private ImageIcon upSide = new ImageIcon(getClass().getResource("/AlertBox/Up_Side.png"));
private String text;
private Rectangle2D fontSize;
private Font font = new Font("Arial", Font.BOLD, 13);
private ImagedButton btnOK;
public enum AlertType{
OK,
Warning,
Error
}
private AlertType alertType;
public AlertBox(String text, AlertType alertType){
// Set JDialog properties
super(new JFrame(), true);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
setUndecorated(true);
setLocationRelativeTo(null);
this.text = text;
this.alertType = alertType;
btnOK = new ImagedButton("OK");
btnOK.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button Clicked");
exitAlertBox();
}
});
//this.add(btnOK);
}
#Override
public void paint(Graphics g) {
// Create Graphics2D Object
Graphics2D g2d = (Graphics2D) g.create();
// Get the Size
fontSize = StringMetrics.getBounds(g2d, font, text);
// set the fontSize
int width = (int) fontSize.getWidth() + 5 + leftSide.getIconWidth() + 5 + rightSide.getIconWidth();
int height = leftUpCorner.getIconHeight() + 5 + (int)fontSize.getHeight() + 5 + btnOK.getHeight() + 5 + leftDownCorner.getIconHeight();
this.setSize(width, height);
//this.replaceButton(width, height);
// Draw Left Upper Corner
System.out.println(leftDownCorner.getIconWidth() + " ; " + leftDownCorner.getIconHeight());
g.drawImage(leftUpCorner.getImage(), 0, 0, this);
g.drawImage(new ImageIcon(getClass().getResource("/Buttons/Button_Down.png")).getImage(), 21, 20, this);
// Draw Upper Side
//g.drawImage(upSide.getImage(), leftUpCorner.getIconWidth(), 0, 5 + (int) fontSize.getWidth() + 5, upSide.getIconHeight(), this);
// Draw Right Upper Corner
//g.drawImage(rightUpCorner.getImage(), this.getWidth() - rightUpCorner.getIconWidth(), 0, this);
// Draw Left Side
//g.drawImage(leftSide.getImage(), 0, leftUpCorner.getIconHeight(), leftSide.getIconWidth(), 5 + (int)fontSize.getHeight() + 5, this);
// Draw Right Side
//g.drawImage(rightSide.getImage(), width - rightSide.getIconWidth(), rightUpCorner.getIconHeight(), rightSide.getIconWidth(), 5 + upSide.getIconHeight() + 5, this);
// Draw Left Downer Corner
//g.drawImage(leftDownCorner.getImage(), 0, height - leftDownCorner.getIconHeight(), this);
// Draw Right Downer Corner
//g.drawImage(rightDownCorner.getImage(), this.getWidth() - rightUpCorner.getIconWidth(), height - rightDownCorner.getIconHeight(), this);
// Draw Downer Side
//g.drawImage(downSide.getImage(), leftDownCorner.getIconWidth(), height - downSide.getIconHeight(), 5 + (int) fontSize.getWidth() + 5, downSide.getIconHeight(), this);
// Draw the text
//g2d.drawString(text, 10, 10);
//g2d.drawString(text, leftUpCorner.getIconWidth() + 5, (int)fontSize.getHeight() + 8);
if (this.alertType == AlertType.OK){
}
}
private void replaceButton(int width, int height){
// paint OK-Button
int testWidth = width - (btnOK.getWidth() / 2);
int testHeight = height - btnOK.getHeight() - 5;
btnOK.setBounds(testWidth, testHeight, btnOK.getWidth(), btnOK.getHeight());
}
private void exitAlertBox(){
this.dispose();
}
}
The problem is, that the window should (at this version of code) display 2 Images. Well it does.. sometimes.. But most of the runs it doesn't.
When I debug my code, it seems like the 'paint' Method is called twice, but i don't find the line where this happens.
Did i do anything wrong?
Thanks for your help :)

How to make the Panels on JLayeredPane transparent?

I have a JLayeredPane with 4 layers added to it. 1 base layer, which is opaque and three 'transparent' layers (setOpaque(false)).
The problem is that although the panels are drawn onto, with every refresh a gray color is shown. The same thing happens if there is no refresh happening. In other words, instead of showing whatever was drawn onto the base layer, a gray color is shown, I assume this is from one of the layers above.
Here is a SSCCE - I'm not sure if this is short enough but it shows my problem.
public class SSCCE extends JLayeredPane{
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(950, 600);
frame.add(new SSCCE());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
// private fields
private boolean drawInitial = true;
private boolean drawn = false;
private JPanel overlay, base, iconPanel, middle;
private BufferedImage baseBuffer, midBuffer, overlayBuffer, iconBuffer;
private boolean updateInit = true;
private Rectangle2D stored = new Rectangle2D.Double(60, 60, 40, 100);
public SSCCE() {
setBorder(new LineBorder(Color.BLACK));
setDoubleBuffered(false);
setOpaque(true);
setSize(new Dimension(950, 600));
setPreferredSize(new Dimension(950, 600));
base = new JPanel();
base.setBackground(new Color(0,0,0,0));
base.setSize(new Dimension(getWidth(), getHeight()));
this.add(base, new Integer(0));
middle = new JPanel();
middle.setSize(new Dimension(getWidth(), getHeight()));
middle.setBackground(new Color(0,0,0,0));
middle.setOpaque(false);
this.add(middle, new Integer(1));
overlay = new JPanel();
overlay.setBackground(new Color(0,0,0,0));
overlay.setOpaque(false);
overlay.setSize(new Dimension(getWidth(), getHeight()));
this.add(overlay, new Integer(2));
iconPanel = new JPanel();
iconPanel.setBackground(new Color(0,0,0,0));
iconPanel.setSize(getWidth(), getHeight());
iconPanel.setOpaque(false);
this.add(iconPanel, new Integer(3));
}
public void update() {
if(updateInit){
checkBuffer();
updateInit = false;
}
drawInfoRect();
drawIcon();
highlightPath(stored);
}
public void render() {
if (drawInitial) {
Graphics2D baseGraphics = (Graphics2D) base.getGraphics();
baseGraphics.drawImage(baseBuffer, 0, 0, null);
}
setResistanceColor((Graphics2D)baseBuffer.getGraphics());
middle.getGraphics().drawImage(midBuffer, 0, 0, null);
iconPanel.getGraphics().drawImage(iconBuffer, 0, 0, null);
drawInfoRect();
base.getGraphics().drawImage(baseBuffer, 0, 0, null);
if (drawn) {
overlay.getGraphics().drawImage(overlayBuffer, 0, 0, null);
}
repaint();
}
// /**
// * draws the appropriate colour
// */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
update();
render();
}
/**
* sets the appropriate colours according to the resistance
* #param g2
*/
private void setResistanceColor(Graphics2D g2) {
Rectangle2D sp = new Rectangle2D.Double(50,50, 50, 50);
g2.setColor(Color.GREEN);
g2.fill(sp);
g2.setColor(Color.BLACK);
}
/**
* checks if there already exists an image to buffer with
*/
private void checkBuffer() {
if (baseBuffer == null) {
baseBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
// background color
Graphics2D g2 = (Graphics2D) baseBuffer.getGraphics();
g2.setColor(Color.decode("#729fcf"));
Rectangle2D rect = new Rectangle2D.Double(0, 0, baseBuffer.getWidth(), baseBuffer.getHeight());
g2.fill(rect);
}
if (midBuffer == null) {
midBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
// background color
Graphics2D g2 = (Graphics2D) midBuffer.getGraphics();
g2.setColor(Color.RED);
Rectangle2D rect = new Rectangle2D.Double(0, 0, midBuffer.getWidth(), midBuffer.getHeight());
g2.fill(rect);
}
if (overlayBuffer == null) {
overlayBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
}
if (iconBuffer == null) {
iconBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
}
}
public void highlightPath(Shape enlighten) {
Area area = new Area();
area.add(new Area(enlighten));
// clearing image before drawing
Graphics2D midBufferG = (Graphics2D) midBuffer.getGraphics();
clearImage(midBufferG);
midBufferG.setColor(Color.white);
// adds a transparent overlay
midBufferG.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));
midBufferG.fill(area);
}
public void drawIcon() {
Graphics2D iconG = (Graphics2D) iconBuffer.getGraphics();
clearImage(iconG);
}
public void drawInfoRect() {
Graphics2D graph = (Graphics2D) overlayBuffer.getGraphics();
Rectangle2D visible = getVisibleRect();
int boxX = (int) (visible.getX() + 50);
int boxY = (int) (visible.getY() + 450);
RoundRectangle2D rect = new RoundRectangle2D.Double(boxX, boxY, 200, 150, 25, 25);
graph.setColor(Color.decode("#729fcf").darker());
graph.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
graph.fill(rect);
graph.setColor(Color.BLACK);
drawn = true;
}
private void clearImage(Graphics2D graph){
graph.setComposite(AlphaComposite.Clear);
graph.fillRect(0, 0, overlayBuffer.getWidth(), overlayBuffer.getHeight());
graph.setComposite(AlphaComposite.SrcOver);
}
}
It might be some basic mistake I made. Thanks for your help!
One of the previously suggested answers actually solved my question, but for some reason they deleted their answer.
Setting the Background of my panels to setBackground(new
Color(0,0,0,0)); solved my problems.
According to the person that suggested this, the cause of that is the fact that JComponent may or may not draw transparent if not explicitly specified.
Thanks again!

Creating a custom button in Java with JButton

I am trying to create a button that has a custom shape (hexagon), but otherwise acts like a normal JButton would (that is, works with an ActionListener).
I have created a class that extends AbstractButton, but it doesn't seem to be sending events to the ActionListener when I click it. If I change the class to extend JButton it works perfectly, but it screws up the way the button is displayed. I'm assuming that there is a method that I need to override to get it to fire events, but I can't figure out what it is.
If you want to create a CustomButtonUI then you have to look
deepest to the BasicXxxUI.
overide List of Colors from JButton
Note there isn't paintComponent(). It's wrong, just use the paint() method,
Below is just a simple example if that is possible (for Metal JButton). Note just for Metal LaF, I'm so lazy and there isn't something about override paintText, paintIcon, paintFocus, paintBorder (for all funcionalities you have to check available methods from BasicButtonUI), and something I put to the ButtonModel, just for my enjoyment.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalButtonUI;
public class TextAreaInButton {
private JFrame frame = new JFrame("sssssssss");
private JButton tip1Null = new JButton(" test button ");
public TextAreaInButton() {
Border line, raisedbevel, loweredbevel, title, empty;
line = BorderFactory.createLineBorder(Color.black);
raisedbevel = BorderFactory.createRaisedBevelBorder();
loweredbevel = BorderFactory.createLoweredBevelBorder();
title = BorderFactory.createTitledBorder("");
empty = BorderFactory.createEmptyBorder(1, 1, 1, 1);
final Border compound;
Color crl = (Color.blue);
compound = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl));
Color crl1 = (Color.red);
final Border compound1;
compound1 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl1));
Color crl2 = (Color.black);
final Border compound2;
compound2 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl2));
tip1Null.setFont(new Font("Serif", Font.BOLD, 14));
tip1Null.setForeground(Color.darkGray);
tip1Null.setPreferredSize(new Dimension(50, 30));
tip1Null.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
tip1Null.setBorderPainted(true);
tip1Null.setFocusPainted(false);
tip1Null.setBorder(compound);
tip1Null.setHorizontalTextPosition(SwingConstants.CENTER);
tip1Null.setVerticalTextPosition(SwingConstants.BOTTOM);
tip1Null.setUI(new ModifButtonUI());
tip1Null.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (model.isRollover()) {
tip1Null.setBorder(compound1);
} else {
tip1Null.setBorder(compound);
}
if (model.isPressed()) {
tip1Null.setBorder(compound2);
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tip1Null, BorderLayout.CENTER);
frame.setLocation(150, 150);
frame.setPreferredSize(new Dimension(310, 75));
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TextAreaInButton taib = new TextAreaInButton();
}
});
}
}
class OldRoundedBorderLine extends AbstractBorder {
private final static int MARGIN = 5;
private static final long serialVersionUID = 1L;
private Color color;
OldRoundedBorderLine(Color clr) {
color = clr;
}
public void setColor(Color clr) {
color = clr;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(color);
g.drawRoundRect(x, y, width, height, MARGIN, MARGIN);
}
#Override
public Insets getBorderInsets(Component c) {
return new Insets(MARGIN, MARGIN, MARGIN, MARGIN);
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = MARGIN;
insets.top = MARGIN;
insets.right = MARGIN;
insets.bottom = MARGIN;
return insets;
}
}
class ModifButtonUI extends MetalButtonUI {
private static final ModifButtonUI buttonUI = new ModifButtonUI();
ModifButtonUI() {
}
public static ComponentUI createUI(JComponent c) {
return new ModifButtonUI();
}
#Override
public void paint(Graphics g, JComponent c) {
final Color color1 = new Color(230, 255, 255, 0);
final Color color2 = new Color(255, 230, 255, 64);
final Color alphaColor = new Color(200, 200, 230, 64);
final Color color3 = new Color(
alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 0);
final Color color4 = new Color(
alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 64);
super.paint(g, c);
Graphics2D g2D = (Graphics2D) g;
GradientPaint gradient1 = new GradientPaint(
0.0F, (float) c.getHeight() / (float) 2, color1, 0.0F, 0.0F, color2);
Rectangle rec1 = new Rectangle(0, 0, c.getWidth(), c.getHeight() / 2);
g2D.setPaint(gradient1);
g2D.fill(rec1);
GradientPaint gradient2 = new GradientPaint(
0.0F, (float) c.getHeight() / (float) 2, color3, 0.0F, c.getHeight(), color4);
Rectangle rec2 = new Rectangle(0, c.getHeight() / 2, c.getWidth(), c.getHeight());
g2D.setPaint(gradient2);
g2D.fill(rec2);
}
#Override
public void paintButtonPressed(Graphics g, AbstractButton b) {
paintText(g, b, b.getBounds(), b.getText());
g.setColor(Color.red.brighter());
g.fillRect(0, 0, b.getSize().width, b.getSize().height);
}
public void paintBorder(Graphics g) {
}
#Override
protected void paintFocus(Graphics g, AbstractButton b,
Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
}
}
You will have to extend JButton class not AbstractButton. Try the following things and you will get idea.
The first move is to subclass JButton.
Then, in your subclass, start by redefining the paintComponent(Graphics) method. If you want any changes.
Then, override paintBorder(Graphics) to give it a shape of hexagon.
I know this question has been answered, but you might want to look at using the built-in methods, and using images to draw your button in different states.
Here is a bit of code I used to generate a custom button.
BufferedImage startButton = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup.png"));
BufferedImage startButtonHover = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup_hover.png"));
BufferedImage startButtonActive = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup_active.png"));
JButton startBackupButton = new JButton(new ImageIcon(startButton));
startBackupButton.setRolloverIcon(new ImageIcon(startButtonHover));
startBackupButton.setPressedIcon(new ImageIcon(startButtonActive));
startBackupButton.setBorder(BorderFactory.createEmptyBorder());
startBackupButton.setContentAreaFilled(false);
startBackupButton.setFocusable(false);
You can then add an action listener to it as normal.
try a Jlabel and use an image for any shape!!
JLabel lbl = new JLabel("");
lbl.setIcon(new ImageIcon("shape.png"));
lbl.setBounds(548, 11, 66, 20);
contentPane.add(lbl);
lbl.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
System.exit(0);
}
});

Categories