I have a JLayeredPane with 4 layers added to it. 1 base layer, which is opaque and three 'transparent' layers (setOpaque(false)).
The problem is that although the panels are drawn onto, with every refresh a gray color is shown. The same thing happens if there is no refresh happening. In other words, instead of showing whatever was drawn onto the base layer, a gray color is shown, I assume this is from one of the layers above.
Here is a SSCCE - I'm not sure if this is short enough but it shows my problem.
public class SSCCE extends JLayeredPane{
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(950, 600);
frame.add(new SSCCE());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
// private fields
private boolean drawInitial = true;
private boolean drawn = false;
private JPanel overlay, base, iconPanel, middle;
private BufferedImage baseBuffer, midBuffer, overlayBuffer, iconBuffer;
private boolean updateInit = true;
private Rectangle2D stored = new Rectangle2D.Double(60, 60, 40, 100);
public SSCCE() {
setBorder(new LineBorder(Color.BLACK));
setDoubleBuffered(false);
setOpaque(true);
setSize(new Dimension(950, 600));
setPreferredSize(new Dimension(950, 600));
base = new JPanel();
base.setBackground(new Color(0,0,0,0));
base.setSize(new Dimension(getWidth(), getHeight()));
this.add(base, new Integer(0));
middle = new JPanel();
middle.setSize(new Dimension(getWidth(), getHeight()));
middle.setBackground(new Color(0,0,0,0));
middle.setOpaque(false);
this.add(middle, new Integer(1));
overlay = new JPanel();
overlay.setBackground(new Color(0,0,0,0));
overlay.setOpaque(false);
overlay.setSize(new Dimension(getWidth(), getHeight()));
this.add(overlay, new Integer(2));
iconPanel = new JPanel();
iconPanel.setBackground(new Color(0,0,0,0));
iconPanel.setSize(getWidth(), getHeight());
iconPanel.setOpaque(false);
this.add(iconPanel, new Integer(3));
}
public void update() {
if(updateInit){
checkBuffer();
updateInit = false;
}
drawInfoRect();
drawIcon();
highlightPath(stored);
}
public void render() {
if (drawInitial) {
Graphics2D baseGraphics = (Graphics2D) base.getGraphics();
baseGraphics.drawImage(baseBuffer, 0, 0, null);
}
setResistanceColor((Graphics2D)baseBuffer.getGraphics());
middle.getGraphics().drawImage(midBuffer, 0, 0, null);
iconPanel.getGraphics().drawImage(iconBuffer, 0, 0, null);
drawInfoRect();
base.getGraphics().drawImage(baseBuffer, 0, 0, null);
if (drawn) {
overlay.getGraphics().drawImage(overlayBuffer, 0, 0, null);
}
repaint();
}
// /**
// * draws the appropriate colour
// */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
update();
render();
}
/**
* sets the appropriate colours according to the resistance
* #param g2
*/
private void setResistanceColor(Graphics2D g2) {
Rectangle2D sp = new Rectangle2D.Double(50,50, 50, 50);
g2.setColor(Color.GREEN);
g2.fill(sp);
g2.setColor(Color.BLACK);
}
/**
* checks if there already exists an image to buffer with
*/
private void checkBuffer() {
if (baseBuffer == null) {
baseBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
// background color
Graphics2D g2 = (Graphics2D) baseBuffer.getGraphics();
g2.setColor(Color.decode("#729fcf"));
Rectangle2D rect = new Rectangle2D.Double(0, 0, baseBuffer.getWidth(), baseBuffer.getHeight());
g2.fill(rect);
}
if (midBuffer == null) {
midBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
// background color
Graphics2D g2 = (Graphics2D) midBuffer.getGraphics();
g2.setColor(Color.RED);
Rectangle2D rect = new Rectangle2D.Double(0, 0, midBuffer.getWidth(), midBuffer.getHeight());
g2.fill(rect);
}
if (overlayBuffer == null) {
overlayBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
}
if (iconBuffer == null) {
iconBuffer = (new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB));
}
}
public void highlightPath(Shape enlighten) {
Area area = new Area();
area.add(new Area(enlighten));
// clearing image before drawing
Graphics2D midBufferG = (Graphics2D) midBuffer.getGraphics();
clearImage(midBufferG);
midBufferG.setColor(Color.white);
// adds a transparent overlay
midBufferG.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));
midBufferG.fill(area);
}
public void drawIcon() {
Graphics2D iconG = (Graphics2D) iconBuffer.getGraphics();
clearImage(iconG);
}
public void drawInfoRect() {
Graphics2D graph = (Graphics2D) overlayBuffer.getGraphics();
Rectangle2D visible = getVisibleRect();
int boxX = (int) (visible.getX() + 50);
int boxY = (int) (visible.getY() + 450);
RoundRectangle2D rect = new RoundRectangle2D.Double(boxX, boxY, 200, 150, 25, 25);
graph.setColor(Color.decode("#729fcf").darker());
graph.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
graph.fill(rect);
graph.setColor(Color.BLACK);
drawn = true;
}
private void clearImage(Graphics2D graph){
graph.setComposite(AlphaComposite.Clear);
graph.fillRect(0, 0, overlayBuffer.getWidth(), overlayBuffer.getHeight());
graph.setComposite(AlphaComposite.SrcOver);
}
}
It might be some basic mistake I made. Thanks for your help!
One of the previously suggested answers actually solved my question, but for some reason they deleted their answer.
Setting the Background of my panels to setBackground(new
Color(0,0,0,0)); solved my problems.
According to the person that suggested this, the cause of that is the fact that JComponent may or may not draw transparent if not explicitly specified.
Thanks again!
Related
I am trying to create a gradient paint for text that goes from the top of the word to the bottom, not from left to right. I was actually able to achieve this from the help of this link here. They took the shape of the text, and painted it on the panel. I simply edited their code and was able to apply the affect I am looking for. Here is what I edited their paint method to (where s is a Shape):
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.translate(100, 150);
Rectangle2D r = s.getBounds2D();
int x = (int) r.getX();
int y = (int) r.getY();
int h = (int) r.getHeight();
GradientPaint gp = new GradientPaint(x, y, Color.MAGENTA, x, h, Color.ORANGE);
g2.setPaint(gp);
g2.fill(s);
}
This worked, but this approach is overriding a paintComponent method of a JPanel. I am trying to recreate this by a new GradientLabel Class that extends JLabel. The issue I am having is that the g2d.fill(s) method is drawing the shape somewhere above the label, seemingly out of reach. I don't understand why it is doing this. Perhaps its from casting Graphics2D g.create();? I have had to add the g2.translate(x,y) method to pull the shape down into a viewable location.
I guess I have 2 questions.
Why doesn't the g2.fill(s) draw the shape over the text that was drawn by the JLabel super method? Could this be because of my layout manager?
Is this approach even the way I should go? Is there an easier way to apply a vertical paint gradient to text?
Here is the minimal code for testing:
public class test extends JFrame {
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
test frame = new test();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 516, 360);
contentPane = new JPanel();
contentPane.setBorder(null);
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[]{0, 0};
gbl_contentPane.rowHeights = new int[]{0, 100, 0};
gbl_contentPane.columnWeights = new double[]{1.0, Double.MIN_VALUE};
gbl_contentPane.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE};
contentPane.setLayout(gbl_contentPane);
Component verticalStrut = Box.createVerticalStrut(20);
GridBagConstraints gbc_verticalStrut = new GridBagConstraints();
gbc_verticalStrut.insets = new Insets(0, 0, 5, 0);
gbc_verticalStrut.gridx = 0;
gbc_verticalStrut.gridy = 0;
contentPane.add(verticalStrut, gbc_verticalStrut);
GradientLabel lblTest = new GradientLabel("TEST");
lblTest.setHorizontalAlignment(SwingConstants.CENTER);
lblTest.setGradientColors(Color.GREEN, Color.WHITE);
lblTest.setFont(new Font("Tahoma", Font.PLAIN, 70));
GridBagConstraints gbc_lblTest = new GridBagConstraints();
gbc_lblTest.fill = GridBagConstraints.BOTH;
gbc_lblTest.gridx = 0;
gbc_lblTest.gridy = 1;
contentPane.add(lblTest, gbc_lblTest);
}
public class GradientLabel extends JLabel {
private Color c1;
private Color c2;
public GradientLabel(String text) {
setText(text);
this.setOpaque(false);
}
public void setGradientColors(Color c1, Color c2) {
this.c1 = c1;
this.c2 = c2;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Font f = getFont();
GlyphVector v = f.createGlyphVector(getFontMetrics(f).getFontRenderContext(), getText());
Shape s = v.getOutline();
Rectangle2D r = s.getBounds2D();
int x = (int) r.getX();
int y = (int) r.getY();
int h = (int) r.getHeight();
int w = (int) r.getWidth();
//without this the shape is drawn almost out of view
g2d.translate(x, h);
g2d.drawRect(x, y, w, h);
//for some reason using only h as the second y doesn't show much of the second color.
//Subtracting 60 arbitrarily showed more of the second color in the gradient.
//Bonus points for an explanation on why that happens.
GradientPaint gp = new GradientPaint(x, y, c1, x, h - 60, c2);
g2d.setPaint(gp);
g2d.fill(s);
}
}
}
Well I was able to answer my own question! First time for everything I guess.
I tracked the code on the JLabel back to the class where it was actually being drawn on the screen to the BasicLabelUI Class. I studied and determined that if I could build a new class that extends this class, I could simply override the painting portion of this class. After testing and determining the best gradient that fully paints both colors from the top of the text to the bottom, this is what I came up with:
public class SBLabelUI extends BasicLabelUI {
#Override
protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
if (l instanceof GradientLabel) {
GradientLabel gl = (GradientLabel) l;
Graphics2D g2d = (Graphics2D) g;
Font f = gl.getFont();
int h = gl.getFontMetrics(f).getHeight();
GradientPaint gp = new GradientPaint(textX, textY, gl.c2, textX, Math.abs(textY-h), gl.c1);
g2d.setPaint(gp);
g2d.drawString(s, textX, textY);
} else {
super.paintEnabledText(l, g, s, textX, textY);
}
}
}
And in my Constructor for the gradient Label, i simply set the UI:
public GradientLabel(String text) {
setText(text);
this.setOpaque(false);
setUI(new SBLabelUI());
}
It works charmingly:
In my code after i added code to paintComponent() when i run it, all the JLabel, textfields, and buttons disappear the textfields and buttons reappear when i click on them while the program is running but i still can't see any of the JLabels.
I hope it is something silly i have commented out the code in the paintComponent() method that seems to cause this error.
public class snowBoarding extends JFrame {
private JButton getReset() {
if (Reset == null) {
Reset = new JButton();
Reset.setBounds(new Rectangle(162, 411, 131, 39));
Reset.setFont(new Font("Dialog", Font.BOLD, 18));
Reset.setText("Reset");
Reset.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e){
textField_1.setText("0");
textField_2.setText("0");
textField_3.setText("0");
textField_4.setText("0");
textField_5.setText("0");
textField_6.setText("0");
textField_7.setText("0");
textField_8.setText("0");
textField_9.setText("0");
textField_10.setText("0");
textField_11.setText("0");
textField.setText("0");
total_1.setText("0");
total_2.setText("0");
Overall.setText("0");
DrawPanel.clear(DrawPanel.getGraphics());
DrawPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
}
});
}
return Reset;
}
public JButton getButton_calc_draw() {
if (Button_calc_draw == null) {
Button_calc_draw = new JButton();
Button_calc_draw.setBounds(303, 411, 131, 39);
Button_calc_draw.setFont(new Font ("Dialog", Font.BOLD, 18));
Button_calc_draw.setText("Draw");
Button_calc_draw.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
// Get values from the text fields
run_1[0] = Integer.parseInt(textField.getText());
run_1[1] = Integer.parseInt(textField_1.getText());
run_1[2] = Integer.parseInt(textField_2.getText());
run_1[3] = Integer.parseInt(textField_3.getText());
run_1[4] = Integer.parseInt(textField_4.getText());
run_1[5] = Integer.parseInt(textField_5.getText());
for (int i = 0; i < run_1.length; i++) {
temp[i] = run_1[i];
}
Arrays.sort(temp);
for (int i = 1; i < (temp.length -1) ; i++){
avg1+=temp[i];
}
avg1 = avg1/4;
run_2[0] = Integer.parseInt(textField_6.getText());
run_2[1] = Integer.parseInt(textField_7.getText());
run_2[2] = Integer.parseInt(textField_8.getText());
run_2[3] = Integer.parseInt(textField_9.getText());
run_2[4] = Integer.parseInt(textField_10.getText());
run_2[5] = Integer.parseInt(textField_11.getText());
for (int i = 0; i < run_2.length; i++) {
temp[i] = run_2[i];
}
Arrays.sort(temp);
for (int i = 1; i < (temp.length -1) ; i++){
avg2+=temp[i];
}
avg2 = avg2/4;
if (avg1 > avg2){
OverallScore = avg1;
}
else {
OverallScore = avg2;
}
total_1.setText(Integer.toString(avg1));
total_2.setText(Integer.toString(avg2));
Overall.setText(Integer.toString(OverallScore));
DrawPanel.repaint();
}
// Transfer the image from the BufferedImage to the JPanel to make it visible.
;
});
}
return Button_calc_draw;
}
}
});
}
return Reset;
}
private myJPanel getDrawPanel() {
if (DrawPanel == null) {
DrawPanel = new myJPanel();
DrawPanel.setLayout(new GridBagLayout());
DrawPanel.setBounds(new Rectangle(258, 39, 326, 361));
DrawPanel.setBackground(Color.white);
DrawPanel.setEnabled(true);
DrawPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
//Instantiate the BufferedImage object and give it the same width
// and height as that of the drawing area JPanel
img = new BufferedImage(DrawPanel.getWidth(),
DrawPanel.getHeight(),
BufferedImage.TYPE_INT_RGB);
//Get its graphics context. A graphics context of a particular object allows us to draw on it.
g2dImg = (Graphics2D)img.getGraphics();
//Draw a filled white coloured rectangle on the entire area to clear it.
g2dImg.setPaint(Color.WHITE);
g2dImg.fill(new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
}
return DrawPanel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
snowBoarding thisClass = new snowBoarding();
thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisClass.setVisible(true);
}
});
}
public snowBoarding() {
super();
setResizable(false);
getContentPane().setLayout(null);
initialize();
}
private void initialize() {
this.setSize(600, 500);
this.setContentPane(getJContentPane());
this.setTitle("Snowboarding Score Calculator");
this.setResizable(false);
this.setVisible(true);
}
}
class myJPanel extends JPanel {
BufferedImage img;
Graphics2D g2dImg;
private static final long serialVersionUID = 1L;
private Rectangle2D.Double rectangle;
public void paintComponent(Graphics g) {
//Must be called to draw the JPanel control.
// As a side effect, it also clears it.
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
rectangle = new Rectangle2D.Double(0, 260-score[0] * 2, 25, score[0] * 2);
g2D.setPaint(Color.blue);
g2D.fill(rectangle);
g2D.draw(rectangle);
}
protected void clear(Graphics g) {
super.paintComponent(g);
// Also clear the BufferedImage object by drawing a white coloured filled rectangle all over.
g2dImg.setPaint(Color.WHITE);
g2dImg.fill(new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
}
}
edit: removing unnecessary code
i need the repaint to draw rectangles using the run_1 and the run_2 array as the x or y values after i click draw and the reset to return the painted image back to a white slate.
draw button --> draws the graph
reset button --> removes the graph so that a new graph can be created.
You shall not use g2dImg in paintComponent(), but g instead (the parameter received by method paintComponent()). More precisely, ((Grpahics2D)g) instead of g2dImg.
g2dImg doesn't seem to be initialized in your code posted here, maybe you have done it somewhere...
More generally, you shall always use the Graphics instance you received in paint methods (casting it to Graphics2D if needed). You shall not try to reuse/share/store instances of Graphics.
The same applies for the clear() method.
Here is an example of how to rewrite this paintComponent() method:
private boolean shallPaint = false;
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (shallPaint) {
Graphics2D g2D = (Graphics2D) g;
rectangle = new Rectangle2D.Double(0, 260-score1 * 2, 25, score1 * 2);
g2D.setPaint(Color.blue);
g2D.fill(rectangle);
g2D.draw(rectangle);
}
}
public void setShallPaint(boolean pShallPaint) {
shallPaint = pShallPaint;
}
Then simply call myJPanel.repaint() to repaint it.
You shall replace, in your reset button:
DrawPanel.clear(DrawPanel.getGraphics());
with:
DrawPanel.setShallPaint(false);
DrawPanel.repaint();
And in Button_calc_draw:
DrawPanel.setShallPaint(true);
DrawPanel.repaint();
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));
Im creating a Java applet for my website where users can draw an image by clicking and dragging the mouse. I then want to convert this image to a black and white image, in the form of a two dimensional array with 1's and 0's. I have created the drawing part but I'm not sure how to go from the applet to the two dimensional array. Any suggestions?
The first thing you need to do is convert the screen to a BufferedImage, this will allow you access to the pixel data.
Something like...
BufferedImage buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = buffer.createGraphics();
printAll(g2d);
g2d.dispose();
Next, you need to convert that to a black and white image...
BufferedImage bwImage = new BufferedImage(
buffer .getWidth(),
buffer .getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g2d = bwImage.createGraphics();
g2d.drawImage(buffer , 0, 0, null);
g2d.dispose();
Now, you can access the raw data...
for (int y = 0; y < bwImage.getHeight(); y++) {
for (int x = 0; x < bwImage.getWidth(); x++) {
Color color = new Color(bwImage.getRGB(x, y));
// You should only be interested in colors of 0,0,0 RGB
}
}
UPDATED with Example
This is an example I adopted from a previous question
public class MyPaint {
public static void main(String[] args) {
new MyPaint();
}
public MyPaint() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 600);
frame.getContentPane().setBackground(Color.DARK_GRAY);
frame.setLocationRelativeTo(null);
frame.setLayout(new GridBagLayout());
final PaintSurfacePane surface = new PaintSurfacePane();
JPanel pnlButtons = new JPanel(new GridBagLayout());
pnlButtons.setOpaque(false);
JButton saveFromImage = new JButton("Save From Image");
JButton saveFromGraphics = new JButton("Save From Grpahics");
pnlButtons.add(saveFromImage);
pnlButtons.add(saveFromGraphics);
saveFromGraphics.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BufferedImage buffer = new BufferedImage(surface.getWidth(), surface.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = buffer.createGraphics();
surface.printAll(g2d);
g2d.dispose();
renderBlackWhite(buffer);
}
});
saveFromImage.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BufferedImage buffer = new BufferedImage(surface.getWidth(), surface.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = buffer.createGraphics();
g2d.drawImage(surface.getPaintSurface(), 0, 0, surface);
g2d.dispose();
renderBlackWhite(buffer);
}
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
frame.add(surface, gbc);
gbc.gridy++;
gbc.weighty = 0;
frame.add(pnlButtons, gbc);
frame.setVisible(true);
}
});
}
public static void renderBlackWhite(BufferedImage buffer) {
BufferedImage bwImage = new BufferedImage(
buffer.getWidth(),
buffer.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g2d = bwImage.createGraphics();
g2d.drawImage(buffer, 0, 0, null);
g2d.dispose();
JFrame frame = new JFrame("Black and White");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JLabel(new ImageIcon(bwImage)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class PaintSurfacePane extends JPanel {
private BufferedImage paintSurface;
public PaintSurfacePane() {
// This will produce a buffered image that will render faster...
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
paintSurface = gc.createCompatibleImage(400, 400, Transparency.OPAQUE);
Graphics2D g2d = paintSurface.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, 400, 400);
g2d.dispose();
MouseHandler handler = new MouseHandler();
addMouseListener(handler);
addMouseMotionListener(handler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(paintSurface, 0, 0, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
#Override
public Dimension getMaximumSize() {
return getPreferredSize();
}
public BufferedImage getPaintSurface() {
return paintSurface;
}
protected class MouseHandler extends MouseAdapter implements MouseMotionListener {
private Point startPoint;
#Override
public void mouseReleased(MouseEvent e) {
startPoint = null;
}
#Override
public void mouseDragged(MouseEvent e) {
Point endPoint = e.getPoint();
if (startPoint != null) {
Graphics2D g2d = paintSurface.createGraphics();
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Float(startPoint, endPoint));
g2d.dispose();
repaint();
}
startPoint = endPoint;
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
}
}
Essentially it uses the "direct from buffer" approach and the "paint" approach to convert the graphics to black and white.
I am trying to create a button that has a custom shape (hexagon), but otherwise acts like a normal JButton would (that is, works with an ActionListener).
I have created a class that extends AbstractButton, but it doesn't seem to be sending events to the ActionListener when I click it. If I change the class to extend JButton it works perfectly, but it screws up the way the button is displayed. I'm assuming that there is a method that I need to override to get it to fire events, but I can't figure out what it is.
If you want to create a CustomButtonUI then you have to look
deepest to the BasicXxxUI.
overide List of Colors from JButton
Note there isn't paintComponent(). It's wrong, just use the paint() method,
Below is just a simple example if that is possible (for Metal JButton). Note just for Metal LaF, I'm so lazy and there isn't something about override paintText, paintIcon, paintFocus, paintBorder (for all funcionalities you have to check available methods from BasicButtonUI), and something I put to the ButtonModel, just for my enjoyment.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalButtonUI;
public class TextAreaInButton {
private JFrame frame = new JFrame("sssssssss");
private JButton tip1Null = new JButton(" test button ");
public TextAreaInButton() {
Border line, raisedbevel, loweredbevel, title, empty;
line = BorderFactory.createLineBorder(Color.black);
raisedbevel = BorderFactory.createRaisedBevelBorder();
loweredbevel = BorderFactory.createLoweredBevelBorder();
title = BorderFactory.createTitledBorder("");
empty = BorderFactory.createEmptyBorder(1, 1, 1, 1);
final Border compound;
Color crl = (Color.blue);
compound = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl));
Color crl1 = (Color.red);
final Border compound1;
compound1 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl1));
Color crl2 = (Color.black);
final Border compound2;
compound2 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl2));
tip1Null.setFont(new Font("Serif", Font.BOLD, 14));
tip1Null.setForeground(Color.darkGray);
tip1Null.setPreferredSize(new Dimension(50, 30));
tip1Null.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
tip1Null.setBorderPainted(true);
tip1Null.setFocusPainted(false);
tip1Null.setBorder(compound);
tip1Null.setHorizontalTextPosition(SwingConstants.CENTER);
tip1Null.setVerticalTextPosition(SwingConstants.BOTTOM);
tip1Null.setUI(new ModifButtonUI());
tip1Null.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (model.isRollover()) {
tip1Null.setBorder(compound1);
} else {
tip1Null.setBorder(compound);
}
if (model.isPressed()) {
tip1Null.setBorder(compound2);
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tip1Null, BorderLayout.CENTER);
frame.setLocation(150, 150);
frame.setPreferredSize(new Dimension(310, 75));
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TextAreaInButton taib = new TextAreaInButton();
}
});
}
}
class OldRoundedBorderLine extends AbstractBorder {
private final static int MARGIN = 5;
private static final long serialVersionUID = 1L;
private Color color;
OldRoundedBorderLine(Color clr) {
color = clr;
}
public void setColor(Color clr) {
color = clr;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(color);
g.drawRoundRect(x, y, width, height, MARGIN, MARGIN);
}
#Override
public Insets getBorderInsets(Component c) {
return new Insets(MARGIN, MARGIN, MARGIN, MARGIN);
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = MARGIN;
insets.top = MARGIN;
insets.right = MARGIN;
insets.bottom = MARGIN;
return insets;
}
}
class ModifButtonUI extends MetalButtonUI {
private static final ModifButtonUI buttonUI = new ModifButtonUI();
ModifButtonUI() {
}
public static ComponentUI createUI(JComponent c) {
return new ModifButtonUI();
}
#Override
public void paint(Graphics g, JComponent c) {
final Color color1 = new Color(230, 255, 255, 0);
final Color color2 = new Color(255, 230, 255, 64);
final Color alphaColor = new Color(200, 200, 230, 64);
final Color color3 = new Color(
alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 0);
final Color color4 = new Color(
alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 64);
super.paint(g, c);
Graphics2D g2D = (Graphics2D) g;
GradientPaint gradient1 = new GradientPaint(
0.0F, (float) c.getHeight() / (float) 2, color1, 0.0F, 0.0F, color2);
Rectangle rec1 = new Rectangle(0, 0, c.getWidth(), c.getHeight() / 2);
g2D.setPaint(gradient1);
g2D.fill(rec1);
GradientPaint gradient2 = new GradientPaint(
0.0F, (float) c.getHeight() / (float) 2, color3, 0.0F, c.getHeight(), color4);
Rectangle rec2 = new Rectangle(0, c.getHeight() / 2, c.getWidth(), c.getHeight());
g2D.setPaint(gradient2);
g2D.fill(rec2);
}
#Override
public void paintButtonPressed(Graphics g, AbstractButton b) {
paintText(g, b, b.getBounds(), b.getText());
g.setColor(Color.red.brighter());
g.fillRect(0, 0, b.getSize().width, b.getSize().height);
}
public void paintBorder(Graphics g) {
}
#Override
protected void paintFocus(Graphics g, AbstractButton b,
Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
}
}
You will have to extend JButton class not AbstractButton. Try the following things and you will get idea.
The first move is to subclass JButton.
Then, in your subclass, start by redefining the paintComponent(Graphics) method. If you want any changes.
Then, override paintBorder(Graphics) to give it a shape of hexagon.
I know this question has been answered, but you might want to look at using the built-in methods, and using images to draw your button in different states.
Here is a bit of code I used to generate a custom button.
BufferedImage startButton = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup.png"));
BufferedImage startButtonHover = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup_hover.png"));
BufferedImage startButtonActive = ImageIO.read(getClass().getResource("/icons/standard/buttons/start_backup_active.png"));
JButton startBackupButton = new JButton(new ImageIcon(startButton));
startBackupButton.setRolloverIcon(new ImageIcon(startButtonHover));
startBackupButton.setPressedIcon(new ImageIcon(startButtonActive));
startBackupButton.setBorder(BorderFactory.createEmptyBorder());
startBackupButton.setContentAreaFilled(false);
startBackupButton.setFocusable(false);
You can then add an action listener to it as normal.
try a Jlabel and use an image for any shape!!
JLabel lbl = new JLabel("");
lbl.setIcon(new ImageIcon("shape.png"));
lbl.setBounds(548, 11, 66, 20);
contentPane.add(lbl);
lbl.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
System.exit(0);
}
});