Need help to create a custom button in swing - java

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

Related

Translucent JPanel not clearing background / showing background artifacts in Linux

I am currently in the process of developing an app, that needs the functionality to select screen area. I've come up with creating a transparent, undecorated, fullscreen JFrame, and adding a translucent, non-opaque JPanel inside of it, where a half-translucent dark background, as well as the selection is painted.
And while the idea (and the code) runs fine on Windows, its not the same story on linux, where the background of the JPanel does not seem to be cleared upon calling repaint() (even though i tell it to via various methods) - upon each repaint method, the background and the component get darker and darker, etc.
Here's the MVCE:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ExampleFrame extends JFrame{
private ExamplePanel selectionPane;
public ExampleFrame(){
this.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
ExampleFrame.this.dispatchEvent(new WindowEvent(ExampleFrame.this, WindowEvent.WINDOW_CLOSING));
}
}
});
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setSize(screenSize);
this.setUndecorated(true);
this.setBackground(new Color(255, 255, 255, 0));
populate();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setType(Window.Type.UTILITY);
this.setVisible(true);
}
private void populate(){
this.selectionPane = new ExamplePanel();
this.setContentPane(selectionPane);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ExampleFrame();
}
});
}
public static class ExamplePanel extends JPanel{
private static Color bg = new Color(0,0,0,0.5f);
private int sx = -1, sy = -1, ex = -1, ey = -1;
public ExamplePanel(){
MouseAdapter mouseAdapter = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
sx = sy = ex = ey = -1;
sx = e.getX();
sy = e.getY();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
ex = e.getX();
ey = e.getY();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
ex = e.getX();
ey = e.getY();
repaint();
}
};
this.addMouseListener(mouseAdapter);
this.addMouseMotionListener(mouseAdapter);
this.setDoubleBuffered(false);
this.setOpaque(false);
this.setBackground(bg);
}
#Override
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D)g.create();
g2.setComposite(AlphaComposite.Clear);
g2.setBackground(new Color(255, 255, 255, 0));
g2.fillRect(0, 0, getWidth(), getHeight());
//g2.clearRect(0, 0, getWidth(), getHeight()); //neither of them work
g2.setComposite(AlphaComposite.Src.derive(.5f));
g2.setPaint(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setComposite(AlphaComposite.Src.derive(1f));
g2.setPaint(Color.WHITE);
g2.drawString("Press Escape to exit", 10, 20);
if(!(sx == -1 || sy == -1 || ex == -1 || ey == -1)){
int asx = Math.min(sx, ex);
int asy = Math.min(sy, ey);
int w = Math.abs(ex - sx);
int h = Math.abs(ey - sy);
g2.setComposite(AlphaComposite.Src);
g2.setPaint(new Color(255, 255, 255, 0));
g2.fillRect(asx, asy, w, h);
g2.setPaint(new Color(0, 0, 0, 1));
g2.fillRect(asx, asy, w, h);
g2.setComposite(AlphaComposite.SrcOver);
g2.setStroke(new BasicStroke(2));
g2.setPaint(new Color(1, 1, 1, 0.15f));
g2.drawRect(asx-1,asy-1, w+2, h+2);
}
}
}
}
Any ideas as to what might cause this? Or maybe this is a bug with Java on linux? I had tested this under Windows 10, and Ubuntu 14.04 LTS as well as unknown version of Arch Linux running with KDE gui (tested by a friend)
EDIT: also tested under OSX (Yosemite & El capitan), both worked fine.
this.setBackground(new Color(255, 255, 255, 0));
If you want a component completely transparent then just use:
component.setOpaque( false );
This tells Swing to look for the parent component and paint it first so you don't get the painting artifacts.
private static Color bg = new Color(0,0,0,0.5f);
If you want semi-transparent backgrounds then need to do custom coding since Swing doesn't support this.
Check out Backgrounds With Transparency for more information on this topic and a couple of solutions.
One is to do your own custom painting with code like:
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
The other solution is a reusable class that can be used with any component so you don't need to customize every component.
panel.setOpaque(false); // background of parent will be painted first
panel.setBackground( new Color(255, 0, 0, 20) );
frame.add(panel);
It's difficult to know the exact cause of the problem without been able to replicate it. There are a number of areas of concern within the code...
Not honouring the paint call chain by not calling super.paintComponent
The use of setDoubleBuffered(false)
The use of this.setBackground(bg); on a JPanel and passing an alpha based color to it
The extensive use of AlphaComposite and it's scrupulous use to try and clear the Graphics context
The basic course of action would be to simplify the paint process until such a time as you can identify the action or combination of actions which are causing the issues.
Or take another approach. Rather than using a combination of different AlphaComposite settings, you might consider just using a Area and subtract the area you want exposed from it....
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.geom.Area;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ExampleFrame extends JFrame {
private ExamplePanel selectionPane;
public ExampleFrame() {
this.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
ExampleFrame.this.dispatchEvent(new WindowEvent(ExampleFrame.this, WindowEvent.WINDOW_CLOSING));
}
}
});
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setSize(screenSize);
this.setUndecorated(true);
this.setBackground(new Color(255, 255, 255, 0));
populate();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setType(Window.Type.UTILITY);
this.setVisible(true);
}
private void populate() {
this.selectionPane = new ExamplePanel();
this.setContentPane(selectionPane);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ExampleFrame();
}
});
}
public static class ExamplePanel extends JPanel {
private static Color bg = new Color(0, 0, 0);
private int sx = -1, sy = -1, ex = -1, ey = -1;
public ExamplePanel() {
MouseAdapter mouseAdapter = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
sx = sy = ex = ey = -1;
sx = e.getX();
sy = e.getY();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
ex = e.getX();
ey = e.getY();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
ex = e.getX();
ey = e.getY();
repaint();
}
};
this.addMouseListener(mouseAdapter);
this.addMouseMotionListener(mouseAdapter);
this.setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
Area area = new Area(new Rectangle(0, 0, getWidth(), getHeight()));
if (!(sx == -1 || sy == -1 || ex == -1 || ey == -1)) {
int asx = Math.min(sx, ex);
int asy = Math.min(sy, ey);
int w = Math.abs(ex - sx);
int h = Math.abs(ey - sy);
area.subtract(new Area(new Rectangle(asx - 1, asy - 1, w + 2, h + 2)));
}
g2.setComposite(AlphaComposite.Src.derive(.25f));
g2.setPaint(bg);
g2.fill(area);
g2.setComposite(AlphaComposite.Src.derive(1f));
g2.setPaint(Color.WHITE);
g2.drawString("Press Escape to exit", 10, 20);
g2.dispose();
}
}
}
Be sure to call super.paintComponent() if you want to clear the background.
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();

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);
}
}
});
}
}

JlayeredPane Transparency setOpaque not working

I am creating a simulation type application, I want one background layer and another layer on top for all of the animations. Im currently using JlayeredPanes but i cannot get the background on the top layer to show as transparent so I can see the background, any help is much appreciated, heres the code:
Background layer
public class SimBackground extends JLayeredPane{
private Model theModel;
private SimulationArea simulationArea;
public SimBackground(Model theModel){
this.theModel=theModel;
setBackground(new Color(0, 230, 0));
setOpaque(true);
setPreferredSize(new Dimension(500,500));
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for(int x=0;x<50;x++){
for(int y=0;y<50;y++){
g.drawRect((x*10), (y*10), 10, 10);
}
}
}
Top layer
public class SimulationArea extends JLayeredPane {
private int SPEED = 100;
private Model theModel;
Timer timer;
public SimulationArea(Model theModel){
this.theModel = theModel;
setPreferredSize(new Dimension(500,500));
setLocation(0,0);
setOpaque(false);
setBackground(new Color(0,0,0,0));
setVisible(true);
//Swing Timer
timer = new Timer(SPEED,new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
update();
repaint();
revalidate();
}
});
}
private void update() {
theModel.update();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
//test get 1 active object
ArrayList<ActiveObject> activeObjects = theModel.getActiveObjects();
//System.out.println(activeObjects.size());
for(int i=0; i<activeObjects.size(); i++){
ActiveObject activeObject = theModel.getActiveObjects().get(i);
int x = activeObject.getCoordinates().getX();
int y = activeObject.getCoordinates().getY();
int size = activeObject.getSize();
g2d.fillRect (x ,y , size, size);
}
}
Can someone please tell me what i'm missing here?
Don't use a JLayeredPane, but if you do need to use JLayeredPane in the future, you will want to read the tutorial here since as per my comment you're not using them correctly at all. Instead I recommend that you simplify by doing all drawing in a single JPanel, drawing your background into a BufferedImage perhaps in the constructor, and then drawing that image and your sprites within the JPanel's paintComponent method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SimExample extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color BKGD_COLOR = new Color(0, 230, 0);
private BufferedImage bkgrnd = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
public SimExample() {
Graphics2D g = bkgrnd.createGraphics();
g.setBackground(BKGD_COLOR);
g.clearRect(0, 0, PREF_W, PREF_H);
g.setColor(Color.black);
for (int x = 0; x < 50; x++) {
for (int y = 0; y < 50; y++) {
g.drawRect((x * 10), (y * 10), 10, 10);
}
}
g.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (bkgrnd != null) {
g.drawImage(bkgrnd, 0, 0, null);
}
// draw sprites here
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
SimExample mainPanel = new SimExample();
JFrame frame = new JFrame("SimExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Java Graphics and Bordering Problems in JScrollPane

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);
}

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