Reputation: 783
I have custom arrow class, which extends BasicArrowButton. It is constructed and displayed the way I need, but then, when it is repainted (mouse over, other tab clicked, etc) arrow disappeares. How can I fix it?
public class CustomArrow extends BasicArrowButton {
private transient Color shadow = new Color(241, 241, 241);
private transient Color dark = new Color(150, 150, 150);
private static int defaultSize = 10;
/** The Polygon that points up. */
private static Polygon upIcon = new Polygon(new int[] { 0, 5, 9 },
new int[] { 7, 2, 7 }, 3);
/** The Polygon that points down. */
private static Polygon downIcon = new Polygon(new int[] { 1, 8, 19 },
new int[] { 3, 13, 3 }, 3);
/** The Polygon that points left. */
private static Polygon leftIcon = new Polygon(new int[] { 7, 3, 7 },
new int[] { 1, 5, 9 }, 3);
/** The Polygon that points right. */
private static Polygon rightIcon = new Polygon(new int[] { 3, 7, 3 },
new int[] { 1, 5, 9 }, 3);
private transient Border buttonBorder = new Border()
{
public Insets getBorderInsets(Component c)
{
return new Insets(2, 2, 2, 2);
}
public boolean isBorderOpaque()
{
return true;
}
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
{
Color saved = g.getColor();
g.setColor(shadow);
g.drawLine(x + 1, y, x + w - 1, y);
g.setColor(dark);
g.drawLine(x, y, x, y + h + 2);
g.setColor(shadow);
g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
g.setColor(shadow);
g.drawLine(x + 1, y + h - 1, x + w, y + h - 1);
g.setColor(saved);
}
};
@Override
public synchronized void addKeyListener(KeyListener l) {
super.addKeyListener(l);
}
@Override
public void addActionListener(ActionListener l) {
super.addActionListener(l);
}
public CustomArrow(int direction)
{
super(direction);
setBorder(buttonBorder);
setDirection(direction);
this.setRolloverEnabled(false);
}
public CustomArrow(int direction, Color background, Color shadow, Color darkShadow, Color highlight)
{
this(direction);
setBackground(background);
}
@Override
public void paintTriangle(Graphics g, int x, int y, int size, int direction, boolean isEnabled)
{
Polygon arrow = null;
switch (direction)
{
case NORTH:
arrow = upIcon;
break;
case SOUTH:
arrow = downIcon;
break;
case EAST:
case RIGHT:
arrow = rightIcon;
break;
case WEST:
case LEFT:
arrow = leftIcon;
break;
}
int[] xPoints = arrow.xpoints;
int[] yPoints = arrow.ypoints;
int x1;
int y1;
int x2;
int y2;
x1 = y1 = x2 = y2 = 0;
x = x - 1;
if (size != defaultSize)
{
float scale = size * 1f / defaultSize;
for (int i = 0; i < 3; i++)
{
xPoints[i] *= scale;
yPoints[i] *= scale;
}
}
g.translate(x, y);
switch (direction)
{
case NORTH:
x1 = xPoints[0] + 2;
y1 = yPoints[0];
y2 = y1;
x2 = xPoints[2] - 1;
break;
case SOUTH:
x1 = xPoints[1];
y1 = yPoints[1] + 1;
x2 = xPoints[2] - 1;
y2 = yPoints[2];
break;
case LEFT:
case WEST:
x1 = xPoints[0] + 1;
y1 = yPoints[0] + 1;
x2 = x1;
y2 = yPoints[2] + 1;
break;
case RIGHT:
case EAST:
x1 = xPoints[2];
y1 = yPoints[2] + 1;
x2 = xPoints[1] - 1;
y2 = yPoints[1] + 1;
break;
}
Color saved = g.getColor();
g.setColor(dark);
if (arrow != null) {
g.fillPolygon(xPoints, yPoints, 3);
}
g.setColor(saved);
g.translate(-x, -y);
}
public static void main(String[] args) {
// Resize the frame to reproduce
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CustomArrow(SwingConstants.NORTH));
frame.setSize(400, 400);
frame.setVisible(true);
}
}
Upvotes: 2
Views: 256
Reputation: 3750
Array variables hold references to the array, not the array itself (just like Object variables). When you do something like
int[] xPoints = arrow.xpoints;
int[] yPoints = arrow.ypoints;
you are copying the reference, not the data, meaning that xPoints and arrow.xpoints still point at the same data and modifying either will affect the other. When you later scale these points, you're changing how the arrow will look every future time it is drawn.
If you want to copy the array data to avoid this, you can use System.arraycopy
:
int[] xPoints = new int[3]; //arrow.xpoints;
int[] yPoints = new int[3]; //arrow.ypoints;
System.arraycopy(arrow.xpoints, 0, xPoints, 0, 3);
System.arraycopy(arrow.ypoints, 0, yPoints, 0, 3);
However, you can simply scale the graphics object instead of scaling your reference points:
Graphics2D g2 = (Graphics2D) g;
float scale = size * 1f / defaultSize;
g2.scale(scale, scale);
Upvotes: 4