I wrote a Java program to take a triangle and either rotate, shift, or rotate and shift it, based upon a button click preformed by the user.
Beforehand, I instruct the user to enter in ranges of logical coordinates to determine how pixel coordinates will map to a real x-y coordinate system.
Initially, I have the triangle appearing in the middle of the screen, and after a button is clicked, the triangle is shown after a certain operation is preformed on it (i.e rotation, shifting, etc.)
However, after the operation is completed and the triangle is redrawn, I see an input box also drawn in the top-left corner of the JPanel.
I'm not sure how this keeps getting drawn there.
Code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class RotateAndShiftTriangles extends JFrame {
public static void main(String[] args) { new RotateAndShiftTriangles(); }
RotateAndShiftTriangles() {
super("Drawing 50 Triangles");
final JPanel drawingPanel = new DrawTriangles();
JPanel buttonPanel = new JPanel();
JButton rotate = new JButton("Rotate"),
shift = new JButton("Shift"),
rotateShift = new JButton("Rotate and Shift"),
reset = new JButton ("Reset");
drawingPanel.setBackground(Color.WHITE);
buttonPanel.add(rotate);
buttonPanel.add(shift);
buttonPanel.add(rotateShift);
buttonPanel.add(reset);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
DrawTriangles.rWidth = Float.parseFloat(JOptionPane.showInputDialog("Input rWidth"));
DrawTriangles.rHeight = Float.parseFloat(JOptionPane.showInputDialog("Input rHeight"));
rotate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DrawTriangles.rotate = true;
drawingPanel.repaint();
}
});
shift.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DrawTriangles.shift = true;
drawingPanel.repaint();
}
});
rotateShift.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DrawTriangles.rotate = true;
DrawTriangles.shift = true;
drawingPanel.repaint();
}
});
reset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DrawTriangles.reset = true;
drawingPanel.repaint();
}
});
setSize(600, 400);
add("South", buttonPanel);
add("Center", drawingPanel);
setVisible(true);
}
}
class DrawTriangles extends JPanel {
static float rWidth, rHeight, pixelSize;
static int maxX, maxY, minMaxXY, centerX, centerY;
static boolean rotate = false, shift = false, reset = false;
float angle = 0;
void initialize() {
Dimension d = getSize();
maxX = d.width - 1; maxY = d.height - 1;
pixelSize = Math.max(rWidth / maxX, rHeight / maxY);
minMaxXY = Math.min(maxX, maxY);
centerX = maxX/2; centerY = maxY/2;
}
public int iX2(float x) { return Math.round(x); }
public int iY2(float y) { return maxY - Math.round(y); }
public static int iX(float x) { return Math.round(centerX + x / pixelSize); }
public static int iY(float y) { return Math.round(centerY - y / pixelSize); }
public static float fx(int x) { return (x - centerX) * pixelSize; }
public static float fy(int y) { return (centerY - y) * pixelSize; }
public void paint(Graphics g) {
super.paintComponent(g);
initialize();
int left = iX(-rWidth/2), right = iX(rWidth/2);
int top = iY(rHeight/2), bot = iY(-rHeight/2);
g.drawString("X: " + -rWidth/2 + " Y: " + rHeight/2, left, top + 10);
g.drawString("X: " + rWidth/2 + " Y: " + rHeight/2, right - 55, top + 10);
g.drawString("X: " + -rWidth/2 + " Y: " + -rHeight/2, left, bot);
g.drawString("X: " + rWidth/2 + " Y: " + -rHeight/2, right - 55, bot);
g.setColor(Color.BLUE);
g.drawRect(left, top, right - left, bot - top);
float side = 0.95f * minMaxXY, sideHalf = 0.5F * side,
h = sideHalf * (float)Math.sqrt(3),
xA, yA, xB, yB, xC, yC,
xA1, yA1, xB1, yB1, xC1, yC1, p, q;
q = 0.05F;
p = 1 - q;
xA = centerX - sideHalf;
yA = centerY - 0.5F * h;
xB = centerX + sideHalf;
yB = yA;
xC = centerX;
yC = centerY + 0.5F * h;
if(!reset) {
if(rotate) {
angle += Float.parseFloat(JOptionPane.showInputDialog("Input Angle of Rotation (in degrees)"));
float xR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Rotation"))),
yR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Rotation")));
xA = rotateX(xA, yA, xR, yR, angle);
yA = rotateY(xA, yA, xR, yR, angle);
xB = rotateX(xB, yB, xR, yR, angle);
yB = rotateY(xB, yB, xR, yR, angle);
xC = rotateX(xC, yC, xR, yR, angle);
yC = rotateY(xC, yC, xR, yR, angle);
rotate = false;
}
if(shift) {
float xShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))),
yShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift")));
xA += xShift;
yA += yShift;
xB += xShift;
yB += yShift;
xC += xShift;
yC += yShift;
shift = false;
}
}
g.setColor(Color.RED);
for (int i = 0; i < 50; i++) {
g.drawLine(iX2(xA), iY2(yA), iX2(xB), iY2(yB));
g.drawLine(iX2(xB), iY2(yB), iX2(xC), iY2(yC));
g.drawLine(iX2(xC), iY2(yC), iX2(xA), iY2(yA));
if(i == 0) {
g.setColor(Color.BLACK);
g.drawString("A: X- " + xA + " Y- " + yA, 0, 50);
g.drawString("B: X- " + xB + " Y- " + yB, 0, 60);
g.drawString("C: X- " + xC + " Y- " + yC, 0, 70);
g.setColor(Color.RED);
}
xA1 = p * xA + q * xB;
yA1 = p * yA + q * yB;
xB1 = p * xB + q * xC;
yB1 = p * yB + q * yC;
xC1 = p * xC + q * xA;
yC1 = p * yC + q * yA;
xA = xA1; xB = xB1; xC = xC1;
yA = yA1; yB = yB1; yC = yC1;
}
if(reset)
angle = 0;
reset = false;
}
public float rotateX(float x, float y, float xR, float yR, float angle) {
angle *= (Math.PI / 180.0);
float c = (float)Math.cos(angle), s = (float)Math.sin(angle),
xF = x - xR, yF = y - yR,
rx = xF * c - yF * s;
return rx + xR;
}
public float rotateY(float x, float y, float xR, float yR, float angle) {
angle *= (Math.PI / 180.0);
float c = (float)Math.cos(angle), s = (float)Math.sin(angle),
xF = x - xR, yF = y - yR,
ry = xF * s + yF * c;
return ry + yR;
}
}
I keep getting this
You are triggering JOptionPane
popups inside your paint()
method.
Calls to .paint()
and its siblings should limit themselves to redrawing the object, nothing else. As is, your code will cause your .paint()
method to block until the popup is closed, then continue processing where it left off, potentially picking up artifacts still on the screen. As you can see here, the background is painted (by the call to super.paintComponent()
) then the popup is drawn and closed, then the rest of your .paint()
method runs, but since the background has already been painted, nothing repaints over where the popup was.
You should move code like:
angle += Float.parseFloat(JOptionPane.showInputDialog("Input Angle of Rotation (in degrees)")); float xR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Rotation"))), yR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Rotation")));
and
float xShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))), yShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift")));
out into the appropriate ActionListener
methods, set the necessary values, and then use them from within your paint()
method.
You should also be consistent about using .paint()
and .paintComponent()
, like @camickr suggests, don't have one method call its sibling's super.