[英]A Java Swing puzzle: What doesn't the first iteration display on the JPanel?
Here's one I've come close to figuring out, but never really did. 这是我接近解决的问题,但从未真正做到。
The code listed below is supposed to draw a green circle as soon as it sees its first click. 下面列出的代码在第一次点击时便会绘制一个绿色圆圈。 It doesn't.
没有。 Subsequent clicks draw lines that connect the current clicked point with the previous one, in red.
后续点击会以红色绘制连接当前点击点和上一个点击点的线。 The code fails for the first click and works on all subsequent ones.
该代码在首次点击时失败,并且在所有后续点击中均有效。 Why doesn't the first click display?
为什么第一次点击不显示? It runs!
它运行!
What am I doing wrong? 我究竟做错了什么?
The code should compile on any current JDE. 该代码应在任何当前的JDE上编译。
TIA TIA
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
class Demo extends JFrame
implements ActionListener, ListSelectionListener, MouseListener {
int clkCt = 0, // Count of the number of clicks we've done.
oldX, // Penultimate X value
oldY, // Penultimate X value
scrH, // Height of the drawing canvas.
scrW; // Width of the drawing canvas.
JFrame f; // Holder for the drawing canvas.
JLabel ctL; // Displays the number of clicks we've done.
JPanel canvas; // The drawing canvas.
public void demoLines() {
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
scrH = (int) ((double) d.height * 0.75);
scrW = (int) ((double) d.width * 0.75);
oldX = scrH / 2;
oldY = oldX;
// Create and set up the window.
f = new JFrame("Multi Click Demo");
f.getContentPane().setLayout(null);
int h = scrH / 5;
f.setBounds(h, h, scrW, scrH);
// Create a panel
canvas = new JPanel();
canvas.setBackground(Color.black);
canvas.setForeground(Color.red);
canvas.setLayout(null);
canvas.setBounds(0, 0, scrW, scrH);
canvas.setPreferredSize(new Dimension(scrW, scrH));
canvas.addMouseListener(this);
f.getContentPane().add(canvas);
// Create the exit button.
JButton exit = new JButton("Exit");
exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
goAway();
}
});
exit.setBackground(Color.black);
exit.setForeground(Color.red);
exit.setBounds(0, 0, (scrW / 15), (scrH / 15));
canvas.add(exit); //*/
// Create the label for the click count.
ctL = new JLabel("None Yet");
ctL.setBackground(Color.black);
ctL.setForeground(Color.red);
ctL.setBounds((scrH / 15), (scrH * 13 / 15), (scrW / 15), (scrH / 15));
canvas.add(ctL);
f.getContentPane().add(canvas);
f.setVisible(true);
Graphics g = canvas.getGraphics();
if (g == null) {
System.out.println("No graphics for canvas!");
} else {
canvas.revalidate(); // This didn't help.
paintComponent(g, (oldX + oldX / 2), (oldY + oldY / 2));
}
}
void goAway() {
f.setVisible(false);
f.dispose();
}
public void mouseClicked(MouseEvent m) {
// Where was the mouse clicked?
int clkdBtn = m.getButton(),
x = m.getX(),
y = m.getY();
Graphics g = canvas.getGraphics();
paintComponent(g, x, y);
}
public void paintComponent(Graphics g,
int x,
int y) {
// This always runs.
ctL.setText(clkCt + "");
if (clkCt == 0) {
// This never displays!
g.setColor(Color.green);
int r = scrH * 4 / 5;
g.drawOval((scrH / 10), (scrH / 10), r, r);
}
g.setColor(Color.red);
g.drawLine(oldX, oldY, x, y);
oldX = x;
oldY = y;
clkCt++;
}
public void actionPerformed(ActionEvent event) { }
public void valueChanged(ListSelectionEvent event) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public static void main(String[] s) {
Demo m = new Demo();
m.demoLines();
}
}
What am I doing wrong?
我究竟做错了什么?
You're using getGraphics
for custom painting. 您正在使用
getGraphics
进行自定义绘画。 Any previous painting will be lost when a repaint
is called. 调用
repaint
时,以前的任何画都将丢失。 Instead move all the custom painting functionality to a new class based on JComponent
or JPanel
and override paintComponent there. 而是将所有自定义绘画功能移至基于
JComponent
或JPanel
的新类,并在那里覆盖paintComponent 。 Remember to invoke super.paintComponent(g)
. 记住要调用
super.paintComponent(g)
。
See Custom Painting Approaches for solutions for drawing multiple components from within paintComponent
. 有关从
paintComponent
内绘制多个组件的解决方案,请参见“ 自定义绘画方法 ”。 You can build a List<Shape>
of custom drawable components, iterate through the list from within the method, and use drawLine
or drawOval
as appropriate. 您可以构建自定义可绘制组件的
List<Shape>
,从方法中遍历列表,并根据需要使用drawLine
或drawOval
。
remove the following lines from demolines()
从
demolines()
删除以下行
Graphics g = canvas.getGraphics();
if (g == null) {
System.out.println("No graphics for canvas!");
} else {
canvas.revalidate(); // This didn't help.
paintComponent(g, (oldX + oldX / 2), (oldY + oldY / 2));
}
and add canvas.addMouseListener(this);
并添加
canvas.addMouseListener(this);
in the end of the function 在功能的最后
There were a multitude of problems with that code. 该代码存在许多问题。 I fixed them but neglected to document every change.
我固定了它们,但忽略了所有更改。 Look closely over this code and ask questions if you do not understand (from reading the relevant documentation/tutorial) why I made the change.
仔细查看此代码,并询问您是否不理解(通过阅读相关文档/教程)为什么进行更改。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.EmptyBorder;
public class Demo extends JPanel
implements ListSelectionListener, MouseListener {
int clkCt = 0, // Count of the number of clicks we've done.
oldX, // Penultimate X value
oldY, // Penultimate X value
scrH = 100, // Height of the drawing canvas.
scrW = 400; // Width of the drawing canvas.
JLabel ctL; // Displays the number of clicks we've done.
int x, y;
public void demoLines() {
oldX = scrH / 2;
oldY = oldX;
// Create a panel
setBackground(Color.black);
setForeground(Color.red);
setPreferredSize(new Dimension(scrW, scrH));
// Create the label for the click count.
ctL = new JLabel("None Yet");
ctL.setBackground(Color.black);
ctL.setForeground(Color.red);
ctL.setBounds((scrH / 15), (scrH * 13 / 15), (scrW / 15), (scrH / 15));
add(ctL);
addMouseListener(this);
}
public void mouseClicked(MouseEvent m) {
// Where was the mouse clicked?
x = m.getX();
y = m.getY();
repaint();
}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
public void paintComponent(Graphics g) {
// This always runs.
ctL.setText(clkCt + "");
if (clkCt == 0) {
// This never displays!
g.setColor(Color.green);
int r = scrH * 4 / 5;
g.drawOval((scrH / 10), (scrH / 10), r, r);
}
g.setColor(Color.red);
g.drawLine(oldX, oldY, x, y);
oldX = x;
oldY = y;
clkCt++;
}
public void valueChanged(ListSelectionEvent event) {
}
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
Demo m = new Demo();
m.demoLines();
JFrame f = new JFrame("Demo");
f.add(m);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
JFrame
, add a JPanel
& do custom painting in the paintComponent(Graphics)
method. JFrame
中绘画,可以添加JPanel
并在paintComponent(Graphics)
方法中进行自定义绘画。 Also return a sensible preferred size for the custom component, to assist the layout manager. JComponent
, override paintComponent(Graphics)
instead of paint(Graphics)
. JComponent
自定义绘画,请重写paintComponent(Graphics)
而不是paint(Graphics)
。 覆盖paintComponent()
时,应始终将super.paintComponent()
作为第一行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.