Java Graphics and Bordering Problems in JScrollPane - java

I have found a CustomScrollbarUIExample, and I am trying to change it completely into my own (with attribution, of course, this is legal). I have immediately run into a problem.
What I am trying to achieve is put a border around not the JScrollPane itself, but the moveable block if you understand what I meen.
I have put the modified source code below, and I have highlighted my problem.
package com.finn.chess;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.plaf.metal.MetalScrollBarUI;
/** #see https://stackoverflow.com/a/12270067/230513 */
public class CustomScrollbarUIExample {
public static void main(String[] args) {
JScrollPane before = makeExamplePane();
JScrollPane after = makeExamplePane();
after.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JScrollBar sb = after.getVerticalScrollBar();
sb.setUI(new MyScrollbarUI());
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0,1));
f.add(before);
f.add(after);
f.pack();
f.setSize(320, 240);
f.setVisible(true);
}
private static JScrollPane makeExamplePane() {
JTextArea text = new JTextArea(16, 16);
text.append("Lorem ipsum dolor sit amet…");
JScrollPane scroll = new JScrollPane(text);
return scroll;
}
static class MyScrollbarUI extends MetalScrollBarUI {
private Image imageThumb, imageTrack;
private JButton b = new JButton() {
#Override
public Dimension getPreferredSize() {
return new Dimension(0, 0);
}
};
MyScrollbarUI() {
imageThumb = FauxImage.create(32, 32, Color.blue.brighter());
imageTrack = FauxImage.create(32, 32, Color.BLACK);
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
g.setColor(Color.blue);
((Graphics2D) g).drawImage(imageThumb,
r.x, r.y, r.width, r.height, null);
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {
((Graphics2D) g).drawImage(imageTrack,
r.x, r.y, r.width, r.height, null);
}
#Override
protected JButton createDecreaseButton(int orientation) {
return b;
}
#Override
protected JButton createIncreaseButton(int orientation) {
return b;
}
}
private static class FauxImage {
static public Image create(int w, int h, Color c) {
BufferedImage bi = new BufferedImage(
w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(c);
g2d.fillRect(0, 0, w, h);
// THIS IS MY PROBLEM, THE BORDER
g2d.setPaint(Color.WHITE);
g2d.drawRect(0, 0, w-1, h-1);
g2d.dispose();
return bi;
}
}
}
Just at the end, you can see that I setup a border to put around it.
But in big sizes, it appears like this:
I don't want that massive block of white down the bottom; I want a simple, one pixel high border.
How do I achieve this?
Also I am posting a brand new thread because the other one was 2 years old, and I can't add ALL this into a comment.

Add the border in paintThumb(), after the image has been scaled by drawImage(). Starting from the original and using Color.red for emphasis, the result is seen below:
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
g.setColor(Color.blue);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(imageThumb, r.x, r.y, r.width, r.height, null);
g2d.setPaint(Color.red);
g2d.drawRect(r.x, r.y, r.width - 1, r.height);
}

Related

rotate an Ellipse2D object

I'm trying to rotate one whole Ellipse2D object based on user key input. If the user presses the right key, rotate right and left key means rotate left. The rotAngle is set to 25. I made a separate drawRotEllipse because otherwise it would have always drawn the original one. I think my confusion is happening with the Graphics and Shapes Objects. Tried the AffineTransform business but that didn't work out either. I just want it to rotate about the center. Thanks for any help!
class Canvas extends JPanel implements java.io.Serializable{
int x1 = (int) (this.getWidth()/2)+100;
int y1 = (int) (this.getHeight()/2)+20;
int x2 = (int) this.getWidth()+100;
int y2 = (int) this.getHeight()+200;
#Override
public void paintComponent(Graphics g){
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.RED);
drawEllipse(g);
}
public void drawEllipse (Graphics g){
Graphics2D g2d = (Graphics2D) g;
myShape = new Ellipse2D.Double(x1,y1,x2,y2);
g2d.draw(myShape);
this.repaint();
}
public void drawRotEllipse (Graphics g){
g2d.draw(myShape);
this.repaint();
}
}
private void jPanel1KeyPressed(java.awt.event.KeyEvent evt) {
if (evt.getKeyCode()==39){
g2d.rotate(Math.toDegrees(rotAngle));
myCanvas.drawRotEllipse(g2d);
}
else if (evt.getKeyCode()==37){
g2d.rotate(Math.toDegrees(-rotAngle));
myCanvas.drawRotEllipse(g2d);
}
}
if (evt.getKeyCode()==39)
Don't use magic numbers. People don't know that means by just looking at the code.
Instead use variable provided by the API:
if (evt.getKeyCode() == KeyEvent.VK_RIGHT)
You KeyEvent code should not do the actual painting. All the code should do is set the "degrees" property of your class. The setDegrees(...) method will then be responsible for invoking repaint(). Now whenever the component is repainted the shape will be painted at its current degrees of rotation.
Here is an example that uses a JSlider to change the rotation degrees of the class.
It rotates an image. You should be able to change the code rotation the image to just draw your shape:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation2 extends JPanel
{
BufferedImage image;
int degrees;
int point = 250;
public Rotation2(BufferedImage image)
{
this.image = image;
setDegrees( 0 );
setPreferredSize( new Dimension(600, 600) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
double radians = Math.toRadians( degrees );
g2.translate(point, point);
g2.rotate(radians);
g2.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2.drawImage(image, 0, 0, null);
g2.dispose();
g.setColor(Color.RED);
g.fillOval(point - 5, point - 5, 10, 10);
}
public void setDegrees(int degrees)
{
this.degrees = degrees;
repaint();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
// String path = "mong.jpg";
String path = "dukewavered.gif";
ClassLoader cl = Rotation2.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
final Rotation2 r = new Rotation2(bi);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
r.setDegrees( value );
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(r));
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}

How build personal JFrame from a PNG picture

I try to build my personal JFrame from a PNG picture. But there is different behavior between Mac OSX 10.8 and Windows 7. (I have to use JDK 6)
Here is my code :
[...]
public Fenetre()
{
this.setLocationRelativeTo(null);
this.setUndecorated(true);
this.setBackground(new Color(0,0,0,0));
try {
image = ImageIO.read(this.getClass().getResource("/Images/frame.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.setSize(image.getWidth(),image.getHeight());
this.setLayout(null);
panel = new JPanel();
JButton quit = new JButton("Quitter");
panel.add(quit);
Dimension size = panel.getPreferredSize();
panel.setBounds(67, 45, size.width, size.height);
this.add(panel);
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.setVisible(true);
}
public void paint(Graphics g) {
Graphics2D g2 =(Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); // SRC_ATOP > Windows
g2.drawImage(image, 0, 0, this);
panel.update(panel.getGraphics());
}
[...]
The result on Mac OSX 10.8 (AlphaComposite = SRC) :
http://imageshack.us/photo/my-images/15/maczr.png/
Then, on Windows 7 (AlphaComposite = SRC_ATOP), at start up and when I move it, I can see :
http://imageshack.us/photo/my-images/16/windowsqu.jpg/
How do it ?
Your code is incomplete, but it seems to me like you are overriding the paint() method of a JFrame. You should never do this (unless you know what you doing and you invoke super.paint(..))!
If you want to display an image in the frame then either:
a) add a JLabel with an image to the frame
b) or do custom painting on a JPanel by overriding the paintComponent() method and then add the panel to the frame.
You are not honoring the paint chain
public void paint(Graphics g) {
// You must call super.paint somewhere here...
Graphics2D g2 =(Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); // SRC_ATOP > Windows
g2.drawImage(image, 0, 0, this);
panel.update(panel.getGraphics());
}
You should NEVER call Component#update.
panel.update(panel.getGraphics());
This is called on you behalf by the repaint manager, which calls paint.
paint calls paintComponent, paintBorder and paintChildren failing to honor the paint chain means that not of these methods are been called and they are very important
As camickr has pointed out, you should never need to overrride the paint method of a top level container, like JFrame.
Instead, create a custom component that is capable of performing you painting for you and set it as the frames content pane...
this.setLocationRelativeTo(null);
this.setUndecorated(true);
this.setBackground(new Color(0,0,0,0));
setContentPane(new FancyPaintPane());
pack();
And the FancyPaintPane
public class FancyPaintPane extends JPanel {
private BufferedImage image;
public FancyPaintPane() {
try {
image = ImageIO.read(this.getClass().getResource("/Images/frame.png"));
} catch (IOException e) {
e.printStackTrace();
}
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(), image.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
Graphics2D g2 = (Graphics2D) g.create();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); // SRC_ATOP > Windows
g2.drawImage(image, 0, 0, this);
g2.dispose();
}
}
You should also never modify a Graphics context without reverting it. These are shared resources across all components within the same top level container. A better approach is to create a copy which you can manipulate and dispose of when you're done...
You are also trying to show a component with transparent elements without first marking the component as transparent. This can produce nasty paint artifacts. You should call JComponent#setOpaque passing it a false value.
I would also strongly discourage you from using null layouts. They have a nasty habit of coming back and biting you.
Updated with simple example
public class CirclePaneTest {
public static void main(String[] args) {
new CirclePaneTest();
}
public CirclePaneTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
CirclePane circlePane = new CirclePane();
circlePane.setLayout(new BorderLayout());
circlePane.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
System.exit(0);
}
}
});
JLabel label = new JLabel("Look Ma, I'm a circle");
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
JFrame frame = new JFrame("Test");
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setContentPane(circlePane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class CirclePane extends JPanel {
public CirclePane() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected int getRadius() {
return Math.min(getWidth(), getHeight()) - 1;
}
#Override
public Insets getInsets() {
int radius = getRadius();
int xOffset = (getWidth() - radius) / 2;
int yOffset = (getHeight() - radius) / 2;
Insets insets = new Insets(
radius / 6,
radius / 6,
radius / 6,
radius / 6);
return insets;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int radius = getRadius();
int xOffset = (getWidth() - radius) / 2;
int yOffset = (getHeight() - radius) / 2;
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(getBackground());
g2d.fillOval(xOffset, yOffset, radius, radius);
g2d.setColor(Color.GRAY);
g2d.drawOval(xOffset, yOffset, radius, radius);
g2d.dispose();
}
}
}
Updated with code for Java 7
The following code should be used to set up the frame to be transparent under Java 6.
JFrame frame = new JFrame("Test");
frame.setAlwaysOnTop(true);
frame.setUndecorated(true);
try {
Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
if (awtUtilsClass != null) {
Method method = awtUtilsClass.getMethod("setWindowOpaque", Window.class, boolean.class);
method.invoke(null, frame, false);
}
} catch (Exception exp) {
}
//frame.setBackground(new Color(0, 0, 0, 0));
frame.setContentPane(circlePane);

Need help to create a custom button in swing

I am trying to create a button which looks as shown below and continuously fades in and fades out .It looks like :-
Now i have done till the looks with gradient paint but what should i do to make the button text appear.Inspite of calling 'super(s)' it doesn't appear as i have painted it with GradientPaint.What should i do make the text appear over paint.My code is shown below :-
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Fader extends JFrame{
Fader()
{
super("A fading button");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setSize(400,400);
add(new CustomButton("Submit"));
setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable(){public void run(){new Fader();}});
}
}
class CustomButton extends JButton
{
public CustomButton(String s) {
super(s);
// TODO Auto-generated constructor stub
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2=(Graphics2D)g.create();
GradientPaint gp=new GradientPaint(0, 0, Color.RED, 200, 100, Color.YELLOW);
g2.setPaint(gp);
g2.fillRect(0, 0, getWidth(), getHeight());
}
public Dimension getPreferredSize()
{
return new Dimension(200,100);
}
}
Secondly,an advice to implement the fade in and out effect is also requested.
You can use this option, that paints a transparent color gradient on a component:
#Override
public void paintComponent(Graphics g){
super.paintComponent( g );
Graphics2D g2=(Graphics2D)g.create();
int h = getHeight();
int w = getWidth();
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .5f));
g2.setPaint(new GradientPaint(0, 0, Color.yellow, 0, h, Color.red));
g2.fillRect(0, 0, w, h);
g2.dispose();
}
Other pretty good example with fading in (as requested). I used RadialGradientPaint. You can play with AlphaComposite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .4f));
where 4f represent transparent level 40%
#Override
public void paintComponent(Graphics g){
super.paintComponent( g );
Graphics2D g2=(Graphics2D)g.create();
int h = getHeight();
int w = getWidth();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f));
Point2D center = new Point2D.Float(100, 50);
float radius = 150;
float[] dist = {0.0f, 1.0f};
Color[] colors = {Color.yellow, Color.red};
RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, colors);
g2.setPaint(p);
g2.fillRect(0, 0, w, h);
g2.dispose();
}
Finally we can play with alpha dynamically. Her is the full code. I created simple thread that change me alpha from 0 to 9 and vise versa. Here we go:
public class Fader extends JFrame{
private static final long serialVersionUID = 1L;
static JButton button;
public static float mTransparent = .0f;
Fader(){
super("A fading button");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setSize(400,400);
JButton button = new CustomButton("Submit");
add(button);
setVisible(true);
Blink blink = new Blink(this);
blink.start();
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){public void run(){new Fader();}});
}
public static float getTransparentLevel() {
return mTransparent;
}
public void setTransparentLevel(float newVal) {
mTransparent = newVal;
if(button != null){
button.repaint();
}
repaint();
}
}
class Blink extends Thread{
Fader fader;
public Blink(Fader fader) {
this.fader = fader;
}
#Override
public void run(){
while(true){
if(Fader.getTransparentLevel() == 0.0f){
//increase to 1f
for(int i=1; i<10; i++){
fader.setTransparentLevel((float)i/10);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
else if(Fader.getTransparentLevel() == 0.9f){
//increase to 1f
for(int i=10; i>=0; i--){
fader.setTransparentLevel((float)i/10);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class CustomButton extends JButton {
private static final long serialVersionUID = 1L;
public CustomButton(String s) {
super(s);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent( g );
Graphics2D g2=(Graphics2D)g.create();
int h = getHeight();
int w = getWidth();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, Fader.getTransparentLevel()));
Point2D center = new Point2D.Float(100, 50);
float radius = 150;
float[] dist = {0.0f, 1.0f};
Color[] colors = {Color.yellow, Color.red};
RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, colors);
g2.setPaint(p);
g2.fillRect(0, 0, w, h);
g2.dispose();
}
public Dimension getPreferredSize(){
return new Dimension(200,100);
}
}
It blinks with sleep 300 ms from .0 to .9 of transparent and back from .9 to .0:
-->
Once you override the paintComponent() method, you are on your own with drawing the button. So, you will have to draw the text yourself. Something like this will help:
g2.setColor(Color.GREEN);
g2.drawString(getText(), 0, 10);
The above code must be added after the fillRect method. However, you will have to use FontMetrics in order to position the text according to the text alignment preferences.
To fadeIn and fadeOut you will need to implement your own Animation Sequencer that runs in a different thread, that will constantly vary the alpha value with a TimerTask. Once the value of alpha reaches 0, it should be incremented back to 100%.
Also check out the book by Romain Guy: Filthy Rich Java Clients

Add a background image to JPanel with rounded corners

I've just recently extended JPanel for use in a project which we want to appear to be more "3D". That's my bosses' way of requiring shadowing and rounded corners on components. That's been accomplished as shown on many online examples. I did it like this:
public class RoundedPanel extends JPanel
{
protected int _strokeSize = 1;
protected Color _shadowColor = Color.BLACK;
protected boolean _shadowed = true;
protected boolean _highQuality = true;
protected Dimension _arcs = new Dimension(30, 30);
protected int _shadowGap = 5;
protected int _shadowOffset = 4;
protected int _shadowAlpha = 150;
protected Color _backgroundColor = Color.LIGHT_GRAY;
public RoundedPanel()
{
super();
setOpaque(false);
}
#Override
public void setBackground(Color c)
{
_backgroundColor = c;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int shadowGap = this._shadowGap;
Color shadowColorA = new Color(_shadowColor.getRed(), _shadowColor.getGreen(), _shadowColor.getBlue(), _shadowAlpha);
Graphics2D graphics = (Graphics2D) g;
if(_highQuality)
{
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
if(_shadowed)
{
graphics.setColor(shadowColorA);
graphics.fillRoundRect(_shadowOffset, _shadowOffset, width - _strokeSize - _shadowOffset,
height - _strokeSize - _shadowOffset, _arcs.width, _arcs.height);
}
else
{
_shadowGap = 1;
}
graphics.setColor(_backgroundColor);
graphics.fillRoundRect(0, 0, width - shadowGap, height - shadowGap, _arcs.width, _arcs.height);
graphics.setStroke(new BasicStroke(_strokeSize));
graphics.setColor(getForeground());
graphics.drawRoundRect(0, 0, width - shadowGap, height - shadowGap, _arcs.width, _arcs.height);
graphics.setStroke(new BasicStroke());
}
}
I am creating a test frame with the following code:
public class UITest
{
private static JFrame mainFrame;
private static ImagePanel mainPanel;
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
mainFrame = new JFrame();
mainFrame.setVisible(true);
try
{
mainPanel = new ImagePanel(ImageIO.read(this.getClass().getResource("/content/diamondPlate_Light.jpg")));
//mainPanel.setBounds(0, 0, 800, 600);
}
catch(IOException e)
{
}
mainPanel.setLayout(null);
RoundedPanel rPanel = new RoundedPanel();
rPanel.setBounds(10, 10, 200, 200);
rPanel.setBackground(new Color(168, 181, 224));
mainPanel.add(rPanel);
rPanel = new RoundedPanel();
rPanel.setBounds(220, 10, 560, 200);
rPanel.setBackground(new Color(168, 224, 168));
mainPanel.add(rPanel);
rPanel = new RoundedPanel();
rPanel.setBounds(10, 220, 770, 300);
rPanel.setBackground(new Color(224, 168, 168));
mainPanel.add(rPanel);
mainFrame.setSize(800, 600);
mainFrame.getContentPane().add(mainPanel);
}
});
}
}
And it results in this (sans the background image of the JFrame's contentPane:
What I would really like to do is generate the red, green, and blue panels with the rounded corners, but filled by a different image instead of the Color. I still want the properly rounded corners, but I'm unsure of how to do this.
If I've got a large texture, can I simply "clip" a piece of it out in the size and shape of the RoundedPanel? I need to evaluate this, since it just occurred to me as I typed, but if I can create a piece of geometry like what is used in graphics.fillRoundRect(...) and then clip the image, this could work.
Are there any other ways of doing this that I'm missing? I'd appreciate any feedback you might be able to offer. Thanks.
Edit:
Based upon the idea in the selected solution below, I've got the following results:
It needs to be whipped into shape for production and the background images are poorly chosen, but as a demo, the following RoundedPanel code gets us to the above results:
public class RoundedPanel extends JPanel
{
protected int strokeSize = 1;
protected Color _shadowColor = Color.BLACK;
protected boolean shadowed = true;
protected boolean _highQuality = true;
protected Dimension _arcs = new Dimension(30, 30);
protected int _shadowGap = 5;
protected int _shadowOffset = 4;
protected int _shadowAlpha = 150;
protected Color _backgroundColor = Color.LIGHT_GRAY;
protected BufferedImage image = null;
public RoundedPanel(BufferedImage img)
{
super();
setOpaque(false);
if(img != null)
{
image = img;
}
}
#Override
public void setBackground(Color c)
{
_backgroundColor = c;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int shadowGap = this._shadowGap;
Color shadowColorA = new Color(_shadowColor.getRed(), _shadowColor.getGreen(), _shadowColor.getBlue(), _shadowAlpha);
Graphics2D graphics = (Graphics2D) g;
if(_highQuality)
{
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
if(shadowed)
{
graphics.setColor(shadowColorA);
graphics.fillRoundRect(_shadowOffset, _shadowOffset, width - strokeSize - _shadowOffset,
height - strokeSize - _shadowOffset, _arcs.width, _arcs.height);
}
else
{
_shadowGap = 1;
}
RoundRectangle2D.Float rr = new RoundRectangle2D.Float(0, 0, (width - shadowGap), (height - shadowGap), _arcs.width, _arcs.height);
Shape clipShape = graphics.getClip();
if(image == null)
{
graphics.setColor(_backgroundColor);
graphics.fill(rr);
}
else
{
RoundRectangle2D.Float rr2 = new RoundRectangle2D.Float(0, 0, (width - strokeSize - shadowGap), (height - strokeSize - shadowGap), _arcs.width, _arcs.height);
graphics.setClip(rr2);
graphics.drawImage(this.image, 0, 0, null);
graphics.setClip(clipShape);
}
graphics.setColor(getForeground());
graphics.setStroke(new BasicStroke(strokeSize));
graphics.draw(rr);
graphics.setStroke(new BasicStroke());
}
}
Thanks for the help.
Try "clipping area" (see the g.setClip() call):
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(new Dimension(600, 400));
f.getContentPane().setLayout(null);
RoundPanel rp = new RoundPanel();
rp.setBounds(100, 50, 400, 300);
f.getContentPane().add(rp);
f.setVisible(true);
}
static class RoundPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
// Prepare a red rectangle
BufferedImage bi = new BufferedImage(400, 300, BufferedImage.TYPE_INT_ARGB);
Graphics2D gb = bi.createGraphics();
gb.setPaint(Color.RED);
gb.fillRect(0, 0, 400, 300);
gb.dispose();
// Set a rounded clipping region:
RoundRectangle2D r = new RoundRectangle2D.Float(0, 0, 400, 300, 20, 20);
g.setClip(r);
// Draw the rectangle (and see whether it has round corners)
g.drawImage(bi, 0, 0, null);
}
}
Beware of the restrictions mentioned in the API doc for Graphics.setClip:
Sets the current clipping area to an arbitrary clip shape. Not all objects that implement the Shape interface can be used to set the clip. The only Shape objects that are guaranteed to be supported are Shape objects that are obtained via the getClip method and via Rectangle objects.

Translucent JFrame border JDK 7

I was asking question about Translucent JFrame border (see here) and I got very good answers, but unfortunatelly, given answers work perfectly only on JDK 6, but not 7. Any ideas how to make it work with JDK 7?
In JDK 6 it looks like this:
And JDK 7:
And my code looks like this:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.border.AbstractBorder;
public class ShadowBorder extends AbstractBorder {
private static final int RADIUS = 30;
private static BufferedImage shadowTop;
private static BufferedImage shadowRight;
private static BufferedImage shadowBottom;
private static BufferedImage shadowLeft;
private static BufferedImage shadowTopLeft;
private static BufferedImage shadowTopRight;
private static BufferedImage shadowBottomLeft;
private static BufferedImage shadowBottomRight;
private static boolean shadowsLoaded = false;
public ShadowBorder() {
if (!shadowsLoaded) {
try {
shadowTop = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-top.png"));
shadowRight = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-right.png"));
shadowBottom = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-bottom.png"));
shadowLeft = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-left.png"));
shadowTopLeft = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-top-left.png"));
shadowTopRight = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-top-right.png"));
shadowBottomLeft = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-bottom-left.png"));
shadowBottomRight = ImageIO.read(getClass().getResource("/cz/vutbr/fit/assets/shadow-bottom-right.png"));
shadowsLoaded = true;
} catch (IOException ex) {
Logger.getLogger(ShadowBorder.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
#Override
public boolean isBorderOpaque() {
return false;
}
#Override
public Insets getBorderInsets(Component c) {
return new Insets(RADIUS, RADIUS, RADIUS, RADIUS);
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
insets.top = RADIUS;
insets.left = RADIUS;
insets.bottom = RADIUS;
insets.right = RADIUS;
return insets;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, 1f));
int recWidth = width - (2 * RADIUS);
int recHeight = height - (2 * RADIUS);
int recX = width - RADIUS;
int recY = height - RADIUS;
//edges
g2d.drawImage(shadowTop.getScaledInstance(recWidth, RADIUS, Image.SCALE_REPLICATE), RADIUS, 0, null);
g2d.drawImage(shadowRight.getScaledInstance(RADIUS, recHeight, Image.SCALE_REPLICATE), recX, RADIUS, null);
g2d.drawImage(shadowBottom.getScaledInstance(recWidth, RADIUS, Image.SCALE_REPLICATE), RADIUS, recY, null);
g2d.drawImage(shadowLeft.getScaledInstance(RADIUS, recHeight, Image.SCALE_REPLICATE), 0, RADIUS, null);
//corners
g2d.drawImage(shadowTopLeft, 0, 0, null);
g2d.drawImage(shadowTopRight, recX, 0, null);
g2d.drawImage(shadowBottomLeft, 0, recY, null);
g2d.drawImage(shadowBottomRight, recX, recY, null);
}
}
Thanks a lot!
I've just solved my problem. The problem was, that JDK 7 implements AWTUtilities.setWindowOpaque() method from JDK6 in setBackground() method and I was (NetBeans did :-)) setting default background for JFrame in different place, so setting background to new Color(0, 0, 0, 0); makes JFrame transparent and all goes well now.
For whoever stumbles upon this thread and wants his own transparent window, I devised this example. With how little information is available on the web, I almost had to break a leg to come up with something just works, and doesn't use image files or anything. (Combined from different examples on this site)
public class GradientTranslucentWindowDemo
{
public static void main(String[] args)
{
// Create the GUI on the event-dispatching thread
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
final JFrame f = new JFrame("Per-pixel translucent window");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setUndecorated(true);
f.setBackground(new Color(0, 0, 0, 0));
final BufferedImage backrgoundImage = makeBackrgoundImage(400, 400);
JPanel panel = new JPanel()
{
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (g instanceof Graphics2D)
{
g.drawImage(backrgoundImage, 0, 0, null);
}
}
};
panel.setOpaque(false);
f.setContentPane(panel);
f.setLayout(new GridBagLayout()); // Centers the button
f.add(new JButton(new AbstractAction("Close")
{
#Override
public void actionPerformed(ActionEvent e)
{
f.dispose();
}
}));
f.setBounds(100, 100, 400, 400);
f.setVisible(true);
}
});
}
static BufferedImage makeBackrgoundImage(int w, int h)
{
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
// Draw something transparent
Graphics2D g = img.createGraphics();
g.setPaint(new RadialGradientPaint(new Point2D.Float(w / 2, h / 2), (w + h) / 4, new float[]{0, 1}, new Color[]{Color.RED, new Color(1f, 0, 0, 0)}));
g.fillRect(0, 0, w, h);
g.setPaint(Color.RED);
g.drawRect(0, 0, w - 1, h - 1);
g.dispose();
return img;
}
}

Categories

Resources