Java 3 Color Gradient - java

I have a JPanel, and I would like to paint a gradient within it. I have the code below, but that only paints a 2 color gradient. I would like to add a 3rd but don't know how. What I want is to have the top left of the panel as white, top right red, and both bottom corners black. What would I have to do to achieve this, something that looks like this:
package pocketshop.util;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class ColorPicker extends JPanel{
public ColorPicker(){
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(
0, 0, Color.white,
0, h, Color.black);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
}
Edit: Possible solution
I was able to come up with using 2 gradients one horizontal and one vertical, like this:
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
int w = getWidth();
int h = getHeight();
// Vertical
GradientPaint gp = new GradientPaint(
0, 0, new Color(0,0,0,0),
0, h, Color.black);
// Horizontal
GradientPaint gp2 = new GradientPaint(
0, 0, Color.white,
w, 0, Color.red, true);
g2d.setPaint(gp2);
g2d.fillRect(0, 0, w, h);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}

Something like this?
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ThreeWayGradient {
public static void main(String[] args) {
final BufferedImage image = new BufferedImage(
200, 200, BufferedImage.TYPE_INT_RGB);
Runnable r = new Runnable() {
#Override
public void run() {
Graphics2D g = image.createGraphics();
GradientPaint primary = new GradientPaint(
0f, 0f, Color.WHITE, 200f, 0f, Color.ORANGE);
GradientPaint shade = new GradientPaint(
0f, 0f, new Color(0, 0, 0, 0),
0f, 200f, new Color(0, 0, 0, 255));
g.setPaint(primary);
g.fillRect(0, 0, 200, 200);
g.setPaint(shade);
g.fillRect(0, 0, 200, 200);
JLabel l = new JLabel(new ImageIcon(image));
JOptionPane.showMessageDialog(null, l);
File f = new File(System.getProperty("user.home"),
"ThreeWayGradient.png");
try {
ImageIO.write(image, "png", f);
} catch (IOException ex) {
ex.printStackTrace();
}
}
};
SwingUtilities.invokeLater(r);
}
}
Making it into a factory method
..because it is prettier.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ThreeWayGradient {
public static BufferedImage getThreeWayGradient(
int size,
Color primaryLeft,
Color primaryRight,
Color shadeColor) {
BufferedImage image = new BufferedImage(
size, size, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
GradientPaint primary = new GradientPaint(
0f, 0f, primaryLeft, size, 0f, primaryRight);
int rC = shadeColor.getRed();
int gC = shadeColor.getGreen();
int bC = shadeColor.getBlue();
GradientPaint shade = new GradientPaint(
0f, 0f, new Color(rC, gC, bC, 0),
0f, size, shadeColor);
g.setPaint(primary);
g.fillRect(0, 0, size, size);
g.setPaint(shade);
g.fillRect(0, 0, size, size);
g.dispose();
return image;
}
/**
* Presumed to have a layout that shows multiple components.
*/
public static void addGradient(
JPanel p, int s, Color pL, Color pR, Color sh) {
JLabel l = new JLabel(new ImageIcon(getThreeWayGradient(s, pL, pR, sh)));
p.add(l);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JPanel gui = new JPanel(new GridLayout(2,4,1,1));
addGradient(gui,100,Color.YELLOW,Color.RED,Color.GREEN);
addGradient(gui,100,Color.GREEN,Color.YELLOW,Color.RED);
addGradient(gui,100,Color.RED,Color.GREEN,Color.YELLOW);
addGradient(gui,100,Color.BLUE,Color.MAGENTA,Color.PINK);
addGradient(gui,100,Color.WHITE,Color.RED,Color.BLACK);
addGradient(gui,100,Color.RED,Color.GREEN,Color.BLACK);
addGradient(gui,100,Color.BLUE,Color.PINK,Color.BLACK);
addGradient(gui,100,Color.BLUE,Color.CYAN,Color.BLACK);
JOptionPane.showMessageDialog(null, gui);
}
};
SwingUtilities.invokeLater(r);
}
}

Take a look at LinearGradientPaint, it allows you to specify n number of colours and their weights.
Update 1
With a "small" change in requirements, it is debatable if either LinearGradientPaint over GradientPant will have any significant effect in performance.
I highly recommend that you take a look at Harmonic Code. This guy does some really interesting posts, and some on gradients. ;)
Update 2
Knew I'd seen something like it before Bilinear color interpolation.

Related

Changing alpha value of an image

I am trying to change the alpha value of an image, I have the code
public void changeImage (File currentImage) throws IOException {
BufferedImage img = ImageIO.read(currentImage);
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int pixel = img.getRGB(x,y);
Color color = new Color(pixel);
int red = 10;
int green = 20;
int blue = 30;
int alpha = 40;
color = new Color(red, green, blue, alpha);
img.setRGB(x, y, color.getRGB());
}
}
File outputImage = new File(currentImage.getAbsolutePath().substring(0, currentImage.getAbsolutePath().length() - 4) + "_encrypted.png");
ImageIO.write(img, "png", outputImage);
}
The colors change just fine and when I get Java to print the new photo's alpha value, it says it's 40 but it doesn't look less transparent at all. Like the colors obviously change but the transparency does not. Example Like see, it's not less transparent at all, this is my first time with colors.
I have tried to do Color color = new Color(pixel, true); instead but it didn't really change anything.
public void changeImage (File currentImage) throws IOException {
BufferedImage img = ImageIO.read(currentImage);
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int pixel = img.getRGB(x,y);
Color color = new Color(pixel);
int red = 10;
int green = 20;
int blue = 30;
int alpha = 40;
color = new Color(red, green, blue, alpha);
img.setRGB(x, y, color.getRGB());
}
}
File outputImage = new File(currentImage.getAbsolutePath().substring(0, currentImage.getAbsolutePath().length() - 4) + "_encrypted.png");
ImageIO.write(img, "png", outputImage);
}
So, my immediate thoughts are:
Why?!
Did you really want to fill the entire image with a single color?
Does the original image support a alpha based color model?
So, if you really just wanted to fill the image with a single translucent color, you could have simply just done...
BufferedImage translucent = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = translucent.createGraphics();
g2d.setColor(new Color(10, 20, 30, 40));
g2d.fillRect(0, 0, master.getWidth(), master.getHeight());
g2d.dispose();
which would be faster.
If, instead, you "really" wanted to make the image appear transparent, then you should probably have started with something like...
public static BufferedImage changeImage(BufferedImage master) {
BufferedImage img = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int pixel = master.getRGB(x, y);
Color color = new Color(pixel);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
int alpha = 40;
color = new Color(red, green, blue, alpha);
img.setRGB(x, y, color.getRGB());
}
}
return img;
}
This creates a new BufferedImage with a color model which supports transparency. It then converts each pixel of the master image to have a alpha color and updates the new image with it.
But again, you could just do something like...
BufferedImage img = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = alphaed.createGraphics();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.156862745098039f));
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
which would be faster.
Runnable example
So, left, original image, middle, your "modified" code, right, AlphaComposite based result
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
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.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public static BufferedImage changeImage(BufferedImage master) {
BufferedImage img = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int pixel = master.getRGB(x, y);
Color color = new Color(pixel);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
int alpha = 40;
color = new Color(red, green, blue, alpha);
img.setRGB(x, y, color.getRGB());
}
}
return img;
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage modified;
private BufferedImage alphaed;
public TestPane() throws IOException {
master = ImageIO.read(getClass().getResource("/images/MegaTokyo.png"));
modified = changeImage(master);
alphaed = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = alphaed.createGraphics();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.156862745098039f));
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(master.getWidth() * 3, master.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(master, 0, 0, this);
g2d.drawImage(modified, master.getWidth(), 0, this);
g2d.drawImage(alphaed, master.getWidth() * 2, 0, this);
g2d.dispose();
}
}
}
Now, it occurs to me that you might be trying to put a color "overlay" on top of the image
In which case you try doing something like...
BufferedImage colorOverlay = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = colorOverlay.createGraphics();
g2d.setColor(new Color(10, 20, 30, 192));
g2d.fillRect(0, 0, colorOverlay.getWidth(), colorOverlay.getHeight());
g2d.dispose();
alphaed = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
g2d = alphaed.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.drawImage(colorOverlay, 0, 0, this);
g2d.dispose();
which could be simplifed to something like...
alphaed = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
g2d = alphaed.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.75f));
g2d.setColor(new Color(10, 20, 30, 192));
g2d.fillRect(0, 0, alphaed.getWidth(), alphaed.getHeight());
g2d.dispose();
(nb: I tried using 40 as the alpha component, but it made such little difference, I changed it to 192 for demonstration purposes)
Runnable example
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
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.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public static BufferedImage changeImage(BufferedImage master) {
BufferedImage img = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < img.getHeight(); y++) {
for (int x = 0; x < img.getWidth(); x++) {
int pixel = master.getRGB(x, y);
Color color = new Color(pixel);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
int alpha = 40;
color = new Color(red, green, blue, alpha);
img.setRGB(x, y, color.getRGB());
}
}
return img;
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage alphaed;
public TestPane() throws IOException {
master = ImageIO.read(getClass().getResource("/images/MegaTokyo.png"));
//--- This -----
BufferedImage colorOverlay = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = colorOverlay.createGraphics();
g2d.setColor(new Color(10, 20, 30, 192));
g2d.fillRect(0, 0, colorOverlay.getWidth(), colorOverlay.getHeight());
g2d.dispose();
alphaed = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
g2d = alphaed.createGraphics();
g2d.drawImage(master, 0, 0, this);
g2d.drawImage(colorOverlay, 0, 0, this);
g2d.dispose();
//--------------
//--- Or This -----
// alphaed = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
// g2d = alphaed.createGraphics();
// g2d.drawImage(master, 0, 0, this);
// g2d.setComposite(AlphaComposite.SrcOver.derive(0.75f));
// g2d.setColor(new Color(10, 20, 30, 192));
// g2d.fillRect(0, 0, alphaed.getWidth(), alphaed.getHeight());
// g2d.dispose();
//-----------------
}
#Override
public Dimension getPreferredSize() {
return new Dimension(master.getWidth() * 2, master.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(master, 0, 0, this);
g2d.drawImage(alphaed, master.getWidth(), 0, this);
g2d.dispose();
}
}
}
Check the type of the original image that you are loading. The image you've linked is of type 5 (TYPE_3BYTE_BGR).
The definition of TYPE_3BYTE_BGR from Javadocs is as follows:
Represents an image with 8-bit RGB color components, corresponding to
a Windows-style BGR color model) with the colors Blue, Green, and Red
stored in 3 bytes. There is no alpha. The image has a
ComponentColorModel. When data with non-opaque alpha is stored in an
image of this type, the color data must be adjusted to a
non-premultiplied form and the alpha discarded, as described in the
java.awt.AlphaComposite documentation.
Make sure that you are either loading in an image that has a type that supports the alpha channel, or convert your image to one of such a type.
Otherwise, what you are doing is correct.

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.

Create light in JAVA using RadialGradientPaint

Im working on a simple game engine using java.
Im want to make some light in the game and I want to use RadialGradientPaint.
Here is my light class
package engine.graphics;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;
import engine.Main;
import engine.maths.Vector2f;
public class Light
{
private Vector2f pos;
private int radius;
public Light(Vector2f pos, int radius)
{
this.pos = pos;
this.radius = radius;
}
public void render(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
Point2D center = new Point2D.Float(pos.x, pos.y);
float[] dist = {0.9f, 1.0f};
Color[] color = {new Color(0.0f, 0.0f, 0.0f, 0.1f), new Color(0, 0, 0, 255)};
RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, color);
g2d.setPaint(p);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .95f));
g2d.fillRect(0, 0, Main.WIDTH, Main.HEIGHT);
g2d.dispose();
}
}
The problem that i found is that i cant draw more than one light.
How can i modify my code to make more lights?
Thank you..
I propose you this :
package solamda;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
private static final Color transparency = new Color(0, 0, 0, 0);
private static final int WIDTH = 500;
private static final int HEIGHT = 500;
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setMinimumSize(new Dimension(WIDTH, HEIGHT));
f.setLayout(new BorderLayout());
f.add(new JLabel() {
#Override
public void paint(Graphics g) {
super.paint(g);
render(g);
}
});
f.pack();
f.setVisible(true);
}
public static void render(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Point[] lights = { new Point(WIDTH / 2, HEIGHT / 2), new Point(0,0),
new Point(WIDTH / 2+10, HEIGHT / 2), new Point(WIDTH / 2-10, HEIGHT / 2) };
for (Point center : lights) {
paintlight(g2d, center);
}
g2d.dispose();
}
private static void paintlight(Graphics2D g2d, Point center) {
float[] dist = { 0.2f, 1.0f };
Color[] color = { Color.white, transparency };
RadialGradientPaint p = new RadialGradientPaint(center, 10, dist, color);
g2d.setPaint(p);
g2d.fillRect(center.x - 20, center.y - 20, 40, 40);
}
}
You don need to fill whole rect just the part where the light is . So from your code i just extract a method where center is a parameter (call paintlight) then in your method render, i can draw as many ligh as i want ; i simply paint a white hallo arround this point and i keep the transparency in the pattern when i paint it

Gradient problems in Java

In my program I wanted to have a translucent white to transparent gradient on my JFrame to overlay a yellow background. This works fine and it needs to be a white to transparent because of how my settings for the program work for the user. However, when I take the program into college (JRE7 to my JRE6) the gradient goes white to blackish then transparent... It isn't so bad until you start to increase the opacity of the white colour... is there anyway I can fix this?
here is the relevant code from the top of my JFrame code.
public class DictionaryGUI extends JFrame
{
protected JPanel pGradientPane;
//Interface gradient specification
private Color pInterfaceColour = new Color(255, 245, 62);
protected int iDegreeWhite = 180
protected int iDegreeBlack = 0
DictionaryGUI(int iWidth, int iHeight)
{
/*General definitions*/
super(String.format("French Verb Conjugator - Version %s", MainLauncher.version));
setSize(iWidth, iHeight);
new Menu(this);
this.iWidth = iWidth;
this.iHeight = iHeight;
getContentPane().setBackground(pInterfaceColour);
pGradientPane = new JPanel(new GridBagLayout())
{
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics)
{
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0, iDegreeBlack));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane.setOpaque(false);
pGradientPane.setPreferredSize(new Dimension(iWidth - 16, iHeight - 62));
/*components added to pGradientPane here!*/
add(pGradientPane);
}
And the mainclass aswell:
public class MainLauncher
{
static int iHeight = 400;
static int iWidth = 730;
static String version = "0A3B6";
public static void main(String[] args)
{
try
{
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName()))
{
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {e.printStackTrace();}
DictionaryGUI window = new DictionaryGUI(iWidth, iHeight);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationByPlatform(true);
window.setVisible(true);
}
Is it just some difference between JRE6 and JRE7? should I make the bottom colour to white aswell? (was black incase people want to darken the colour at the bottom.)
I can post some screenshots tommorrow if anybody needs them....
Thanks
Jamie
EDIT:
I changed the second (transparent) colour in the gradient to white and it fixes the problem. However, I am still troubled to why the transparent black colour shows through in the middle? it must be something to do with JRE7 because thats where it occurs... maybe they changed something with how transparency in gradients work. Does anybody know how to eliminate this problem while keeping the colour black?
Here is my version of your code as an sscce:
import java.awt.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class MainLauncher {
static int iHeight = 400;
static int iWidth = 730;
static String version = "0A3B6";
public static void main(String[] args) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
DictionaryGUI window = new DictionaryGUI(iWidth, iHeight);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationByPlatform(true);
window.setVisible(true);
}
}
class DictionaryGUI extends JFrame {
protected JPanel pGradientPane;
// Interface gradient specification
private Color pInterfaceColour = new Color(255, 245, 62);
protected int iDegreeWhite = 180;
protected int iDegreeBlack = 0;
DictionaryGUI(int iWidth, int iHeight) {
/* General definitions */
super(String.format("French Verb Conjugator - Version %s",
MainLauncher.version));
setSize(iWidth, iHeight);
getContentPane().setBackground(pInterfaceColour);
pGradientPane = new JPanel() {
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics) {
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255,
255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0,
iDegreeBlack));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane.setOpaque(false);
pGradientPane.setPreferredSize(new Dimension(iWidth - 16, iHeight - 62));
/* components added to pGradientPane here! */
add(pGradientPane);
}
}
But again this doesn't demonstrate your problem. I'm guessing though that your problem is one of using transparent backgrounds with Swing GUI where painting artifacts are not corrected fully. If so, please read what Rob Camick has to say about this on his blog: Backgrounds With Transparency
The problem with the code is this line:
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0, iDegreeBlack));
should be this:
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(255, 245, 62, iDegreeWhite));
Looking back at your question, I see you've basically found the solution - but it's a little different. Here's why:
When blending the colors in the gradient, your blending all aspects of the color: RBGA
You see, until you reach the full second color, you are mixing black into the color gradient and that mix won't be at the full transparency. So 20% of the way down the page, you'll have this color: 204,204,204,144 (that's 80% white, 20% black, and 56% opaque).
The easiest solution is to avoid translucency completely if you're not using it - just blend from the light yellow at the top to the dark yellow at the bottom. It takes less resources this way too.
But since you're using transparency, the solution I've provided uses transparency as well. You'll be blending from the white to the yellow using a consistent transparency.
If you blend from white to white (transparent), you'll have the same problem as before only with white (which will be less noticeable since it's one of the colors you're using): The gradient will have a white "streak" until the second color reaches full transparency.
As far as why it acts different on different JVMs, I'd guess that Oracle may have changed the way alpha's are blended. Better alpha support seems to be something they've been working on for a while, and this is a logical step in that direction. I don't have any proof on this statement though - it's just based on other changes I've seen with alpha's (like transparent windowing).
EDIT
This SSCCE demos both the problem and the solution:
import java.awt.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class TransparencyDemo extends Box{
protected JPanel pGradientPane;
//Interface gradient specification
private Color pInterfaceColour = new Color(255, 245, 62);
protected int iDegreeWhite = 180;
protected int iDegreeBlack = 0;
public TransparencyDemo() {
super(BoxLayout.X_AXIS);
setOpaque(true);
//Incorrect Solution
pGradientPane = new JPanel(new GridBagLayout())
{
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics)
{
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0, iDegreeBlack));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane.setOpaque(false);
add(pGradientPane);
//Correct Solution
JPanel pGradientPane2 = new JPanel(new GridBagLayout())
{
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics)
{
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(255, 245, 62, iDegreeWhite));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane2.setOpaque(false);
add(pGradientPane2);
setBackground(pInterfaceColour);
}
public static void main(String[] args){
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TransparencyDemo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
My guess is that it's about the 'graphics pipeline' that's being used on the different computers.
Java has several different pipelines, here is some information about them.
On my computer I can use the X11 pipeline, or the OpenGL pipeline. With the X11 pipeline the darkness occurs; on OpenGL, it doesn't.
On Windows you can choose from 3 different pipelines, and even then (looking at the link above), there can be differences.
I can't immediately imagine what's the configuration your school has, and why it's different, but you can try to investigate.
You might want to file this difference as a bug.
I have got fatamorgana, I'm sure that GradientPaint is darker and darker and darker, phaaa crazy eye illusion, brrrr
//http://stackoverflow.com/questions/13748810/gradient-problems-in-java/13806210#comment18995490_13806210
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
public class MainLauncher {
private JFrame window = new JFrame();
public MainLauncher() {
GradientPane pane = new GradientPane();
pane.setLayout(new GridLayout(6, 4, 15, 15));
for (int i = 1; i <= 24; i++) {
pane.add(createButton(i));
}
pane.setOpaque(false);
window.add(pane);
RepaintManager.setCurrentManager(new RepaintManager() {
#Override
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
Container con = c.getParent();
while (con instanceof JComponent) {
if (!con.isVisible()) {
return;
}
if (con instanceof GradientPane) {
c = (JComponent) con;
x = 0;
y = 0;
w = con.getWidth();
h = con.getHeight();
}
con = con.getParent();
}
super.addDirtyRegion(c, x, y, w, h);
}
});
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationByPlatform(true);
window.setSize(400, 300);
//window.pack();
window.setVisible(true);
}
private JButton createButton(final int text) {
JButton button = new JButton(Integer.toString(text));
return button;
}
class GradientPane extends JPanel {
private static final long serialVersionUID = 1L;
private final int h = 150;
private BufferedImage img = null;
private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);
public GradientPane() {
paintBackGround(new Color(150, 250, 150));
}
public void paintBackGround(Color g) {
Graphics2D g2 = shadow.createGraphics();
g2.setPaint(g);
g2.fillRect(0, 0, 1, h);
g2.setComposite(AlphaComposite.DstIn);
g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h, new Color(0.1f, 0.8f, 0.8f, 0.5f)));
g2.fillRect(0, 0, 1, h);
g2.dispose();
}
#Override
public void paintComponent(Graphics g) {
if (img == null || img.getWidth() != getWidth() || img.getHeight() != getHeight()) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2 = img.createGraphics();
super.paintComponent(g2);
Rectangle bounds = this.getVisibleRect();
g2.scale(bounds.getWidth(), -1);
g2.drawImage(shadow, bounds.x, -bounds.y - h, null);
g2.scale(1, -1);
g2.drawImage(shadow, bounds.x, bounds.y + bounds.height - h, null);
g2.dispose();
g.drawImage(img, 0, 0, null);
}
}
public static void main(String[] args) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MainLauncher ml = new MainLauncher();
}
});
}
}
As Nick pointed out, the problem is that you are using transparent black rather than transparent white. So the translucent colours are a shade between white and black.
Try replacing with this line in your code:
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(255, 255, 255, iDegreeBlack));

Triangle inside rectangular grids

I have written a code that draws grids and a triangle inside one grid cell. The grid size is increased/decreased when the window is maximized or minimized.
My requirement is that the triangle size should also increase/decrease to fit the grid cell each time the grid size is increased/decreased.
My code is as follows:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Grid extends JPanel {
/**
* #param args
*/
public static void main(String[] args) {
Grid g = new Grid();
JFrame f = new JFrame("Application GUI Window");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
f.getContentPane().add("Center", g);
f.pack();
f.setSize(new Dimension(450,400));
f.show();
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Dimension d = getSize();
g2d.setBackground(getBackground());
g2d.clearRect(0, 0, d.width, d.height);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawGrid(d.width, d.height, g2d);
int[] xPoints = {20,15,25};
int[] yPoints = {15,25,25};
int n = 3;
Polygon triangle = new Polygon(xPoints, yPoints, n);
g.fillPolygon(triangle);
}
private void drawGrid(int width, int height, Graphics2D g2d) {
/* BasicStroke border = new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 0, new float[]{0,1,0,1}, 0);
g2d.setStroke(border);
g2d.drawRect(3,3,width-6,height-6);*/
//horizontal lines
int cellheight = height/10;
int cellwidth = width/5;
for (int j=0;j<height;j=j+cellheight)
{
BasicStroke line = new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 0, new float[]{0,1,0,1}, 0);
g2d.setStroke(line);
g2d.drawLine(0, j, cellwidth*5, j);
}
//vertical lines
for (int i=0;i<width;i=i+cellwidth)
{
BasicStroke line = new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 0, new float[]{0,1,0,1}, 0);
g2d.setStroke(line);
g2d.drawLine(i, 0, i, cellheight*10);
}
}
}
Thanks in advance for your help.
You can tie the coordinates of the triangle to the dimensions of a grid cell. Here is a snippet based on your example:
int cellHeight = d.height/10;
int cellWidth = d.width/5;
int xOffset = cellWidth/6;
int yOffset = cellHeight/6;
int[] xPoints = {cellWidth/2, xOffset, cellWidth - xOffset};
int[] yPoints = {yOffset, cellHeight - yOffset, cellHeight - yOffset};
Polygon triangle = new Polygon(xPoints, yPoints, xPoints.length);
Note that in Swing you usually should override paintComponent() rather than paint(), unless in some special cases. See A Closer Look at the Paint Mechanism for more details.
Also note that show() is deprecated in favor of setVisible(). You can replace it with: setVisible(true)

Categories