Java GUI Window 显示垃圾
Java GUI Window Displays Garbage
我编写了一个 Java 程序,根据用户执行的按钮点击操作,对三角形进行旋转、移动或旋转并移动。
事先,我指示用户输入逻辑坐标范围以确定像素坐标将如何映射到真实的 x-y 坐标系。
最初,我的三角形出现在屏幕中间,点击按钮后,三角形在其上进行了一定的操作(即旋转、移动等)后显示
但是,在操作完成并重新绘制三角形后,我看到在JPanel 的左上角也绘制了一个输入框。
我不确定这怎么一直画在那里。
代码:
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;
}
}
我一直收到这个
public void paint(Graphics g) {
super.paintComponent(g);
不知道这是否是唯一的问题,但是自定义绘画是通过重写 paintComponent()
方法完成的:
public void paintComponent(Graphics g) {
super.paintComponent(g);
编辑:
其他评论,与问题没有直接关系,但对正确设计很重要:
add("South", buttonPanel);
add("Center", drawingPanel);
不要使用硬编码文字。布局管理器将提供您可以使用的变量。另外,不推荐这种形式的 add(...) 方法(阅读 API)。新表格是:
add(buttonPanel, BordeLayout.PAGE_END);
add("Center", BorderLayout.CENTER);
不要使用静态方法和变量。如果您想更改 class 的 属性,请创建 "setter" 方法。例如创建一个 setter 方法:
public void setRotate(Boolean rotate)
{
this.rotate = rotate
repaint();
}
另外,并不是说 setter 方法调用了 repaint() 方法。这是因为您的自定义 class(不是使用 class 的代码)应该负责重绘。
然后调用setter方法:
//DrawTriangles.rotate = true; // wrong
drawingPanel.setRotate(true);
看起来只有在显示对话框时才会发生这种情况。我已经修改了代码并硬编码了一些值,它没有问题。
if(!reset) {
if(rotate) {
angle += Float.parseFloat("15");
float xR = fx(3),
yR = fx(3);
// other stuff...
}
我建议你尝试显示对话框并设置相应的值然后重新绘制组件,类似于此:
shift.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
float xShift = -DrawTriangles.fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))),
yShift = -DrawTriangles.fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift")));
drawingPanel.xShift = xShift;
drawingPanel.yShift = yShift;
DrawTriangles.shift = true;
drawingPanel.repaint();
}
});
使用BufferedImage修正了绘图,但仍然出现异常。
public void paint(Graphics gg) {
BufferedImage bf = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = bf.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
...
gg.drawImage(bf, 0, 0, null);
if(reset)
angle = 0;
reset = false;
}
您正在触发 JOptionPane
弹出窗口 在您的 paint()
方法中。
对 .paint()
及其兄弟项的调用应仅限于重绘对象,除此之外别无其他。照原样,您的代码将导致 .paint()
方法阻塞,直到弹出窗口关闭,然后继续处理它停止的地方,可能会拾取仍在屏幕上的工件。正如你在这里看到的,背景被绘制(通过调用 super.paintComponent()
)然后弹出窗口被绘制并关闭,然后你的 .paint()
方法的其余部分运行,但是由于背景已经被绘制, 没有重绘弹出窗口所在的位置。
你应该像这样移动代码:
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")));
和
float xShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))),
yShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift")));
进入适当的 ActionListener
方法,设置必要的值,然后在 paint()
方法中使用它们。
你也应该在使用 .paint()
和 .paintComponent()
时保持一致,就像@camickr 建议的那样,不要有一个方法调用其兄弟的 super。
我编写了一个 Java 程序,根据用户执行的按钮点击操作,对三角形进行旋转、移动或旋转并移动。
事先,我指示用户输入逻辑坐标范围以确定像素坐标将如何映射到真实的 x-y 坐标系。
最初,我的三角形出现在屏幕中间,点击按钮后,三角形在其上进行了一定的操作(即旋转、移动等)后显示
但是,在操作完成并重新绘制三角形后,我看到在JPanel 的左上角也绘制了一个输入框。
我不确定这怎么一直画在那里。
代码:
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;
}
}
我一直收到这个
public void paint(Graphics g) {
super.paintComponent(g);
不知道这是否是唯一的问题,但是自定义绘画是通过重写 paintComponent()
方法完成的:
public void paintComponent(Graphics g) {
super.paintComponent(g);
编辑:
其他评论,与问题没有直接关系,但对正确设计很重要:
add("South", buttonPanel);
add("Center", drawingPanel);
不要使用硬编码文字。布局管理器将提供您可以使用的变量。另外,不推荐这种形式的 add(...) 方法(阅读 API)。新表格是:
add(buttonPanel, BordeLayout.PAGE_END);
add("Center", BorderLayout.CENTER);
不要使用静态方法和变量。如果您想更改 class 的 属性,请创建 "setter" 方法。例如创建一个 setter 方法:
public void setRotate(Boolean rotate)
{
this.rotate = rotate
repaint();
}
另外,并不是说 setter 方法调用了 repaint() 方法。这是因为您的自定义 class(不是使用 class 的代码)应该负责重绘。
然后调用setter方法:
//DrawTriangles.rotate = true; // wrong
drawingPanel.setRotate(true);
看起来只有在显示对话框时才会发生这种情况。我已经修改了代码并硬编码了一些值,它没有问题。
if(!reset) {
if(rotate) {
angle += Float.parseFloat("15");
float xR = fx(3),
yR = fx(3);
// other stuff...
}
我建议你尝试显示对话框并设置相应的值然后重新绘制组件,类似于此:
shift.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
float xShift = -DrawTriangles.fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))),
yShift = -DrawTriangles.fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift")));
drawingPanel.xShift = xShift;
drawingPanel.yShift = yShift;
DrawTriangles.shift = true;
drawingPanel.repaint();
}
});
使用BufferedImage修正了绘图,但仍然出现异常。
public void paint(Graphics gg) {
BufferedImage bf = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = bf.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
...
gg.drawImage(bf, 0, 0, null);
if(reset)
angle = 0;
reset = false;
}
您正在触发 JOptionPane
弹出窗口 在您的 paint()
方法中。
对 .paint()
及其兄弟项的调用应仅限于重绘对象,除此之外别无其他。照原样,您的代码将导致 .paint()
方法阻塞,直到弹出窗口关闭,然后继续处理它停止的地方,可能会拾取仍在屏幕上的工件。正如你在这里看到的,背景被绘制(通过调用 super.paintComponent()
)然后弹出窗口被绘制并关闭,然后你的 .paint()
方法的其余部分运行,但是由于背景已经被绘制, 没有重绘弹出窗口所在的位置。
你应该像这样移动代码:
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")));
和
float xShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))), yShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift")));
进入适当的 ActionListener
方法,设置必要的值,然后在 paint()
方法中使用它们。
你也应该在使用 .paint()
和 .paintComponent()
时保持一致,就像@camickr 建议的那样,不要有一个方法调用其兄弟的 super。