我有一个简单的类,当鼠标拖动时画一条线或者鼠标按下(释放)时画一个点。
当我最小化应用程序然后恢复它时,窗口的内容将消失,除了最后一个点(像素)。我知道方法super.paint(g)
每次窗口改变时重新绘制背景,但无论我是否使用它,结果似乎都是一样的。它们之间的区别在于,当我不使用它时,窗口上绘制的不仅仅是一个像素,而不是我的所有绘画。我该如何解决这个问题?
这是班级。
package painting;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
class CustomCanvas extends Canvas{
Point oldLocation= new Point(10, 10);
Point location= new Point(10, 10);
Dimension dimension = new Dimension(2, 2);
CustomCanvas(Dimension dimension){
this.dimension = dimension;
this.init();
addListeners();
}
private void init(){
oldLocation= new Point(0, 0);
location= new Point(0, 0);
}
public void paintLine(){
if ((location.x!=oldLocation.x) || (location.y!=oldLocation.y)) {
repaint(location.x,location.y,1,1);
}
}
private void addListeners(){
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
@Override
public void mouseReleased(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
paintLine();
}
});
}
@Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.red);
g.drawLine(location.x, location.y, oldLocation.x, oldLocation.y);
}
@Override
public Dimension getMinimumSize() {
return dimension;
}
@Override
public Dimension getPreferredSize() {
return dimension;
}
}
class CustomFrame extends JPanel {
JPanel displayPanel = new JPanel(new BorderLayout());
CustomCanvas canvas = new CustomCanvas(new Dimension(200, 200));
public CustomFrame(String titlu) {
canvas.setBackground(Color.white);
displayPanel.add(canvas, BorderLayout.CENTER);
this.add(displayPanel);
}
}
public class CustomCanvasFrame {
public static void main(String args[]) {
CustomFrame panel = new CustomFrame("Test Paint");
JFrame f = new JFrame();
f.add(panel);
f.pack();
SwingConsole.run(f, 700, 700);
}
}
答案 0 :(得分:5)
您没有存储您正在绘制的点的状态。重新绘制面板时,它只显示它绘制的最后一点的信息。
对评论的回应:
您需要拥有一组Points,例如ArrayList<Point> location = new ArrayList<Point>();
然后,在你的听众中:location.add(new Point(me.getX(), me.getY()));
最后,在paintLine()中:
for (Point location : locations) {
repaint(location.x,location.y,1,1);
}
集合locations
通常称为显示列表。大多数图形程序都使用它们。
对评论的回应:
是的,我希望如此。我只是根据你的代码抛出一个想法给你一个起点。完全按照我的描述做几乎肯定是一个坏主意。
答案 1 :(得分:5)
这是否意味着每次按或拖动鼠标时我都会绘制所有点(而不是一个点)?
是的,但@ Dave的方法对于数千个节点来说是完全令人满意的,如GraphPanel
中所示。除此之外,请考虑flyweight pattern使用的JTable
renderers并说明here。
附录:关注AWTPainting
个问题,下面的变体可能会说明System- and App-triggered Painting之间的差异。拖动鼠标时,repaint()
会调用update()
,调用paint()
;这是应用程序触发的。调整窗口大小时,仅调用paint()
(不会绘制红色数字);这是系统触发的。请注意,在调整大小后释放鼠标时, 闪烁。
当整个组件的背景被清除并重新绘制时,通常会发生闪烁:
4.如果组件不覆盖
update()
,则update()
的默认实现会清除组件的背景(如果它不是轻量级组件),只需调用{{ 1}}。
paint()
答案 2 :(得分:2)
@Andrew,@ Dave,@ trashgod嗨, 我对此做了一些研究,最后,这就是我所拥有的。如果我错了,请纠正我。你不能覆盖paint(),所以你每次需要做app触发的绘画时都要调用repaint()。 Repaint()调用update(),其默认行为是调用paint()。 update()用于增量绘画;这解释了当paint()完成所有工作时闪烁的屏幕,这实际上意味着它在每一步都在绘制整个图像。 但是,我的问题是,如果我在更新方法中添加“locationsAdded = 0”,这意味着每次我拖动鼠标我都会绘制整个图像(就像在绘画中一样),那么为什么它不像以前一样闪烁? 我还读过一些关于在秋千上绘画的内容,我不明白为什么从不为swing调用update()。你能解释一下为什么吗?
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
class CustomCanvas extends Canvas{
ArrayList<Point> locations;
int locationsAdded;
Point oldLocation;
Point location;
Dimension dimension;
CustomCanvas(Dimension dimension){
locations = new ArrayList<>();
this.dimension = dimension;
this.init();
addListeners();
}
private void init(){
oldLocation= new Point(0, 0);
location= new Point(0, 0);
}
public void paintLine(Graphics g, int x){
Point p1 = (Point)locations.get(x);
Point p2 = (Point)locations.get(x+1);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
locationsAdded++;
}
@Override
public void paint(Graphics g){
locationsAdded = 0;
g.setColor(Color.red);
for(int i = locationsAdded; i < locations.size()-1; i++){
paintLine(g, i);
}
}
public void update(Graphics g) {
//locationsAdded = 0;
for (int i = locationsAdded; i < locations.size()-1; i++) {
paintLine(g, i);
}
}
private void addListeners(){
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent me){
oldLocation = location;
location = new Point(me.getX(), me.getY());
locations.add(location);
repaint();
}
});
}
@Override
public Dimension getMinimumSize() {
return dimension;
}
@Override
public Dimension getPreferredSize() {
return dimension;
}
}
class CustomFrame extends Panel {
Panel displayPanel = new Panel(new BorderLayout());
CustomCanvas canvas = new CustomCanvas(new Dimension(700, 700));
public CustomFrame(String titlu) {
canvas.setBackground(Color.white);
displayPanel.add(canvas, BorderLayout.CENTER);
this.add(displayPanel);
}
}
public class AWTPainting {
public static void main(String args[]) {
CustomFrame panel = new CustomFrame("Test Paint");
Frame f = new Frame();
f.add(panel);
f.pack();
f.setSize(700,700);
f.show();
}
}
答案 3 :(得分:0)
将布局设置为空布局