Related
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:
When I run the program I'm able to select one smiley to be active, and I can change this from the JRadio button choices to different selections and it'd work cause I'm testing it with changing colors.
My issue is that I'm only able to change active panels by descending order. I can't go back to a previous one. When I run the program and select smiley_a, I'm able to change its colors, but when I select smiley_b, smiley_a continues the be the one that's changing. Once I get to A, I can't go back to or C or D, and if I start with B, I can't go back to C or D, only to A, and so forth. I'm able to click, but it doesn't update which frame is active.
#Override
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
if (action.equals("Change Colors")) {
update();
selector();
}
if (action.equals("Face +")) {
System.out.println("work");
//frameAsmiley.setSize(20);
//System.out.println("work");
//frameAsmiley.repaint();
}
if (action.equals("Face -")) {
frameAsmiley.setSize(20);
frameAsmiley.repaint();
}
}
#Override
public void itemStateChanged(ItemEvent e) {
Object source = e.getSource();
if (source == a) {
smiley_a = true;
update();
}if (source == b) {
smiley_b = true;
update();
}if (source== c) {
smiley_c = true;
update();
}if (source == d) {
smiley_d = true;
update();
}
if (source == glasses_on) {
cube_a.repaint();
}if (source == glasses_off) {
cube_a.repaint();
}if (source== c) {
smiley_c = true;
update();
}if (source == d) {
smiley_d = true;
update();
}
if(e.getStateChange() == ItemEvent.SELECTED){
if (emotions.getSelectedItem().equals("Smile!")) {
}
if (emotions.getSelectedItem().equals("Angry!")) {
}if (emotions.getSelectedItem().equals("Sad!")) {
}if (emotions.getSelectedItem().equals("Shock!")) {
}if (emotions.getSelectedItem().equals("Wink!")) {
}
}
}
class OutputScreen extends JPanel {
OutputScreen() {
setPreferredSize(new Dimension(600, 400));
}
}
This is my main code
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.HashMap;
import java.util.Map;
import static javax.swing.BorderFactory.createCompoundBorder;
public class SmileyTwo extends JFrame implements ActionListener, ItemListener {
private final int framewidth = 1200, frameheight = 1000;
private final int cubes_width = framewidth / 4 - 10, cubes_height = frameheight / 4 - 10;
JPanel mainpanel, cube_1, cube_2, cube_3, cube_4, control_panel_u, control_panel_d, selectsmiley = new JPanel();
JButton color;
JComboBox emotions;
Smiley frameAsmiley, frameBsmiley, frameCsmiley, frameDsmiley, currentpanel;
ButtonGroup eyesopenorclose, glasses_toggle, glasses_state, smileyselector;
JRadioButton eyes_open, eyes_closed, glasses_on, glasses_off, glasses_dark, glasses_clear, a, b, c, d;
JRadioButton left_eye_closed, right_eye_closed = new JRadioButton();
JLabel emotes, smiley, eyestate, glass_state;
Container screen;
boolean smiley_a = false, smiley_b = false, smiley_c = false, smiley_d = false;
int smiley_int_width = 200, smiley_int_height = 200, smiley_face_x_int = 200, smiley_face_y_int = 100;
int smiley_eyes_w = smiley_int_width / 4, smiley_eyes_h = smiley_int_width / 4;
int smileyCtrPoint_x = smiley_face_x_int + smiley_int_width / 2, smileyCtrPoint_y = smiley_face_y_int + smiley_int_height / 2;
int left_eye_x = smileyCtrPoint_x - 80, left_eye_y = smileyCtrPoint_y - 50;
int right_eye_x = smileyCtrPoint_x + 80, right_eye_y = smileyCtrPoint_y - 50;
public OutputScreen cube_a, cube_b, cube_c, cube_d;
public static void main(String[] args) {
int face = 100;
SmileyTwo frame = new SmileyTwo();
frame.setSize(new Dimension(frame.framewidth, frame.frameheight));
frame.setTitle("SMILEY");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.createGui();
frame.repaint();
frame.setVisible(true);
}
public void controlBox() {
JPanel glasses = new JPanel();
JPanel emojis = new JPanel();
JPanel expressions = new JPanel();
JPanel eyes_choices = new JPanel();
JPanel eyepanel = new JPanel();
JPanel glasspanel = new JPanel();
JPanel selectsmiley = new JPanel();
control_panel_u = new JPanel();
control_panel_d = new JPanel();
smileyselector = new ButtonGroup();
eyes_open = new JRadioButton();
eyes_closed = new JRadioButton();
glasses_on = new JRadioButton();
glasses_off = new JRadioButton();
glasses_dark = new JRadioButton();
glasses_clear = new JRadioButton();
left_eye_closed = new JRadioButton();
right_eye_closed = new JRadioButton();
//
JLabel smiley = new JLabel();
smiley.setText("TOGGLE SMILEY BOX");
a = new JRadioButton();
b = new JRadioButton();
c = new JRadioButton();
d = new JRadioButton();
a.addItemListener(this);
b.addItemListener(this);
c.addItemListener(this);
d.addItemListener(this);
JPanel smileyoptions = new JPanel();
JButton color = new JButton("Change Colors");
color.addActionListener(this);
emotes = new JLabel();
emotes.setText("SELECT EMOJI");
emotes.setHorizontalAlignment(JLabel.CENTER);
emotions = new JComboBox();
emotions.addItem("Smile!");
emotions.addItem("Wink!");
emotions.addItem("Shock!");
emotions.addItem("Angry!");
emotions.addItem("Sad!");
emotions.setSize(30, 10);
emotions.addItemListener(this);
emojis.add(emotions);
emojis.add(color);
expressions.add(emotes);
expressions.add(emojis);
expressions.setLayout(new GridLayout(2, 1));
//
eyestate = new JLabel("EYE OPTIONS");
ButtonGroup eyesopenorclose = new ButtonGroup();
eyes_choices.setLayout(new GridLayout(2, 2));
eyes_choices.add(eyes_open);
eyes_choices.add(left_eye_closed);
eyes_choices.add(eyes_closed);
eyes_choices.add(right_eye_closed);
eyepanel.add(eyestate);
eyepanel.add(eyes_choices);
eyes_open.setText("open both eyes");
eyes_closed.setText("close both eyes");
left_eye_closed.setText("close right eye");
right_eye_closed.setText("close left eye");
eyesopenorclose.add(eyes_open);
eyesopenorclose.add(eyes_closed);
eyesopenorclose.add(left_eye_closed);
eyesopenorclose.add(right_eye_closed);
eyepanel.add(eyestate);
eyestate.setHorizontalAlignment(JLabel.CENTER);
eyepanel.add(eyes_choices);
eyepanel.setLayout(new GridLayout(2, 1));
//
glass_state = new JLabel("GLASSES OPTIONS");
ButtonGroup glasses_toggle = new ButtonGroup();
ButtonGroup glasses_state = new ButtonGroup();
glasses_on.setText("glasses on");
glasses_off.setText("glasses off");
glasses_dark.setText("dark shades");
glasses_clear.setText("clear glasses");
glasses_on.addItemListener(this);
glasses_off.addItemListener(this);
glasses_dark.addItemListener(this);
glasses_clear.addItemListener(this);
glasses_toggle.add(glasses_off);
glasses_toggle.add(glasses_on);
glasses_state.add(glasses_dark);
glasses_state.add(glasses_clear);
GridLayout forglass = new GridLayout(2, 2);
glasses.setLayout(new GridLayout(2, 2));
glasses.setBackground(Color.WHITE);
glasses.add(glasses_on);
glasses.add(glasses_dark);
glasses.add(glasses_off);
glasses.add(glasses_clear);
glasspanel.add(glass_state);
glasspanel.add(glasses);
glass_state.setHorizontalAlignment(JLabel.CENTER);
glasspanel.setLayout(new GridLayout(2, 1));
//
smileyselector.add(a);
smileyselector.add(b);
smileyselector.add(c);
smileyselector.add(d);
a.setText("Smiley A");
b.setText("Smiley B");
c.setText("Smiley C");
d.setText("Smiley D");
smileyoptions.add(a);
smileyoptions.add(b);
smileyoptions.add(c);
smileyoptions.add(d);
selectsmiley.add(smiley);
selectsmiley.add(smileyoptions);
smiley.setHorizontalAlignment(JLabel.CENTER);
selectsmiley.setLayout(new GridLayout(2, 1));
//
control_panel_u.setLayout(new FlowLayout());
control_panel_u.add(selectsmiley);
control_panel_u.add(expressions);
control_panel_u.add(glasspanel);
control_panel_u.add(eyepanel);
control_panel_u.setBorder(BorderFactory.createLineBorder(Color.BLACK));
glasses.setBorder(BorderFactory.createLineBorder(Color.BLACK));
eyes_choices.setBorder(BorderFactory.createLineBorder(Color.BLACK));
emojis.setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
public void createGui() {
controlBox();
selector();
Smiley frameAsmiley = new Smiley(150, 100, 400, 400, "shock");
Smiley frameBsmiley = new Smiley(150, 100, 400, 400, "frown");
Smiley frameCsmiley = new Smiley(150, 100, 400, 400,"smile");
Smiley frameDsmiley = new Smiley(150, 100, 400, 400, "wink");
currentpanel = frameAsmiley;
screen = getContentPane();
mainpanel = new JPanel();
JPanel cubepanels = new JPanel();
cube_1 = new JPanel();
cube_2 = new JPanel();
cube_3 = new JPanel();
cube_4 = new JPanel();
cube_a = new OutputScreen();
cube_b = new OutputScreen();
cube_c = new OutputScreen();
cube_d = new OutputScreen();
cube_1.setSize(cubes_width, cubes_height);
cube_2.setSize(cubes_width, cubes_height);
cube_3.setSize(cubes_width, cubes_height);
cube_4.setSize(cubes_width, cubes_height);
cube_a.setSize(cubes_width - 5, cubes_height - 50);
cube_b.setSize(cubes_width - 5, cubes_height);
cube_c.setSize(cubes_width - 5, cubes_height);
cube_d.setSize(cubes_width - 5, cubes_height);
mainpanel.setBackground(Color.WHITE);
cube_1.setBorder(BorderFactory.createLineBorder(Color.BLACK));
cube_2.setBorder(BorderFactory.createLineBorder(Color.BLACK));
cube_3.setBorder(BorderFactory.createLineBorder(Color.BLACK));
cube_4.setBorder(BorderFactory.createLineBorder(Color.BLACK));
cubepanels.add(cube_1, BorderLayout.NORTH);
cubepanels.add(cube_2, BorderLayout.SOUTH);
cubepanels.add(cube_3, BorderLayout.EAST);
cubepanels.add(cube_4, BorderLayout.WEST);
cubepanels.setLayout(new GridLayout(2, 2));
mainpanel.add(cubepanels, BorderLayout.NORTH);
mainpanel.add(control_panel_u, BorderLayout.SOUTH);
cube_a.setBackground(Color.WHITE);
frameAsmiley.setPreferredSize(new Dimension(600, 500));
frameBsmiley.setPreferredSize(new Dimension(600, 500));
frameCsmiley.setPreferredSize(new Dimension(600, 500));
frameDsmiley.setPreferredSize(new Dimension(600, 500));
//
cube_a.add(frameAsmiley, BorderLayout.CENTER);
cube_1.add(cube_a, BorderLayout.CENTER);
cube_1.setLayout(new BoxLayout(cube_1, BoxLayout.Y_AXIS));
frameAsmiley.setBackground(Color.WHITE);
//
cube_b.add(frameBsmiley, BorderLayout.CENTER);
cube_2.add(cube_b, BorderLayout.CENTER);
cube_2.setLayout(new BoxLayout(cube_2, BoxLayout.Y_AXIS));
frameBsmiley.setBackground(Color.WHITE);
//
cube_c.add(frameCsmiley, BorderLayout.CENTER);
cube_3.add(cube_c, BorderLayout.CENTER);
cube_3.setLayout(new BoxLayout(cube_3, BoxLayout.Y_AXIS));
frameCsmiley.setBackground(Color.WHITE);
//
cube_d.add(frameDsmiley, BorderLayout.CENTER);
cube_4.add(cube_d, BorderLayout.CENTER);
cube_4.setLayout(new BoxLayout(cube_4, BoxLayout.Y_AXIS));
frameDsmiley.setBackground(Color.WHITE);
//
screen.add(mainpanel);
}
public void selector() {
if (smiley_a == true) {
smiley_b = false;
smiley_c = false;
smiley_d = false;
cube_a.repaint();
} else if (smiley_b == true) {
smiley_a = false;
smiley_c = false;
smiley_d = false;
cube_b.repaint();
} else if (smiley_c == true) {
smiley_a = false;
smiley_b = false;
smiley_d = false;
cube_c.repaint();
} else if (smiley_d == true) {
smiley_a = false;
smiley_b = false;
smiley_c = false;
cube_d.repaint();
}
}
public void update() {
if (smiley_a == true) {
smiley_b = false;
smiley_c = false;
smiley_d = false;
} else if (smiley_b == true) {
smiley_a = false;
smiley_c = false;
smiley_d = false;
} else if (smiley_c == true) {
smiley_a = false;
smiley_b = false;
smiley_d = false;
} else if (smiley_d == true) {
smiley_a = false;
smiley_b = false;
smiley_c = false;
}
}
#Override
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
if (action.equals("Change Colors")) {
update();
selector();
}
if (action.equals("Face +")) {
System.out.println("work");
frameAsmiley.setSize(20);
//System.out.println("work");
frameAsmiley.repaint();
}
if (action.equals("Face -")) {
frameAsmiley.setSize(20);
frameAsmiley.repaint();
}
}
#Override
public void itemStateChanged(ItemEvent e) {
Object source = e.getSource();
if (source == a) {
smiley_a = true;
update();
}if (source == b) {
smiley_b = true;
update();
}if (source== c) {
smiley_c = true;
update();
}if (source == d) {
smiley_d = true;
update();
}
if (source == glasses_on) {
cube_a.repaint();
}if (source == glasses_off) {
cube_a.repaint();
}if (source== c) {
smiley_c = true;
update();
}if (source == d) {
smiley_d = true;
update();
}
if(e.getStateChange() == ItemEvent.SELECTED){
if (emotions.getSelectedItem().equals("Smile!")) {
}
if (emotions.getSelectedItem().equals("Angry!")) {
}if (emotions.getSelectedItem().equals("Sad!")) {
}if (emotions.getSelectedItem().equals("Shock!")) {
}if (emotions.getSelectedItem().equals("Wink!")) {
}
}
}
class OutputScreen extends JPanel {
OutputScreen() {
setPreferredSize(new Dimension(600, 400));
}
}
}
this is the custom class
import javax.swing.*;
import java.awt.*;
import java.lang.Object.*;
import java.util.HashSet;
public class Smiley extends JPanel {
public Smiley(int x, int y, int width, int height, String mood) {
this.x = x - 20;
this.y = y - 70;
this.width = width - 100;
this.height = height - 100;
this.mood = mood;
}
public Color randomColor() {
int R = (int) (Math.random() * 255);
int G = (int) (Math.random() * 255);
int B = (int) (Math.random() * 255);
int A = (int) (Math.random() * 3);
Color randomColor = new Color(A, R, G, B);
return randomColor;
}
public int x, y, width, height;
String mood;
HashSet specs;
public int geteyeheight() {
int eyeHeight = height / 5;
return eyeHeight;
}
public String currentlook() {
String currentlook = mood;
return currentlook;
}
public int geteyewidth() {
int eyeWidth = width / 5;
return eyeWidth;
}
public int getlefteyeX() {
int centerPointX = (x + width) / 2;
int leftEyeX = centerPointX - 40;
return leftEyeX;
}
public int getlefteyeY() {
int centerPointY = (y + height) / 2;
int leftEyeY = centerPointY - 50;
return leftEyeY;
}
public int getrighteyeX() {
int centerPointX = (x + width) / 2;
int rightEyeX = centerPointX + 110;
return rightEyeX;
}
public int getrighteyeY() {
int centerPointY = (y + height) / 2;
int rightEyeY = centerPointY - 50;
return rightEyeY;
}
public int getsmileY() {
int centerPointY = (y + height) / 2;
int smileYint = centerPointY + 20;
return smileYint;
}
public int getsmileX() {
int centerPointX = (x + width) / 2;
int smileXint = centerPointX - 10;
return smileXint;
}
public int getsmilewidth() {
int smilewidth = width / 2;
return smilewidth;
}
public int getsmileheight() {
int smileheight = height / 3;
return smileheight;
}
public void setSize(int size){
height+=size;
width+=size;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(randomColor());
g2d.fillOval(x, y, width, height);
g2d.setColor(randomColor());
if (currentlook().equals("smile")) {
DrawSmile(g);
}
else if(currentlook().equals("frown")){
DrawFrown(g);
}else if(currentlook().equals("angry")){
DrawAngry(g);
}else if(currentlook().equals("wink")){
DrawWink(g);
}else if(currentlook().equals("shock")){
DrawShock(g);
}
}
//INDIVIDUAL FACIAL FEATURES
public void rightEye(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.fillOval(getrighteyeX(), getrighteyeY(), geteyewidth(), geteyeheight());
}
public void leftEye(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.fillOval(getlefteyeX(), getlefteyeY(), geteyewidth(), geteyeheight());
}
public void leftEyeAngry(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(getlefteyeX() + 20, getlefteyeY(), getlefteyeX() + 50, getrighteyeY() + 30);
g2d.fillOval(getlefteyeX() + 15, getlefteyeY() + 25, 30, 30);
}
public void rightEyeAngry(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(getrighteyeX() + 30, getrighteyeY(), getrighteyeX(), getrighteyeY() + 30);
g2d.fillOval(getlefteyeX() + 155, getlefteyeY() + 25, 30, 30);
}
public void CloseLeftEye(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(5));
g2d.drawArc(getlefteyeX(), getlefteyeY(), geteyewidth(), geteyeheight(), 0, -180);
}
public void CloseRightEye(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(5));
g2d.drawArc(getrighteyeX(), getrighteyeY(), geteyewidth(), geteyeheight(), 0, -180);
}
public void lipSmile(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(10));
g2d.drawArc(getsmileX(), getsmileY(), getsmilewidth(), getsmileheight(), 0, -180);
}
public void lipFrown(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(10));
g2d.drawArc(getsmileX(), getsmileY() + 30, getsmilewidth(), getsmileheight(), 0, +180);
}
public void winkEye(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawArc(getrighteyeX() - 60, getlefteyeY(), 150, 250, 90, 45);
g2d.drawArc(getrighteyeX() - 90, getlefteyeY() + 30, 150, 200, 60, 45);
}
public void narrowEye(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.fillOval(getlefteyeX() + 20, getlefteyeY(), geteyewidth() - 20, geteyeheight() + 30);
}
public void smallerSmile(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.fillArc(getsmileX() + 30, getsmileY() + 15, getsmilewidth() / 2, getsmileheight(), 0, -180);
}
//EXPRESSIONS
public void DrawSmile(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
rightEye(g);
leftEye(g);
lipSmile(g);
}
public void DrawFrown(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
rightEye(g);
leftEye(g);
lipFrown(g);
}
public void DrawAngry(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(15));
leftEyeAngry(g);
rightEyeAngry(g);
lipFrown(g);
}
public void DrawWink(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(15));
winkEye(g);
narrowEye(g);
smallerSmile(g);
}
public void Glasses(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
g2d.drawOval(getlefteyeX() - 20, getlefteyeY() - 20, geteyewidth() + 40, geteyeheight() + 40);
g2d.drawOval(getrighteyeX() - 20, getrighteyeY() - 20, geteyewidth() + 40, geteyeheight() + 40);
g2d.drawArc(getlefteyeX() + 80, getlefteyeY() + 20, 50, 20, 0, 180);
}
public void glassesDark(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
g2d.fillOval(getlefteyeX() - 20, getlefteyeY() - 20, geteyewidth() + 40, geteyeheight() + 40);
g2d.fillOval(getrighteyeX() - 20, getrighteyeY() - 20, geteyewidth() + 40, geteyeheight() + 40);
g2d.drawArc(getlefteyeX() + 70, getlefteyeY() + 20, 70, 20, 0, 180);
}
public void DrawShock(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(15));
g2d.drawLine(getlefteyeX() - 10, getlefteyeY(), getlefteyeX() + 40, getrighteyeY() - 20);
g2d.drawLine(170 + getlefteyeX() + 40, getlefteyeY(), 170 + getlefteyeX() - 10, getrighteyeY() - 20);
g2d.fillOval(getrighteyeX() - 20, getrighteyeY(), geteyewidth() + 20, geteyeheight() + 20);
g2d.fillOval(getlefteyeX(), getlefteyeY(), geteyewidth() + 20, geteyeheight() + 20);
g2d.fillOval(getsmileX() + 40, getsmileY() + 25, geteyewidth() + 20, geteyeheight() + 30);
}
}
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);
}
}
I am designing a grid-based game which uses the Java swing framework. I have a JFrame with two JPanel within it, but one of them appears in two places. Here is a screenshot:
The panel that says "Turn 1" and has the buttons is only supposed to appear to the right of the grid, but it strangely also appears in the upper-left hand corner. Here is my code:
public class ArenaPanel extends JPanel {
private final GridPanel gp;
private final InfoPanel ip;
private GameManager gm;
private int w, h;
private int cw, ch;
private double tw, th;
private Point p2;
private Point p1;
private int shotWidth;
private Color shotColor;
public ArenaPanel(int w, int h) {
Images.load();
setLayout(new GridBagLayout());
this.w = w;
this.h = h;
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.weightx = 0;
c.weighty = 1;
gp = new GridPanel();
gp.setPreferredSize(new Dimension(700, 700));
this.add(gp, c);
c.gridx = 1;
c.weightx = c.weighty = 0;
ip = new InfoPanel();
add(ip, c);
}
public void setGameManager(GameManager g) {
gm = g;
}
public void start() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
gm.start();
}
});
t.start();
}
public void step() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
gm.doTurn();
}
});
t.start();
}
public void paint(Graphics g) {
g.setColor(Color.black);
int val = Math.min(getWidth() - 200, getHeight());
gp.setPreferredSize(new Dimension(val, val));
gp.revalidate();
g.fillRect(0, 0, getWidth(), getHeight());
paintComponents(g);
}
private class GridPanel extends JPanel {
public void paint(Graphics g) {
cw = getWidth();
ch = getHeight();
g.setColor(Color.gray);
g.fillRect(0, 0, cw, ch);
tw = (double) cw / w;
th = (double) ch / h;
g.setColor(Color.black);
for (int i = 0; i < w; i++) {
g.drawLine((int) (i * tw), 0, (int) (i * tw), ch);
}
for (int i = 0; i < h; i++) {
g.drawLine(0, (int) (i * th), cw, (int) (i * th));
}
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
Robot t = gm.getGrid()[i][j];
if (t != null) {
Point p = expand(i, j);
g.drawImage(t.getImage(), p.x + t.getOffsetX(),
p.y + t.getOffsetY(), (int) tw, (int) th, null);
}
}
}
if (p1 != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(shotColor);
g2.setStroke(new BasicStroke(shotWidth));
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
p1 = null;
p2 = null;
}
}
}
private class InfoPanel extends JPanel implements ActionListener {
private JButton start, stop, step;
private JLabel turns;
private int numTurns = 0;
private GridBagConstraints gbc;
private ArrayList<TeamPanel> tpanels;
public InfoPanel() {
JPanel buttons = new JPanel();
setLayout(new GridBagLayout());
buttons.setLayout(new GridBagLayout());
gbc = new GridBagConstraints();
start = new JButton("Start");
gbc.gridy = 0;
gbc.gridx = 1;
turns = new JLabel("Turn 1");
buttons.add(turns, gbc);
start.addActionListener(this);
gbc.gridy = 1;
gbc.gridx = 0;
buttons.add(start, gbc);
step = new JButton("Step");
step.addActionListener(this);
gbc.gridx++;
buttons.add(step, gbc);
stop = new JButton("Stop");
stop.addActionListener(this);
gbc.gridx++;
buttons.add(stop, gbc);
gbc.gridx = 0;
gbc.gridy = 0;
add(buttons, gbc);
tpanels = new ArrayList<TeamPanel>();
}
#Override
public void actionPerformed(ActionEvent actionEvent) {
if (actionEvent.getSource() == start) {
start();
} else if (actionEvent.getSource() == stop) {
gm.stop();
} else if (actionEvent.getSource() == step) {
step();
}
}
public void incrementTurn() {
numTurns++;
turns.setText("Turn " + numTurns);
}
public void initializeTeams(Map<String, TeamInfo> m) {
Set<String> k = m.keySet();
for (TeamPanel tp : tpanels) {
this.remove(tp);
}
tpanels.clear();
gbc.gridy = 1;
for (String s : k) {
TeamPanel tp = new TeamPanel(m.get(s));
add(tp, gbc);
gbc.gridy++;
tpanels.add(tp);
}
this.revalidate();
}
}
private class TeamPanel extends JPanel {
private Color col;
private int score;
private JLabel scoreLabel;
private TeamInfo inf;
public TeamPanel(TeamInfo inf) {
this.inf = inf;
col = getColor(inf.c);
super.setLayout(new FlowLayout());
BufferedImage ico = new BufferedImage(20, 20, BufferedImage.TYPE_3BYTE_BGR);
Graphics g = ico.getGraphics();
g.setColor(col);
g.fillRect(0, 0, 20, 20);
add(new JLabel(new ImageIcon(ico)));
this.add(new JLabel(inf.team));
scoreLabel = new JLabel("" + inf.score);
add(scoreLabel);
}
public void paint(Graphics g) {
//g.setColor(col);
//g.fillRect(-5, 0, 10, 10);
scoreLabel.setText("Score: " + inf.score);
this.paintComponents(g);
}
}
public void initializeTeams(Map<String, TeamInfo> m) {
ip.initializeTeams(m);
}
}
I have looked on google and StackOverflow for a similar problem, but I was unable to find one. Any help would be greatly appreciated.
Thanks!
Don't override the paint(...) method
Override the JPanel's paintComponent(...) method instead.
Don't forget to call the super paintComponent(...) method within your override.
And never call the super's paintComponents(...) (note the trailing "s") from within either the paint or paintComponent method. This smells like it could be the cause of your problem.
I could add a rounded corner border to my JDialog as in How to create a rounded title border in Java Swing. But it is still one color. I want to make the border looks like 3D.
Here is how I tried.
Graphics2D g2d = (Graphics2D) g;
Color c1 = getBackground();
Color c2 = color1.darker();
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(
0, 0, c1,
0, h, c2);
g2d.setPaint(gp);
g2d.fill3DRect(0,0, w, h,true);
Then, no 3D look, but the border has been widen more with its border color.
How can I achieve this?
Any sample code or links will be highly appreciated.
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;
public class ThreeDimensionalBorder extends AbstractBorder {
private static final long serialVersionUID = 1L;
private Color color;
private int thickness = 8;
private int radii = 8;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
RenderingHints hints;
int shadowPad = 3;
ThreeDimensionalBorder(Color color) {
this(color, 128, 8);
}
ThreeDimensionalBorder(Color color, int transparency, int shadowWidth) {
this.color = color;
shadowPad = shadowWidth;
stroke = new BasicStroke(thickness);
strokePad = thickness/2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + strokePad + shadowPad;
int rightPad = pad + strokePad + shadowPad;
insets = new Insets(pad,pad,bottomPad+shadowPad,rightPad);
}
#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-shadowPad;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0+strokePad,
0+strokePad,
width-thickness-shadowPad,
bottomLineY,
radii,
radii
);
Area area = new Area(bubble);
g2.setRenderingHints(hints);
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
Area shadowArea = new Area(new Rectangle(0,0,width,height));
shadowArea.subtract(area);
g.setClip(shadowArea);
Color shadow = new Color(color.getRed(),color.getGreen(),color.getBlue(),128);
g2.setColor(shadow);
g2.translate(shadowPad,shadowPad);
g2.draw(area);
AffineTransform at = g2.getTransform();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel p = new JPanel();
String t = "The quick brown fox jumps over the lazy dog!";
JLabel l1 = new JLabel(t);
l1.setBorder(new ThreeDimensionalBorder(Color.MAGENTA.darker(),128,4));
p.add(l1);
JLabel l2 = new JLabel(t);
l2.setBorder(new ThreeDimensionalBorder(Color.BLACK,200,5));
p.add(l2);
JLabel l3 = new JLabel(t);
l3.setBorder(new ThreeDimensionalBorder(Color.BLUE,40,6));
p.add(l3);
JOptionPane.showMessageDialog(null, p);
}
});
}
}
Would this suffice??
It's far from perfect, but the basic idea works...
public class MyRoundedBorder implements Border {
protected static final Insets DEFAULT_INSETS = new Insets(4, 4, 4, 4);
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.setColor(Color.WHITE);
Shape corner = new RoundedShape(width - 8, height - 8);
g2d.translate(x + 2, y + 2);
g2d.draw(corner);
g2d.transform(AffineTransform.getRotateInstance(Math.toRadians(180), (width - 8) / 2, (height - 8) / 2));
g2d.setColor(Color.LIGHT_GRAY);
g2d.draw(corner);
g2d.dispose();
}
#Override
public Insets getBorderInsets(Component c) {
return DEFAULT_INSETS;
}
#Override
public boolean isBorderOpaque() {
return true;
}
public class RoundedShape extends Path2D.Float {
public RoundedShape(int width, int height) {
moveTo(0, height - 20);
append(new Arc2D.Float(0, height - 20, 20, 20, 180, 45, Arc2D.CHORD), false);
lineTo(0, 20);
curveTo(0, 0, 0, 0, 20, 0);
lineTo(width - 10, 0);
append(new Arc2D.Float(width - 20, 0, 20, 20, 90, -45, Arc2D.CHORD), false);
}
}
}