重绘JPanel的一部分

时间:2013-03-29 16:05:28

标签: java swing jpanel repaint paintcomponent

我需要在x-y轴坐标系中绘制google和yahoo访问时间。现在我绘制了x-y轴坐标系。

public void paintComponent(Graphics gl) {
    Graphics2D g = (Graphics2D) gl;
    g.setColor(new Color(222, 222, 222));
    g.fillRect(0, 0, this.getWidth(), this.getHeight());
    g.setColor(new Color(0, 0, 0));
    int x=15;
    int y=15;
    g.drawString("20", 0, 10);
    for(int i=1;i<=20;i++) {
        g.drawLine(x, y+(35*(i-1)), x, y+(35*i));
        g.drawString(""+(20-i), 0, y+(35*i));
    }
    for(int i=1;i<=10;i++) {
        g.drawLine(x+(70*(i-1)),715, x+(70*i), 715);
        g.drawString(""+i,  x+(70*i),730);
    }
}

现在我需要动态地在这个X-Y坐标系上重新绘制访问时间的值。但我知道何时调用repaint()。它将再次重绘()X-Y坐标.. 如何在不重新绘制X-Y坐标的情况下重新绘制访问时间值?

2 个答案:

答案 0 :(得分:5)

将GUI显示的稳定背景部分放入BufferedImage,然后在paintComponent(...)方法中绘制。

例如,

// Warning: code has not been run nor compiled and may contain errors.
public class MyGui extends JPanel {
   public static final int BI_WIDTH = //..... ? the width of the image
   public static final int BI_HEIGHT = // .....? the height of the image
   private BufferedImage bImg;

   public MyGui() {
     bImg = makeImage();
     // ... other code
   }

   public BufferedImage makeImage() {
     BufferedImage bImg = new BufferedImage(BI_WIDTH, BI_HEIGHT, 
         BufferedImage.TYPE_INT_ARGB);
     Graphics2D g2 = bImg.createGraphics();

     // ... do your background drawing here, the display that doesn't change

     g2.dispose();
     return bImg;
   }

   public void paintComponent(Graphics g) {
     super.paintComponent(g);
     if (bImg != null) {
       g.drawImage(bImg, 0, 0, this);
     }
     // ...  draw the changing parts of your display
   }

   // note, if your image is going to fill up your JPanel, then it's
   // also a good idea to override the getPreferredSize() method to make sure 
   // that the JPanel's size is correct and matches that of the image:
   @Override
   public Dimension getPreferredSize() {
     return new Dimension(BI_WIDTH, BI_HEIGHT);
   }

修改:注意有关getPreferredSize()

的代码和评论

答案 1 :(得分:1)

  

如何在不重新绘制X-Y坐标的情况下重新绘制访问时间值?

如果再次重新绘制X / Y轴,为什么重要?如果您担心性能,它将不会产生任何明显的差异。

我知道这不是你提出的问题,但这里有一个解决方案,将X / Y轴描绘成单独的组件。然后,您可以独立绘制访问时间。它可能看起来有点复杂,但那是因为X / Y轴代码比你的更加绚丽。

此外,这可能会使绘画访问时间更容易,因为所有绘画偏移现在都是零,因为您在单独的面板上绘画。

import java.awt.*;
import javax.swing.*;

public class Axis extends JComponent
{
    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;

    private int orientation;
    private int ticks;
    private int tickIncrement;
    private int tickSize = 7;

    public Axis(int orientation, int ticks, int tickIncrement)
    {
        this.orientation = orientation;
        this.ticks = ticks;
        this.tickIncrement = tickIncrement;

        setFont( new Font("SansSerif", Font.PLAIN, 10) );
    }

    public Dimension getPreferredSize()
    {
        FontMetrics fontMetrics = getFontMetrics( getFont() );
        int tickDimension = ticks * tickIncrement;

        if (orientation == HORIZONTAL)
        {
            int height = (fontMetrics.getHeight() * 2) - fontMetrics.getAscent() + (tickSize * 2);
            return new Dimension(tickDimension + getVerticalAxisWidth(), height);
        }
        else
        {
            int digits = String.valueOf(ticks).length();
            int textWidth = fontMetrics.charWidth( '0' ) * digits;
            int width = textWidth + (tickSize * 2) + 10;
            return new Dimension(width, tickDimension);
        }
    }

    protected void paintComponent(Graphics g)
    {
        //  Paint background

        g.setColor( getBackground() );
        g.fillRect(0, 0, getWidth(), getHeight());

        //  Paint graph axis

        g.setFont( getFont() );
        g.setColor( getForeground() );

        if (orientation == HORIZONTAL)
            paintHorizontalAxis(g);
        else
            paintVerticalAxis(g);
    }

    private void paintHorizontalAxis(Graphics g)
    {
        FontMetrics fontMetrics = getFontMetrics( g.getFont() );
        int label = 1;
        int offset = tickIncrement;
        int width = getWidth();
        int adjustmentX = getVerticalAxisWidth() - 1;
        int textOffset = tickSize + fontMetrics.getHeight();

        while (offset <= width)
        {
            int hOffset = adjustmentX + offset;
            g.drawLine(adjustmentX, 0, width, 0);
            g.drawLine(hOffset, 0, hOffset, tickSize);
            String text = "" + label;
            int textAdjustment = (fontMetrics.stringWidth(text) - 1) / 2;
            g.drawString(text, hOffset - textAdjustment, textOffset);

            offset += tickIncrement;
            label++;
        }
    }

    private int getVerticalAxisWidth()
    {
        Container parent = (Container)getParent();

        if (parent == null)
            return 0;

        LayoutManager manager = parent.getLayout();

        if (manager instanceof BorderLayout)
        {
            BorderLayout layout = (BorderLayout)manager;

            Component south = layout.getLayoutComponent(BorderLayout.SOUTH);
            Component west = layout.getLayoutComponent(BorderLayout.WEST);

            if (this.equals(south)
            &&  west instanceof Axis)
            {
                return west.getPreferredSize().width;
            }
        }

        return 0;
    }

    private void paintVerticalAxis(Graphics g)
    {
        FontMetrics fontMetrics = getFontMetrics( g.getFont() );
        int label = 1;
        int offset = tickIncrement;
        int x = getWidth() - 1;
        int height = getHeight();
        int textOffset = fontMetrics.getHeight() - fontMetrics.getAscent() + 1;

        while (offset <= height)
        {
            int vOffset = height - offset;
            g.drawLine(x, 0, x, height);
            g.drawLine(x, vOffset, x - tickSize, vOffset);
            String text = "" + label;
            int textAdjustment = fontMetrics.stringWidth( text ) + tickSize + 5;
            g.drawString(text, x - textAdjustment, vOffset + textOffset);

            offset += tickIncrement;
            label++;
        }
    }

    private static void createAndShowUI()
    {
        JPanel graph = new JPanel( new BorderLayout() );

        Axis vertical = new Axis(Axis.VERTICAL, 8, 50);
        vertical.setBackground(Color.ORANGE);
        graph.add(vertical, BorderLayout.WEST);

        Axis horizontal = new Axis(Axis.HORIZONTAL, 12, 50);
        horizontal.setBackground(Color.ORANGE);
        graph.add(horizontal, BorderLayout.SOUTH);

        //  Do you custom painting on this panel

        JPanel center = new JPanel();
        center.setBackground( Color.YELLOW );
        graph.add(center);

        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JScrollPane(graph));
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

这仍然不是一个完美的解决方案,因为代码依赖于你使用BorderLayout来保存3个面板,但我不想编写自定义布局管理器来演示一个概念。