上个贴子在回复中写的新问题没人理了,只好另开炉灶~
目前这个程序类似WINDOWS画图的功能,现在的问题出在画特定图形的功能实现上。
暂时的写法是在Panel上绘图,然后mouse事件里写入缓冲区,然后在paint方法里从缓冲区读取图象。这样写的问题是在画线,椭圆等特定图形时画面不断闪烁(因为用到了update。可是麻烦在于必须用到update,画特定图形例如线时,点击点与拖动鼠标的轨迹点之间的线必须不断清除,只留下松开鼠标之前的那条直线,否则就成了扇形~)。
一般解决这种闪烁有两个办法,第一重写update使其不清除画面,这条不行了。二是全部在缓冲区操作,个人感觉解决突破口应该在此,但不知具体该如何处理:把在Panel上绘图的方法照搬过去行不通,因为update会清除缓冲区,这样之前作品在操作中就无法保留了。想在update上作文章,但考虑了几天仍然无奈,所以期盼高手指点,请各位不吝赐教!感谢!!

解决方案 »

  1.   

    写了一个简单的划线的,觉得还算好用啊,没觉得是扇形啊
    package squall.swing;import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.util.ArrayList;import javax.swing.JFrame;
    import javax.swing.JPanel;public class TestFrame extends JFrame {
    public TestFrame() {
    this.add(new TestPanel());
    this.setTitle("TestFrame");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setSize(400, 400);
    this.setVisible(true);
    } public static void main(String[] args) {
    new TestFrame();
    }
    }class TestPanel extends JPanel {
    public TestPanel() {
    TestMouse action = new TestMouse(this);
    this.addMouseListener(action);
    this.addMouseMotionListener(action);
    } public ArrayList lines = new ArrayList(); public Point[] tmp = null; public void addPoint(Point[] pair) {
    lines.add(pair);
    } @Override
    public void paint(Graphics g) {
    // TODO Auto-generated method stub
    super.paint(g);
    Graphics2D g2 = (Graphics2D) g;
    for (int i = 0, length = lines.size(); i < length; ++i) {
    Point[] points = (Point[]) lines.get(i);
    g2.drawLine((int) points[0].getX(), (int) points[0].getY(),
    (int) points[1].getX(), (int) points[1].getY());
    }
    if (tmp != null) {
    g2.drawLine((int) tmp[0].getX(), (int) tmp[0].getY(), (int) tmp[1]
    .getX(), (int) tmp[1].getY());
    }
    }}class TestMouse implements MouseListener, java.awt.event.MouseMotionListener {
    public TestPanel owner; public TestMouse(TestPanel panel) {
    this.owner = panel;
    } private Point begin = null; public void mouseClicked(MouseEvent e) {
    // TODO Auto-generated method stub } public void mouseEntered(MouseEvent e) {
    // TODO Auto-generated method stub } public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub } public void mousePressed(MouseEvent e) {
    // TODO Auto-generated method stub
    begin = e.getPoint();
    } public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub
    if (begin != null) {
    owner.addPoint(new Point[] { begin, e.getPoint() });
    begin = null;
    owner.tmp = null;
    }
    owner.repaint();
    } public void mouseDragged(MouseEvent e) {
    // TODO Auto-generated method stub owner.tmp = new Point[] { begin, e.getPoint() };
    owner.repaint(); } public void mouseMoved(MouseEvent e) {
    // TODO Auto-generated method stub }}
      

  2.   

    repaint的时候先画已经确定保留的图形,再画正在变化中的图形,感觉不存在擦除临时图形的问题
      

  3.   


    先感谢你的解答!
    这个方法好象对于简单的例子比较适用,因为我的理解,你的方法是通过保存上之前绘图时鼠标的位置,在当前绘图时重新绘出前后的图形。如果要画的图形很多,那不是要在paint方法里写出全部的绘图方法,而且有一点很麻烦的是还有按鼠标轨迹绘图的功能(这个如果不用双缓冲,我感觉很难重新绘制出来)。
    不知道我有没有理解错误的地方,还请你多指点
      

  4.   

    再来两个arraylist
    一个放保存了的shape
    一个放改动中的shape感觉应该可以
      

  5.   


    是的,就是初始点也不断改变画线的情况
    还有我说的图形很多是指种类,比如直线,圆,椭圆,长方形等等,如果绘图时作品包括所有这些,那paint方法里必须对每一种图形都要分别记录数据然后重新绘图吧
      

  6.   

    还有,我感觉在缓冲区每次清除后都重新绘图似乎paint方法会过于复杂,我的想法是能不能覆盖update方法,让每次清除的时候不是清除整个绘图区域,而只是刷新当前对象。不知道这个想法行不行的通~暂时也没找到合适的update写法
      

  7.   

    楼主可以使用JPanel来绘制, 而不是用Panel, 因为JPanel已经实现了双缓冲机制(简单点讲就是当前在进行绘制图像的同时, 屏幕上在显示一幅已经绘制好的存放在缓冲区的图像, 即当前看到的图像并不是你正在绘制的图像, 因为显示的是一幅完整的已经绘制好的图像, 所以在刷新时, 屏幕不会闪烁).
    使用JPanel来绘制, 用的不是paint方法, 而是JPanel的protected void paintComponent(Graphics g)方法, 在方法的第一句, 要先调用父类的此方法, 如:
    public class MyPanel extends JPanel() {
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);    // 开始进行绘制
        g.drawString("Was", 0, 0);
    }
    }如果还想继续使用Panel来绘制的话, 那就要自己实现双缓冲机制了:
    先建一个BufferedImage bufferedImage, 
    在paint方法中, Graphics gg = bufferedImage.getGraphics();
    然后所有需要绘制的东西, 都使用这个gg来绘制, 
    绘制完成后, 把这个bufferedImage绘制到从paint方法得到的Graphics环境中:
    void paint(Graphics g) {
        Graphics gg = bufferedImage.getGraphics();
        gg.drawString("buffer", 0, 0);
        //......其他的绘制工作    g.drawImage(bufferedImage, 0, 0, this);
    }
      

  8.   

    可以让所有被绘制的图形继承一个Shape类,自己定义的类,该类提供一个draw方法,其他的图形实现,这样,在paint方法中,直接循环调用每个Shape子类的draw方法即可
      

  9.   


    很感谢你的建议,这样写确实会让程序更简洁一些。
    不过现在的主要问题是在repaint方法的内部,也就是说如何让update-paint的过程不影响之前的缓存图象而且不会使画面闪烁
      

  10.   

    知道了两端点的坐标有没有方法删除这条直线呢,如果可以,就应该能解决update的问题了,哪位高人指点下啊~
    (用背景色重画行不通的,这样会盖掉其他图形)
      

  11.   

    汗没人帮帮忙啊~
    其实说白了就是想知道WINDOWS画图程序那种类似橡皮筋直线画法如何做到可覆盖,不闪烁的,这里应该不会没人知道如何做到的吧
      

  12.   

    不是没人帮忙, 而是上面大家说的东西已经够多了, 是你听不过进.如果你想要不闪烁, 都已经说过了要使用双缓冲, 一种方法是JPanel自带了双缓冲, 直接在JPanel的paintComponent中绘制, 另一种方法是自己实现双缓冲, 上面也有大概的方法, 细节方面在网络上一搜, 非常多.删除一个图形, 即可以随时删除所画的图形中的任一个, 如果不把图形对象保存起来, 怎么删除? 这种方法上面也有很多人提出来过, 可是你听进去了吗?
      

  13.   

    鼠标的轨迹就是一系列长度为1的线段。
    其实除了线段,你需要的就是Shape保存图形了。
      

  14.   

    其实开始朦胧感觉这种方法写起来比较复杂,幻想WINDOWS画图那样的程序应该会有比较便捷的算法,就没仔细从这个方法找突破口,想偷点懒找找有没有稍微简洁一点的方法(或许是害怕对已经写好的代码动大手术~)。
    真的很感谢你给我这么多这方面的建议,我就从这个方法入手去写写看,有什么问题还请你多多指点
      

  15.   

    当遇到用鼠标轨迹画图的时候,用一个arraylist保存鼠标经过的每一个点,
    然后把前后相邻的两个点连接起来就可以了
      

  16.   

    我也给一些参考:第一个方法就是组件重绘方法,第二个就是双缓冲区
    1.package src;import java.awt.*;
    public class Myline {
    ////////////////////////
    private int orgX;
    private int orgY;
    private int endX;
    private int endY;

    public Myline(int orgX,int orgY,int endX,int endY){

    this.orgX = orgX;
    this.orgY = orgY;
    this.endX = endX;
    this.endY = endY;

    }

    public void dramline(Graphics g){
    g.setColor(Color.RED);
    g.drawString(orgX + "," + orgY,orgX,orgY);
    g.drawString(endX+ "," + endY,endX,endY);
    g.drawLine(orgX, orgY, endX, endY);
    }
    }package src;import java.awt.*;
    import java.util.*;
    import java.awt.event.*;
    public class Paint extends Frame {
    /**
     * @param args
     */
    static final long serialVersionUID = 42L;

    Vector allLine = new Vector();

    public static void main(String[] args) {
    // TODO 自动生成方法存根
    Paint p = new Paint();
    p.init(); }

    public void init(){

    this.addWindowListener(new WindowAdapter(){

    public void windowClosing(WindowEvent e){
    dispose();
    System.exit(0);
    }
    });
    this.addMouseListener(new MouseAdapter(){
    int orgX;
    int orgY;
    public void mousePressed(MouseEvent e){
    orgX = e.getX();
    orgY = e.getY();
    }

    public void mouseReleased(MouseEvent e){

    allLine.add(new Myline(orgX, orgY, e.getX(), e.getY()));
    repaint();
    }
    });
    this.setSize(300,300);
    this.setVisible(true);
    }
    public void paint(Graphics g){
    Enumeration lines = allLine.elements();
    while(lines.hasMoreElements()){
    Myline l = (Myline)lines.nextElement();
    l.dramline(g);
    }
    }}
    2.
    package src;import java.awt.*;
    import java.util.*;
    import java.awt.event.*;
    public class TestImage extends Frame {
    /**
     * @param args
     */
    static final long serialVersionUID = 42L;

    Vector allLine = new Vector();

    Image img = null;
    Graphics og = null;

    public static void main(String[] args) {
    // TODO 自动生成方法存根
    TestImage p = new TestImage();
    p.init(); }

    public void init(){

    setSize(300,300);
    setVisible(true);
    Dimension d = getSize(); 
    img = createImage(d.width,d.height);
    og = img.getGraphics();

    addWindowListener(new WindowAdapter(){

    public void windowClosing(WindowEvent e){
    dispose();
    System.exit(0);
    }
    });

    addMouseListener(new MouseAdapter(){
    int orgX;
    int orgY;
    public void mousePressed(MouseEvent e){
    orgX = e.getX();
    orgY = e.getY();
    }

    public void mouseReleased(MouseEvent e){

    /*allLine.add(new Myline(orgX, orgY, e.getX(), e.getY()));
    repaint();*/
    Graphics g = getGraphics();
    g.setColor(Color.RED);
    g.drawString(orgX + "," + orgY,orgX,orgY);
    g.drawString(e.getX()+ "," + e.getY(),e.getX(),e.getY());
    g.drawLine(orgX, orgY, e.getX(), e.getY());

    og.setColor(Color.RED);
    og.drawString(orgX + "," + orgY,orgX,orgY);
    og.drawString(e.getX()+ "," + e.getY(),e.getX(),e.getY());
    og.drawLine(orgX, orgY, e.getX(), e.getY());

    }
    });
    }
    public void paint(Graphics g){
    /*Enumeration lines = allLine.elements();
    while(lines.hasMoreElements()){
    Myline l = (Myline)lines.nextElement();
    l.dramline(g);*/
    if(img!=null){
    g.drawImage(img,0,0,this);
    }
    }}