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;
}
}
Related
I am trying to design a JButton.
I want the JButton to look like this:
I tried to achieve this using Polygon but I couldn't make the corners be round as seen above.
The one I designed looks like this:
The code that generated this button is below:
public class arcButton extends JButton{
public arcButton() {
Dimension size = getPreferredSize();
size.width = size.height = Math.max(size.width, size.height);
setPreferredSize(size);
setContentAreaFilled(false);
}
protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
g.setColor(Color.CYAN.darker().darker());
} else {
g.setColor(Color.CYAN.darker());
}
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
g.fillPolygon(xPoints, yPoints, xPoints.length);
super.paintComponent(g);
}
protected void paintBorder(Graphics g) {
g.setColor(Color.cyan);
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
g.drawPolygon(xPoints, yPoints, xPoints.length);
}
Polygon polygon;
public boolean contains(int x, int y) {
if (polygon == null ||
!polygon.getBounds().equals(getBounds())) {
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
polygon = new Polygon(xPoints,yPoints,xPoints.length);
}
return polygon.contains(x, y);
}
}
I tried to draw with arcs but when I use ((Graphics2D)g).draw(arc) in the paintComponent. It kept giving a lot of errors when mouse was on the GUI.
How should I approach this?
I created the following GUI.
Instead of extending a JButton, I created a class to hold two BufferedImages. One for the arrow, and one to signify a pressed button.
I created a test GUI so I could draw the arrow one small piece at a time. I wound up creating two Polygons, one for the semi-circle and one for the arrowhead.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CustonButtonGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CustonButtonGUI());
}
private ButtonImages buttonImages;
public CustonButtonGUI() {
this.buttonImages = new ButtonImages();
}
#Override
public void run() {
JFrame frame = new JFrame("Custom JButton");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
BufferedImage image = buttonImages.getMainImage();
JButton button = new JButton();
button.setPreferredSize(new Dimension(image.getWidth(panel),
image.getHeight(panel)));
button.setIcon(new ImageIcon(image));
button.setPressedIcon(new ImageIcon(buttonImages.getPressedImage()));
panel.add(button);
return panel;
}
private class ButtonImages {
private final BufferedImage mainImage;
private final BufferedImage pressedImage;
public ButtonImages() {
this.mainImage = createMainImage(120, 200);
this.pressedImage = createPressedImage(120, 200);
}
private BufferedImage createMainImage(int width, int height) {
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
g2d.setColor(Color.BLACK);
g2d.fillPolygon(createArrowPolygon(width, height));
g2d.fillPolygon(createCircularPolygon(width, height));
g2d.dispose();
return image;
}
private Polygon createArrowPolygon(int width, int height) {
Polygon polygon = new Polygon();
int margin = 10;
int arrowWidth = 30;
int x = width - margin;
int y = height - margin;
polygon.addPoint(x, y - arrowWidth);
polygon.addPoint(x - arrowWidth, y - arrowWidth - arrowWidth);
polygon.addPoint(x - arrowWidth, y);
return polygon;
}
private Polygon createCircularPolygon(int width, int height) {
Polygon polygon = new Polygon();
int centerY = height / 2;
int margin = 10;
Point centerPoint = new Point(width - margin - 30, centerY);
double radius = centerY - 55.0;
for (int angle = 90; angle <= 270; angle++) {
double theta = Math.toRadians(angle);
int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
polygon.addPoint(x, y);
}
radius += 25.0;
for (int angle = 270; angle >= 90; angle--) {
double theta = Math.toRadians(angle);
int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
polygon.addPoint(x, y);
}
return polygon;
}
private BufferedImage createPressedImage(int width, int height) {
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
return image;
}
public BufferedImage getMainImage() {
return mainImage;
}
public BufferedImage getPressedImage() {
return pressedImage;
}
}
}
After scaling BufferdImages of nation flags about 50% of all flags are displayed in black and white (not grayscale) and few do look weird, like turky:
Here's a black and white example
Here I set the flag
protected void updateFlag(BufferedImage flag){
int height = pnlFlag.getHeight();
int width = (int)(1f * flag.getWidth() / flag.getHeight() * height);
BufferedImage scaledFlag = new BufferedImage(width, height, flag.getType());
Graphics2D g2d = scaledFlag.createGraphics();
g2d.drawImage(flag, 0, 0, scaledFlag.getWidth(), scaledFlag.getHeight(), null);
g2d.dispose();
pnlFlag.flag = scaledFlag;
pnlFlag.repaint();
}
And my JPanel
class FlagPanel extends JPanel{
private BufferedImage flag;
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(flag == null) return;
g.drawImage(flag, 0, 0, null);
}
}
I'm pretty sure you can not just change the height and width of a Buffered Image and it will scale for you.
Try using getScaledInstance() like in this question.
The code bellow works fine, but you need to call the repaint method because the getScaledInstance method take a time to generate the scaloned image.
public class Main extends JFrame {
private ImageIcon ico;
private boolean resize = true;
private Image scale;
public Main() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
ico = new ImageIcon("image.jpg");
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D gg = (Graphics2D) g;
if (!resize) {
g.drawImage(ico.getImage(), 0, 0, null);
} else {
if (scale == null) {
scale = ico.getImage().getScaledInstance(ico.getIconWidth() / 2, ico.getIconHeight() / 2, Image.SCALE_SMOOTH);
}
g.drawImage(scale, 0, 0, null);
// gg.scale(0.5, 0.5);
// gg.drawImage(ico.getImage(), 0, 0, null);
}
}
public static void main(String[] args) {
Main m = new Main();
m.setSize(600, 600);
m.setVisible(true);
}
}
Is there a way to make a JButton which has a transparent fill(30% transparent) and a text which is not transparent?
For now I discovered the following options:
make both the button and the text transparent.
make both of them not transparent.
is there an option in between?
Here is one possible implementation using JButton#setIcon(Icon_30%_transparent):
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;
public final class TranslucentButtonIconTest {
private static final TexturePaint TEXTURE = makeCheckerTexture();
public JComponent makeUI() {
JPanel p = new JPanel() {
#Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(TEXTURE);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.dispose();
}
};
p.add(makeButton("aaa"));
p.add(makeButton("bbbbbbb"));
p.add(makeButton("ccccccccccc"));
p.add(makeButton("ddddddddddddddddddddddddddddd"));
return p;
}
private static AbstractButton makeButton(String title) {
return new JButton(title) {
#Override public void updateUI() {
super.updateUI();
setVerticalAlignment(SwingConstants.CENTER);
setVerticalTextPosition(SwingConstants.CENTER);
setHorizontalAlignment(SwingConstants.CENTER);
setHorizontalTextPosition(SwingConstants.CENTER);
setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 8));
setMargin(new Insets(2, 8, 2, 8));
setContentAreaFilled(false);
setFocusPainted(false);
setOpaque(false);
setForeground(Color.WHITE);
setIcon(new TranslucentButtonIcon());
}
};
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TranslucentButtonIconTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static TexturePaint makeCheckerTexture() {
int cs = 6;
int sz = cs * cs;
BufferedImage img = new BufferedImage(sz, sz, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setPaint(new Color(120, 120, 220));
g2.fillRect(0, 0, sz, sz);
g2.setPaint(new Color(200, 200, 200, 20));
for (int i = 0; i * cs < sz; i++) {
for (int j = 0; j * cs < sz; j++) {
if ((i + j) % 2 == 0) {
g2.fillRect(i * cs, j * cs, cs, cs);
}
}
}
g2.dispose();
return new TexturePaint(img, new Rectangle(0, 0, sz, sz));
}
}
class TranslucentButtonIcon implements Icon {
private static final int R = 8;
private int width;
private int height;
#Override public void paintIcon(Component c, Graphics g, int x, int y) {
if (c instanceof AbstractButton) {
AbstractButton b = (AbstractButton) c;
Insets i = b.getMargin();
int w = c.getWidth();
int h = c.getHeight();
width = w - i.left - i.right;
height = h - i.top - i.bottom;
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Shape area = new RoundRectangle2D.Float(x - i.left, y - i.top, w - 1, h - 1, R, R);
Color color = new Color(0f, 0f, 0f, .3f);
ButtonModel m = b.getModel();
if (m.isPressed()) {
color = new Color(0f, 0f, 0f, .3f);
} else if (m.isRollover()) {
color = new Color(1f, 1f, 1f, .3f);
}
g2.setPaint(color);
g2.fill(area);
g2.setPaint(Color.WHITE);
g2.draw(area);
g2.dispose();
}
}
#Override public int getIconWidth() {
return Math.max(width, 100);
}
#Override public int getIconHeight() {
return Math.max(height, 24);
}
}
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
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.