[Advanced-java] Non-rectangular AWT button: can't get background to
redraw
Alexander Farber
alexander.farber at gmail.com
Wed May 3 06:34:06 PDT 2006
Hello,
I'm struggling since several days, trying to create
a custom translucent button, based on an AWT Canvas.
My problem is that when the button's state change
(for example when I click on it and its surface should
be drawn a bit lower and without a shadow) then
I can't get the background to be repainted and thus
I have artefacts near the button.
For background I've tried both subclassing a Frame
and paint()ing on its surface and also I've tried a
Frame with a custom LayoutManager which would
put (by calling setBounds() in its layoutContainer())
a custom background Canvas underneath the button.
Nothing helps :-( I've also downloaded j2se 1.5.0
source code from java.sun.com and looked at the
Container.java, (Sun)GraphicsCallBack.java etc...
I've created a test case for your convenience.
Please compile it by "javac TransButton" and
run by "java -classpath . TransButton" and you'll
see what I mean by the "drawing artifacts" there.
In the test case below I've replaced the translucent
colors (0x80......) by opaque ones (0xFF......)
because it demonstrates the problem anyway.
I've tried removing update(), calling invalidate() etc...
Just try my code and give me your good ideas! ;-)
Thank you
Alex
// A custom translucent button for http://preferans.de
// Usage: java TransButton.java && java -classpath . TransButton
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class TransButton extends Canvas
{
// the shadow offset
private static final int OFFSET = 8;
// the 4 possible button states
private static final int ENABLED = 0;
private static final int SELECTED = 1;
private static final int PRESSED = 2;
private static final int DISABLED = 3;
private int state = ENABLED;
private String label;
private static Image dark, lite, shadow;
private ActionListener listener;
public TransButton(String label) {
this.label = label;
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
public void setBounds(int x, int y, int w, int h) {
System.err.println("setBounds(" + x + ", " +
y + ", " + w + ", " + h + ") on " + label);
super.setBounds(x, y, w, h);
releaseImages();
}
public void createImages(int w, int h) {
System.out.println("createImages(" + w + ", " + h + ")");
h -= OFFSET;
w -= OFFSET;
if (w <= 0 || h <= 0)
return;
int[] pixels = new int[w * h];
for (int i = 0; i < pixels.length; i++)
pixels[i] = 0xFF008000;
//pixels[i] = 0x80008000;
dark = createImage(new
MemoryImageSource(w, h, pixels, 0, w));
pixels = new int[w * h];
for (int i = 0; i < pixels.length; i++)
pixels[i] = 0xFF80FF80;
//pixels[i] = 0x8080FF80;
lite = createImage(new
MemoryImageSource(w, h, pixels, 0, w));
pixels = new int[w * h];
for (int i = 0; i < pixels.length; i++)
pixels[i] = 0xFF808080;
//pixels[i] = 0x20000000;
shadow = createImage(new
MemoryImageSource(w, h, pixels, 0, w));
}
private static void releaseImages() {
if (dark != null) {
dark.flush();
dark = null;
}
if (lite != null) {
lite.flush();
lite = null;
}
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
int w = getSize().width;
int h = getSize().height;
// catch negative dimensions or out of memory
try {
if (dark == null || lite == null || shadow==null)
createImages(w, h);
if (state != PRESSED) {
g.drawImage(shadow, OFFSET, OFFSET, this);
g.drawImage(
(state == ENABLED ? dark : lite),
0, 0, this);
// draw the label over the translucent image
g.drawString(label, h / 3, h * 2 / 3);
} else {
g.drawImage(
(state == ENABLED ? dark : lite),
OFFSET, OFFSET, this);
// draw the label over the translucent image
g.drawString(label, OFFSET + h / 3,
OFFSET + h * 2 / 3);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void addActionListener(ActionListener l) {
listener = AWTEventMulticaster.add(listener, l);
}
public void removeActionListener(ActionListener l) {
listener = AWTEventMulticaster.remove(listener, l);
}
protected void processMouseEvent(MouseEvent ev) {
switch(ev.getID()) {
case MouseEvent.MOUSE_ENTERED:
state = SELECTED;
break;
case MouseEvent.MOUSE_EXITED:
state = ENABLED;
break;
case MouseEvent.MOUSE_PRESSED:
state = PRESSED;
break;
case MouseEvent.MOUSE_CLICKED:
if (listener != null)
listener.actionPerformed(
new ActionEvent(this,
ActionEvent.ACTION_PERFORMED,
label));
state = ENABLED;
break;
}
//invalidate();
//getParent().repaint();
repaint();
}
public Dimension getMinimumSize() {
FontMetrics metrics = getFontMetrics(getFont());
int w = metrics.stringWidth(label);
int h = metrics.getHeight();
return new Dimension(w, h);
}
public Dimension getPreferredSize() {
FontMetrics metrics = getFontMetrics(getFont());
int w = metrics.stringWidth(label) * 3 / 2;
int h = metrics.getHeight() * 3 / 2;
return new Dimension(w, h);
}
public static void main(String args[]) {
TestFrame tf = new TestFrame("TransButton Test");
tf.setFont(new Font("SansSerif", Font.BOLD, 24));
tf.setForeground(Color.white);
tf.setBackground(Color.yellow);
tf.setSize(400, 300);
tf.setVisible(true);
}
}
class TestFrame extends Frame implements ActionListener {
//Button b1, b2, b3;
TransButton b1, b2, b3;
public TestFrame(String title) {
super(title);
// use GridLayout because the dimensions of the TransButtons
// must be same (as they use same static images dark+lite)
GridLayout layout = new GridLayout(3, 1);
layout.setVgap(10);
setLayout(layout);
//b1 = new Button("Button 1");
//b2 = new Button("Button Two");
//b3 = new Button("Button Three");
b1 = new TransButton("Button 1");
b2 = new TransButton("Button Two");
b3 = new TransButton("Button Three");
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
add(b1);
add(b2);
add(b3);
}
public void actionPerformed(ActionEvent ev) {
Component srcComp = (Component) ev.getSource();
String args = ev.getActionCommand();
System.out.println(ev + ", args: " + args);
}
public void update(Graphics g) {
super.update(g);
//paint(g);
}
public void paint(Graphics g) {
int w = getSize().width;
int h = getSize().height;
g.setColor(Color.red);
g.fillRect(0, 0, w, h);
g.setColor(Color.white);
g.drawLine(0, 0, w, h);
g.drawLine(0, h, w, 0);
//super.paint(g);
//paintComponents(g);
}
}
More information about the Advanced-java
mailing list