Issue with BasicScrollBarUI and LAF - java

I'm creating a program which has a Nimbus laf, in there i'm using a JScrollPane with a BasicScrollBarUI.
sp = new JScrollPane(lista);
sp.getVerticalScrollBar().setUI(new CustomScrollBarUI());
The problem is that i need the Nimbus laf for some custom buttons, and the BasicScrollBarUI for the scroll bar which i can't make with Nimbus, if i use both my scrollbar gets out of the border.
Just like that
The class i'm using for ScrollBarUI is:
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color color = ColorPri;
JScrollBar sb = (JScrollBar) c;
scrollBarWidth = 9;
if (!sb.isEnabled()) {
return;
} else if (isDragging) {
color = ColorSec;
}
g2.setColor(color);
g2.fillRect(r.x, r.y, r.width, r.height);
g2.setColor(color);
g2.fillRect(r.x, r.y, r.width, r.height);
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color color = null;
JScrollBar sb = (JScrollBar) c;
if (!sb.isEnabled()) {
return;
} else if (isDragging) {
color = ColorPri;
} else if (isThumbRollover()) {
color = ColorSec;
} else {
color = ColorSec;
}
g2.setPaint(color);
g2.fillRoundRect(1, r.y, 7, r.height, 5, 5);
g2.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
scrollbar.repaint();
}
}
The colors are received from the main class
Is there any way to fix it without having to delete the laf or the basicUI?
Thanks in advance

Related

Is it possible to write paint on screen program in java/swing?

I'm writing paint on screen program using Java Swing. It working on ubuntu linux. But windows shows black screen instead of transparent panel. I included similar example code. What is wrong in my code?
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class Example {
public static final Color COLOR_TRANSPARENT = new Color(0,0,0,0);
public Example() {
Canvas drawArea = new Canvas();
drawArea.setBackground(COLOR_TRANSPARENT);
drawArea.setOpaque(true);
JWindow drawingFrame = new JWindow();
drawingFrame.setBackground(COLOR_TRANSPARENT);
drawingFrame.setContentPane(drawArea);
drawingFrame.pack();
drawingFrame.setSize(640, 460);
drawingFrame.setVisible(true);
drawingFrame.setLocationRelativeTo(null);
drawingFrame.setAlwaysOnTop(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(Example::new);
}
class Canvas extends JPanel{
private Image image;
private Graphics2D g2;
public Canvas() {
super();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
g2.setPaint(Color.RED);
g2.fillOval(x-10, y-10, 20, 20);
repaint(x-10, y-10, 20, 20);
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image == null){
image = createImage(getWidth(), getHeight());
g2 = (Graphics2D) image.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setBackground(COLOR_TRANSPARENT);
clear();
}
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, 0,0, null);
}
public void clear(){
System.out.println("clearing canvas ");
g2.setComposite(AlphaComposite.Clear);
g2.setBackground(COLOR_TRANSPARENT);
g2.setColor(COLOR_TRANSPARENT);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.clearRect(0, 0, getWidth(), getHeight());
g2.setPaint(Color.RED);
g2.setComposite(AlphaComposite.SrcOver);
repaint();
}
}
}
Here is screenshot what I wanted.
Example code updated. Now code should work without any other additional code.
For windows I made a couple of changes:
image = createImage(getWidth(), getHeight());
image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
I used a BufferedImage to you can set the alpha values of the image to be transparent.
//public static final Color COLOR_TRANSPARENT = new Color(0,0,0,0);
public static final Color COLOR_TRANSPARENT = new Color(0,0,0,1);
I made the alpha value non-zero, because a value of zero means the Java application won't receive the MouseEvent because it is passed to the application under the window.

Attaching images to JLabel's border

I want to write a custom subclass of JLabel that would have two images attached to the border, that can be moved by moving the mouse. Real effects like this:
Here's my subclass, how could I add these attached images?
public class Rect extends JLabel{
private int width,height;
public Rect (int width,int height){
this.width = width;
this.height = height;
setText("b1");
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(0, 0, this.width, this.height);
}
public void reDraw(){
this.repaint();
}
public void setWidth(int width) {
this.width = width;
repaint();
}
public void setHeight(int height) {
this.height = height;
repaint();
}
}
To do this there are 4 things you should to do:
Extend an AbstractBorder not a Jlabel, then you can easily add your custom border to any component, not just a jLabel.
Override the paintBorder method so that you can draw your border.
Add an mouse action listeners to keep track of your border images.
And lastly you need a bit of logic to manage your border images.
I found this question interesting so I took a crack at making something as a test. It came out well, and does what you want, but will need a bit of work to get it looking correct. See below for a break down of each point.
Example image before we look at the code:
Extend an AbstractBorder:
public class MyCustomBorder extends AbstractBorder
{
private Color borderColour;
private int borderThickness = 10;
private Point firstSlider = new Point(0, 0);
private Point secondSlider = new Point(0, 0);
private BufferedImage firstSliderImage;
private BufferedImage secondSliderImage;
Boolean draggingFirst = false;
Boolean draggingSecond = false;
//See usage info
public MyCustomBorder(Color colour, int thickness, Point firstSlider, BufferedImage firstSliderImage, Point secondSlider, BufferedImage secondSliderImage)
{
borderColour = colour;
borderThickness = thickness;
this.firstSlider = firstSlider;
this.secondSlider = secondSlider;
this.firstSliderImage = firstSliderImage;
this.secondSliderImage = secondSliderImage;
}
Override the paintBorder method and insets:
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
super.paintBorder(c, g, x, y, width, height);
Graphics2D g2d = null;
if (g instanceof Graphics2D)
{
g2d = (Graphics2D) g;
//Draw border fill (currently hard coded to white, but can be changed)
g2d.setColor(Color.white);
//Top
g2d.fill(new Rectangle2D.Double(0, 0, width, borderThickness));
//Left
g2d.fill(new Rectangle2D.Double(0, 0, borderThickness, height));
//Bottom
g2d.fill(new Rectangle2D.Double(0, height-borderThickness, width, borderThickness));
//Right
g2d.fill(new Rectangle2D.Double(width-borderThickness, 0, borderThickness, height));
//draw black seperator
g2d.setColor(borderColour);
//Top
g2d.fill(new Rectangle2D.Double(borderThickness, borderThickness, width-(borderThickness*2), 1));
//Left
g2d.fill(new Rectangle2D.Double(borderThickness, borderThickness, 1, height-(borderThickness*2)));
//Bottom
g2d.fill(new Rectangle2D.Double(borderThickness, height-borderThickness-1, width-(borderThickness*2), 1));
//Right
g2d.fill(new Rectangle2D.Double(width-borderThickness-1, borderThickness, 1, height-(borderThickness*2)));
//draw sliders an custom position
g2d.drawImage(scale(secondSliderImage), null, secondSlider.x, secondSlider.y);
g2d.drawImage(scale(firstSliderImage), null, firstSlider.x, firstSlider.y);
}
}
#Override
public Insets getBorderInsets(Component c)
{
return (getBorderInsets(c, new Insets(borderThickness, borderThickness, borderThickness, borderThickness)));
}
#Override
public Insets getBorderInsets(Component c, Insets insets)
{
insets.left = insets.top = insets.right = insets.bottom = borderThickness;
return insets;
}
#Override
public boolean isBorderOpaque()
{
return false;
}
}
Add mouse action listeners:
//listeners for dragging
void addListeners(Component button)
{
button.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
{
public void mouseDragged(java.awt.event.MouseEvent evt)
{
//Only drag if a slider was selected
if (draggingFirst)
{
//update position of silder
firstSlider = snapToEdge(evt.getPoint(), evt.getComponent());
evt.getComponent().repaint();
}
else if (draggingSecond)
{
//update position of silder
secondSlider = snapToEdge(evt.getPoint(), evt.getComponent());
evt.getComponent().repaint();
}
}
});
button.addMouseListener(new java.awt.event.MouseAdapter()
{
//check if a slider was selected
public void mousePressed(java.awt.event.MouseEvent evt)
{
if (isInside(evt.getPoint(), firstSlider))
{
draggingFirst = true;
}
else if (isInside(evt.getPoint(), secondSlider))
{
draggingSecond = true;
}
}
public void mouseReleased(java.awt.event.MouseEvent evt)
{
//cancel selected slider
draggingFirst = false;
draggingSecond = false;
}
});
}
Logic:
//check if a slider was selected
private Boolean isInside(Point clicked, Point toCheck)
{
if (clicked.x > toCheck.x && clicked.x < toCheck.x + borderThickness)
{
if (clicked.y > toCheck.y && clicked.y < toCheck.y + borderThickness)
{
return true;
}
}
return false;
}
//snap a sliders co-ords to as edge
private Point snapToEdge(Point dragged, Component label)
{
//work out how close to each edge
int topEdge = dragged.y;
int leftEdge = dragged.x;
int rightEdge = label.getWidth()- dragged.x;
int bottomEdge = label.getHeight() - dragged.y;
//snap to slider co-ords to closest edge
if (topEdge < leftEdge && topEdge < rightEdge && topEdge < bottomEdge)
{
dragged.y = 0;
}
else if (leftEdge < rightEdge && leftEdge < bottomEdge)
{
dragged.x = 0;
}
else if (rightEdge < bottomEdge)
{
dragged.x = label.getWidth()-borderThickness;
}
else
{
dragged.y = label.getHeight()-borderThickness;
}
return dragged;
}
//scale slider images to fit border size
public BufferedImage scale(BufferedImage image)
{
BufferedImage resizedImage = null;
if (image != null)
{
double border = borderThickness;
resizedImage = new BufferedImage(borderThickness, borderThickness, TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
AffineTransform at = AffineTransform.getScaleInstance(border / (double)image.getWidth(), border / (double)image.getHeight());
g.drawRenderedImage(image, at);
}
return resizedImage;
}
The full code to copy and paste can be found here:
https://github.com/sorifiend/customBorder/blob/master/MyCustomBorder.java
Usage Example:
You can put this code in your form class to add a border to most swing components. In this example I added it to a jLabel called my_jLabel:
//Create border
MyCustomBorder border = new MyCustomBorder(Color.BLACK, 10, new Point(0, 0), img1, new Point(0, 0), img2);
//Add border to component called my_jLabel
my_jLabel.setBorder(border);
//Add action listeners for dragging sliders (very important)
border.addListeners(my_jLabel);

How can I fix this NullPointerException when trying to render on a JPanel with Graphics2D? [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I've been trying to make a shop for my game.
This has been unsuccessful.
I've tried drawComponent, didn't work.
No errors, code executed, but didn't work.
Now i'm trying to do:
private void render() {
Graphics2D g = (Graphics2D) graphics.getGraphics();
/////////////////////
g.drawImage(img, 0, 0, WIDTH, HEIGHT, null);
/////////////////////
g.dispose();
Graphics2D g2d = (Graphics2D) getGraphics();
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
}
Now i get a NullPointerException on g2d.
I've tried everything.
`Exception in thread "game" java.lang.NullPointerException
at com.johnythecarrot.game.Shop$DrawPane.access$2(Shop.java:123)
at com.johnythecarrot.game.Shop.render(Shop.java:154)
at com.johnythecarrot.game.Game.render(Game.java:75)
at com.johnythecarrot.game.Game.run(Game.java:112)
at java.lang.Thread.run(Unknown Source)`
My goals are to be able to have clickable buttons.
It DID work. But i had to restart almost everytime. Because mostly of the time to code wasn't even executed. So i tried to fix it. Now it's all messed up.
This is the code to it.
(DoubleInt is a part of my library it's nothing more than just x and y. )
public class Shop {
public BuildWindow window;
public static JWindow w;
private int WIDTH = 860, HEIGHT = 440;
private BufferedImage graphics = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
public DrawPane drawPane;
public Shop() {
//window = new BuildWindow().setSize(new DoubleInt(100, 100)).at(wi, he).setTitle("Shop").setOpacity(1).setDragable(false).showEmpty(true);
w = new JWindow();
w.setOpacity(1);
w.setSize(WIDTH, HEIGHT);
w.setLocation(800, 800);
w.setVisible(false);
w.setAlwaysOnTop(true);
//graphics = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
}
private void createShop() {
/***Graphics2D g = (Graphics2D) graphics.getGraphics();
g.setColor(Color.blue);
g.drawString("hey", WIDTH-50, HEIGHT-50);
g.fillRect(0, 0, WIDTH, HEIGHT);*/
}
public class DrawPane extends JPanel {
int width = WIDTH;
int height = HEIGHT;
private ArrayList<Shape> buttons;
private Shape btn1 = new Rectangle2D.Double(20, 60, width/2, height-20);
private Shape btnClose = new Rectangle2D.Double(width-25, 5, 20, 20);
Point wCoords;
Point mCoords;
public DrawPane() {
buttons = new ArrayList<>();
buttons.add(btn1);
buttons.add(btnClose);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
for(Shape s : buttons) {
if(s.contains(e.getPoint())) {
System.out.println("Clicked " + s.getBounds());
if(s == btnClose) {
w.dispose();
}
}
}
}
#Override
public void mousePressed(MouseEvent e) {
mCoords = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent arg0) {
mCoords = null;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
wCoords = e.getLocationOnScreen();
w.setLocation(wCoords.x - mCoords.x, wCoords.y - mCoords.y);
}
});
}
void repaintThis() {
repaint();
}
BufferedImage img = loadImageFrom.LoadImageFrom(Shop.class, "bar.png");
Graphics gb;
/**
* super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.red);
//g.fillRect(0, 0, width, 50);
g.drawImage(img, 0, 0, width, 50, null);
g.setColor(Color.WHITE);
g.drawString("SHOP", 15, 30);
g.drawString("X", width-20, 20);
for(Shape b : buttons) {
g2d.draw(b);
}
System.out.println("Built");
gb = g;
*/
private void render() {
Graphics2D g = (Graphics2D) graphics.getGraphics();
/////////////////////
g.drawImage(img, 0, 0, WIDTH, HEIGHT, null);
/////////////////////
g.dispose();
Graphics2D g2d = (Graphics2D) getGraphics();
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
}
public void Build() {
Graphics g = gb;
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.red);
//g.fillRect(0, 0, width, 50);
g.drawImage(img, 0, 0, width, 50, null);
g.setColor(Color.WHITE);
g.drawString("SHOP", 15, 30);
g.drawString("X", width-20, 20);
for(Shape b : buttons) {
g2d.draw(b);
}
System.out.println("Built");
}
}
public void render(Graphics2D g) {
drawPane.render();
}
public void addDrawPane() {
drawPane = new DrawPane();
w.add(drawPane);
}
}
If you need access to more code, just ask me.
You should override the paintComponent method like this:
public class DrawPane extends JPanel {
// all your variables and other things
#Override
paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
// Your code goes here, use the g2d
}
}
then if you need to repaint your component, simply call repaint() on it.

JSlider image behind track

I want to put an image (visualization of an audio) behind the JSlider which represents the audioplayer, the process of playing.
First I tried to overwrite the paint-method of the Slider
public void paintComponent(Graphics g) {
// Draw the previously loaded image to Component
g.drawImage(img, 0, -100, null);
super.paintComponent(g);
}
this worked, but the image is higher than the slider, so my next try was a JLayeredPane, where I put the JSlider above a JLabel with the image. Looks good for the first moment. But I mentioned that I need the image behind the track of the slider, not the whole slider. There is space to the left and right. Can anybody tell me a way how to calculate this space? Or the width and offset of the track to the border of the slider? This should run under Windows and MacOs, so different LookAndFeels, so I think hard coded values will not work.
Example Slider with background image
Thankyou.
My solution for this Problem is now to overwrite the SliderUI. So this is a very special component, so it's nonrelevant that it looks the same on all LookAndFeels.
It supports also jumping directly to mouse position, which is different to BasicSliderUI.
/**
*
* Custom SliderUI for AudioPlayer with audioimage in background
*/
public class AudioSliderUI extends BasicSliderUI {
private BasicStroke stroke = new BasicStroke(1f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND, 0f);
public AudioSliderUI(AudioSlider b) {
super(b);
}
#Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
super.paint(g, c);
}
#Override
protected Dimension getThumbSize() {
return new Dimension(2, 200);
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Stroke old = g2d.getStroke();
g2d.setStroke(stroke);
g2d.setPaint(Color.WHITE);
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2,
trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
} else {
g2d.drawLine(trackRect.x + trackRect.width / 2, trackRect.y,
trackRect.x + trackRect.width / 2, trackRect.y + trackRect.height);
}
g2d.setStroke(old);
Image img = ((AudioSlider)slider).getImage();
g2d.drawImage(img, trackRect.x, trackRect.y, trackRect.width, trackRect.height, slider);
}
#Override
public void paintThumb(Graphics g) {
Rectangle knobBounds = thumbRect;
int w = knobBounds.width;
int h = 100;
int newStarty = knobBounds.height/2- h/2;
g.translate(knobBounds.x, knobBounds.y);
// "plain" version
g.setColor(Color.YELLOW);
g.fillRect(0, newStarty, w, h);
}
#Override
protected TrackListener createTrackListener(JSlider slider) {
return new TrackListener() {
#Override
public void mousePressed(MouseEvent e) {
if (UIManager.getBoolean("Slider.onlyLeftMouseButtonDrag")
&& SwingUtilities.isLeftMouseButton(e)) {
JSlider slider = (JSlider) e.getComponent();
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
slider.setValue(valueForYPosition(e.getY()));
break;
case SwingConstants.HORIZONTAL:
slider.setValue(valueForXPosition(e.getX()));
break;
default:
throw new IllegalArgumentException(
"orientation must be one of: VERTICAL, HORIZONTAL");
}
super.mousePressed(e); // isDragging = true;
super.mouseDragged(e);
} else {
super.mousePressed(e);
}
}
#Override
public boolean shouldScroll(int direction) {
return false;
}
};
}
}
Matching Slider:
public class AudioSlider extends JSlider {
private Image img;
public AudioSlider() {
setOpaque(false);
}
/**
* #return the img
*/
public Image getImage() {
return img;
}
public void setImage(Image img) {
this.img = img;
}
}
Works for me, maybe covers not all prospects.

JPanel Drop Shadow

I have a JPanel element and I would like added a drop shadow to it, how can I add a nice faded drop shadow to the element? Do I need to use external libraries or is there something that is built in that I can use?
Example:
So I looked into swingx which extends JPanel and was able to achieve the results I was looking for with the following code:
public class Canvas extends JXPanel{
public Canvas(){
DropShadowBorder shadow = new DropShadowBorder();
shadow.setShadowColor(Color.BLACK);
shadow.setShowLeftShadow(true);
shadow.setShowRightShadow(true);
shadow.setShowBottomShadow(true);
shadow.setShowTopShadow(true);
this.setBorder(shadow);
}
}
And the result:
This is a complete HACK
This will require you to have a copy of JH-Labs Filters for the blur implementation
This is an expensive operation as it uses a blur operation, the reason I use it is that will take into account the the shape of the component it is shadowing.
The main problem you have is that borders aren't them selves, transparent, there's no way to really have an opaque component and a transparent border. Hench the hack
public class TestDropShadowBorder {
public static void main(String[] args) {
new TestDropShadowBorder();
}
public TestDropShadowBorder() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBackground(Color.RED);
setBorder(new EmptyBorder(20, 20, 20, 20));
setLayout(new BorderLayout());
JPanel drop = new JPanel();
drop.setOpaque(false);
DropShadowBorder border = new DropShadowBorder();
border.setFillContentArea(true);
drop.setBorder(new CompoundBorder(border, new LineBorder(Color.BLACK)));
add(drop);
}
}
public static class DropShadowBorder implements Border {
protected static final int SHADOW_SIZE = 4;
protected static final Map<Component, DropShadowBorder.CachedBorder> BORDER_CACHE = new WeakHashMap<Component, CachedBorder>(5);
private boolean fillContentArea;
private int shadowSize;
private float shadowOpacity;
private Color shadowColor;
public DropShadowBorder() {
this(SHADOW_SIZE, Color.BLACK, 0.5f, true);
}
public DropShadowBorder(boolean paintContentArea) {
this(SHADOW_SIZE, Color.BLACK, 0.5f, paintContentArea);
}
public DropShadowBorder(int shadowSize) {
this(shadowSize, Color.BLACK, 0.5f, true);
}
public DropShadowBorder(Color shadowColor) {
this(SHADOW_SIZE, shadowColor, 0.5f, true);
}
public DropShadowBorder(int shadowSize, Color showColor) {
this(shadowSize, showColor, 0.5f, true);
}
public DropShadowBorder(int shadowSize, float opacity) {
this(shadowSize, Color.BLACK, opacity, true);
}
public DropShadowBorder(Color shadowColor, float opacity) {
this(SHADOW_SIZE, shadowColor, opacity, true);
}
public DropShadowBorder(int shadowSize, Color shadowColor, float opacity) {
this(shadowSize, shadowColor, opacity, true);
}
public DropShadowBorder(int shadowSize, boolean paintContentArea) {
this(shadowSize, Color.BLACK, 0.5f, paintContentArea);
}
public DropShadowBorder(Color shadowColor, boolean paintContentArea) {
this(SHADOW_SIZE, shadowColor, 0.5f, paintContentArea);
}
public DropShadowBorder(int shadowSize, Color showColor, boolean paintContentArea) {
this(shadowSize, showColor, 0.5f, paintContentArea);
}
public DropShadowBorder(int shadowSize, float opacity, boolean paintContentArea) {
this(shadowSize, Color.BLACK, opacity, paintContentArea);
}
public DropShadowBorder(Color shadowColor, float opacity, boolean paintContentArea) {
this(SHADOW_SIZE, shadowColor, opacity, paintContentArea);
}
public DropShadowBorder(int shadowSize, Color showColor, float opacity, boolean paintContentArea) {
setShadowSize(shadowSize);
setShadowColor(showColor);
setShadowOpacity(opacity);
setFillContentArea(paintContentArea);
}
public void setShadowColor(Color shadowColor) {
this.shadowColor = shadowColor;
}
public void setShadowOpacity(float shadowOpacity) {
this.shadowOpacity = shadowOpacity;
}
public Color getShadowColor() {
return shadowColor;
}
public float getShadowOpacity() {
return shadowOpacity;
}
public void setShadowSize(int size) {
shadowSize = size;
}
public int getShadowSize() {
return shadowSize;
}
public static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
public static BufferedImage createCompatibleImage(int width, int height) {
return createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {
int imgWidth = imgSource.getWidth() + (size * 2);
int imgHeight = imgSource.getHeight() + (size * 2);
BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgMask.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
g2.drawImage(imgSource, x, y, null);
g2.dispose();
// ---- Blur here ---
BufferedImage imgGlow = generateBlur(imgMask, size, color, alpha);
//
// BufferedImage imgGlow = ImageUtilities.createCompatibleImage(imgWidth, imgHeight);
// g2 = imgGlow.createGraphics();
//
// g2.drawImage(imgMask, 0, 0, null);
// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
// g2.setColor(color);
//
// g2.fillRect(x, y, imgSource.getWidth(), imgSource.getHeight());
// g2.dispose();
//
// imgGlow = filter.filter(imgGlow, null);
// ---- Blur here ----
// imgGlow = ImageUtilities.applyMask(imgGlow, imgMask, AlphaComposite.DST_OUT);
return imgGlow;
}
public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2d = imgBlur.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.drawImage(imgSource, 0, 0, null);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2d.setColor(color);
g2d.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2d.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
/*
* Because of the amount of time it can take to render the drop shadow,
* we cache the results in a static cache, based on the component
* and the components size.
*
* This allows the shadows to repainted quickly so long as the component
* hasn't changed in size.
*/
BufferedImage dropShadow = null;
DropShadowBorder.CachedBorder cached = BORDER_CACHE.get(c);
if (cached != null) {
dropShadow = cached.getImage(c);
}
if (dropShadow == null) {
int shadowSize = getShadowSize();
float opacity = getShadowOpacity();
Color color = getShadowColor();
// Create a blank canvas, from which the actually border can be generated
// from...
// The ahadow routine can actually generate a non-rectangular border, but
// because we don't have a suitable template to run from, we need to
// set this up our selves...
// It would be nice to be able to user the component itself, but this will
// have to
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.fillRect(0, 0, width - (shadowSize * 2), height - (shadowSize * 2));
g2d.dispose();
// Generate the shadow
BufferedImage shadow = generateShadow(img, shadowSize, getShadowColor(), getShadowOpacity());
// We need to produce a clipping result, cause the border is painted ontop
// of the base component...
BufferedImage clipedShadow = createCompatibleImage(width, height, Transparency.TRANSLUCENT);
g2d = clipedShadow.createGraphics();
Shape clip = g2d.getClip();
// First we create a "area" filling the avaliable space...
Area area = new Area(new Rectangle(width, height));
// Then we subtract the space left over for the component
area.subtract(new Area(new Rectangle(width - (shadowSize * 2), height - (shadowSize * 2))));
// And then apply the clip
g2d.setClip(area);
// Then draw the shadow image
// g2d.drawImage(shadow, -(shadowSize / 2), -(shadowSize / 2), c);
g2d.drawImage(shadow, 0, 0, c);
g2d.setClip(clip);
if (!c.isOpaque() && isFillContentArea()) {
area = new Area(new Rectangle(width - (shadowSize * 2), height - (shadowSize * 2)));
g2d.setColor(c.getBackground());
g2d.fill(area);
}
// g2d.setColor(Color.RED);
// g2d.drawRect(x, y, width - 1, height - 1);
//
// g2d.setColor(Color.GREEN);
// g2d.drawRect(x, y, width - (shadowSize * 2), height - (shadowSize * 2));
g2d.dispose();
dropShadow = clipedShadow;
BORDER_CACHE.put(c, new CachedBorder(dropShadow, c.getSize()));
}
g.drawImage(dropShadow, x, y, c);
// if (!c.isOpaque() && isFillContentArea()) {
//
// Graphics2D g2d = (Graphics2D) g;
//
// Area area = new Area(new Rectangle(width - (shadowSize * 2), height - (shadowSize * 2)));
// g2d.setColor(c.getBackground());
// g2d.fill(area);
//
// }
// g.setColor(Color.MAGENTA);
// g.drawRect(x + 1, y + 1, width - (shadowSize * 2) - 1, height - (shadowSize * 2) - 1);
}
public Insets getBorderInsets(Component cmpnt) {
return new Insets(0, 0, getShadowSize() * 2, getShadowSize() * 2);
}
public boolean isBorderOpaque() {
return false;
}
/**
* Returns if the content area should be painted by this border when the
* parent component is opaque...
*
* The problem is, the paintComponent method will paint the WHOLE component
* background, including the border area. This is a reasonable assumption to
* make, but it makes the shadow border really show up when the parent
* component is a different color.
*
* This allows the border to take control of that fact.
*
* When using it, you will need to try and make this the first border to get
* painted though :P
*
* #return
*/
public boolean isFillContentArea() {
return fillContentArea;
}
public void setFillContentArea(boolean fill) {
fillContentArea = fill;
}
protected class CachedBorder {
private BufferedImage image;
private Dimension size;
public CachedBorder(BufferedImage border, Dimension size) {
this.image = border;
this.size = size;
}
public BufferedImage getImage(Component comp) {
BufferedImage dropShadow = null;
if (comp.getSize().equals(size)) {
dropShadow = image;
}
return dropShadow;
}
}
}
}
UPDATED with additional Example
The drop shadow border has limitations, it can't take into consideration the shape of the component, as the time the border is painted, the component hasn't begin, so we have no reference point.
In order to be able to generate a drop shadow which takes into consideration the shape of the component, we need to create a custom component and inject our border directly into the paint process.
public class TestDropShadowBorder {
public static void main(String[] args) {
new TestDropShadowBorder();
}
public TestDropShadowBorder() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBackground(Color.RED);
setBorder(new EmptyBorder(20, 20, 20, 20));
setLayout(new BorderLayout());
add(new RoundedPane());
}
}
public class RoundedPane extends JPanel {
private int shadowSize = 5;
public RoundedPane() {
// This is very important, as part of the panel is going to be transparent
setOpaque(false);
}
#Override
public Insets getInsets() {
return new Insets(0, 0, 10, 10);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
int width = getWidth() - 1;
int height = getHeight() - 1;
Graphics2D g2d = (Graphics2D) g.create();
applyQualityProperties(g2d);
Insets insets = getInsets();
Rectangle bounds = getBounds();
bounds.x = insets.left;
bounds.y = insets.top;
bounds.width = width - (insets.left + insets.right);
bounds.height = height - (insets.top + insets.bottom);
RoundRectangle2D shape = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height, 20, 20);
/**
* * THIS SHOULD BE CAHCED AND ONLY UPDATED WHEN THE SIZE OF THE
* COMPONENT CHANGES **
*/
BufferedImage img = createCompatibleImage(bounds.width, bounds.height);
Graphics2D tg2d = img.createGraphics();
applyQualityProperties(g2d);
tg2d.setColor(Color.BLACK);
tg2d.translate(-bounds.x, -bounds.y);
tg2d.fill(shape);
tg2d.dispose();
BufferedImage shadow = generateShadow(img, shadowSize, Color.BLACK, 0.5f);
g2d.drawImage(shadow, shadowSize, shadowSize, this);
g2d.setColor(getBackground());
g2d.fill(shape);
/**
* THIS ONE OF THE ONLY OCCASIONS THAT I WOULDN'T CALL
* super.paintComponent *
*/
getUI().paint(g2d, this);
g2d.setColor(Color.GRAY);
g2d.draw(shape);
g2d.dispose();
}
}
public static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
public static BufferedImage createCompatibleImage(int width, int height) {
return createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
public static void applyQualityProperties(Graphics2D g2) {
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {
int imgWidth = imgSource.getWidth() + (size * 2);
int imgHeight = imgSource.getHeight() + (size * 2);
BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgMask.createGraphics();
applyQualityProperties(g2);
int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
// g2.drawImage(imgSource, x, y, null);
g2.drawImage(imgSource, 0, 0, null);
g2.dispose();
// ---- Blur here ---
BufferedImage imgShadow = generateBlur(imgMask, size, color, alpha);
return imgShadow;
}
public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2d = imgBlur.createGraphics();
applyQualityProperties(g2d);
g2d.drawImage(imgSource, 0, 0, null);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2d.setColor(color);
g2d.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2d.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
}
Simple drop shadow you can work off. You can see implemented on these JPanels.
public class DropShadowPanel extends JPanel {
private static final long serialVersionUID = 1L;
public int pixels;
public DropShadowPanel(int pix) {
this.pixels = pix;
Border border = BorderFactory.createEmptyBorder(pixels, pixels, pixels, pixels);
this.setBorder(BorderFactory.createCompoundBorder(this.getBorder(), border));
this.setLayout(new BorderLayout());
}
#Override
protected void paintComponent(Graphics g) {
int shade = 0;
int topOpacity = 80;
for (int i = 0; i < pixels; i++) {
g.setColor(new Color(shade, shade, shade, ((topOpacity / pixels) * i)));
g.drawRect(i, i, this.getWidth() - ((i * 2) + 1), this.getHeight() - ((i * 2) + 1));
}
}
}
Do you mean something like this:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ShadowTest {
private JFrame frame;
public ShadowTest() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShadowTest();
}
});
}
private void initComponents() {
frame = new JFrame();
frame.setTitle("Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//app exited when frame closes
frame.setResizable(false);
frame.setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.fill = GridBagConstraints.HORIZONTAL;
gc.insets = new Insets(10, 10, 10, 10);
frame.add(new RoundedPanel(), gc);
//pack frame (size components to preferred size)
frame.pack();
frame.setVisible(true);//make frame visible
}
}
class RoundedPanel extends JPanel {
/**
* Stroke size. it is recommended to set it to 1 for better view
*/
protected int strokeSize = 1;
/**
* Color of shadow
*/
protected Color shadowColor = Color.black;
/**
* Sets if it drops shadow
*/
protected boolean shady = true;
/**
* Sets if it has an High Quality view
*/
protected boolean highQuality = true;
/**
* Double values for Horizontal and Vertical radius of corner arcs
*/
protected Dimension arcs = new Dimension(0, 0);
//protected Dimension arcs = new Dimension(20, 20);//creates curved borders and panel
/**
* Distance between shadow border and opaque panel border
*/
protected int shadowGap = 10;
/**
* The offset of shadow.
*/
protected int shadowOffset = 4;
/**
* The transparency value of shadow. ( 0 - 255)
*/
protected int shadowAlpha = 150;
int width = 300, height = 300;
public RoundedPanel() {
super();
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Color shadowColorA = new Color(shadowColor.getRed(),
shadowColor.getGreen(), shadowColor.getBlue(), shadowAlpha);
Graphics2D graphics = (Graphics2D) g;
//Sets antialiasing if HQ.
if (highQuality) {
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
//Draws shadow borders if any.
if (shady) {
graphics.setColor(shadowColorA);
graphics.fillRoundRect(
shadowOffset,// X position
shadowOffset,// Y position
width - strokeSize - shadowOffset, // width
height - strokeSize - shadowOffset, // height
arcs.width, arcs.height);// arc Dimension
} else {
shadowGap = 1;
}
//Draws the rounded opaque panel with borders.
graphics.setColor(getBackground());
graphics.fillRoundRect(0, 0, width - shadowGap,
height - shadowGap, arcs.width, arcs.height);
graphics.setColor(getForeground());
graphics.setStroke(new BasicStroke(strokeSize));
graphics.drawRoundRect(0, 0, width - shadowGap,
height - shadowGap, arcs.width, arcs.height);
//Sets strokes to default, is better.
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
Reference:
Rounded Border JPanel

Categories