创建具有多个矩形的面板的问题

时间:2013-04-29 21:16:47

标签: java graphics rectangles

我正在尝试创建一个面板,显示我们存储的一些“地图”的历史记录。 最早出现在顶部,其次是后来有时会提供额外信息。

到目前为止,HistoryGraph的主要代码是:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/**
 * @author woo Apr 29, 2013
 * 
 *         TODO
 * 
 *         freemind freemind.database.graphics
 */
public class HistoryGraph extends JPanel
{

   public HistoryGraph()
   {
      super();
   }

   private List<HistoryNode> nodes = new ArrayList<HistoryNode>();

   public void add( int startX, int startY, HistoryNode node )
   {
      node.setPosition( startX, startY );
      nodes.add( node );
      System.out.println( "There are now " + nodes.size() + " nodes" );
   }

   @Override
   public void paintComponent( Graphics g )
   {
      Graphics2D g2 = ( Graphics2D ) g;
      g2.setColor( getBackground() );

      g2.fillRect( getX(), getY(), getWidth(), getHeight() );

      g2.setColor( Color.black );
      int lastX = 0;
      int lastY = 0;
      int k = 0;
      for ( int i = 0; i < nodes.size(); i++ )
      {
         HistoryNode node = nodes.get( i );
         node.paintComponent( g2 );
         if ( k > 0 )
         {
            int x = node.getX() + node.getWidth() / 2;
            int y = node.getY();
            g2.draw( new Line2D.Double( lastX, lastY, x, y ) );
         }
         lastX = node.getX() + node.getWidth() / 2;
         lastY = node.getY() + node.getHeight();
         k++;
      }
   }

   /**
    * @param args
    */
   public static void main( String[] args )
   {
      JFrame f = new JFrame( "History of Map X" );
      f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
      List<HistoryNode> nodes = new ArrayList<HistoryNode>();
      HistoryGraph panel = new HistoryGraph();
      panel.setBackground( Color.green );
      nodes.add( new HistoryNode( "2012-04-09,Version 1.2" ) );
      nodes.add( new HistoryNode( "2012-05-01,Release 1.1" ) );
      nodes.add( new HistoryNode( "2012-05-03,Release 1.2,Version 1.3,Test" ) );
      int x = 50;
      int y = 50;
      int deltaY = 100;
      for ( int i = 0; i < nodes.size(); i++ )
      {
         HistoryNode node = nodes.get( i );

     node.setBackground( Color.orange );
     panel.add( x, y, node );
     y += deltaY;
  }

HistoryNode的代码是:

import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @author woo Apr 29, 2013
 * 
 *         TODO
 * 
 *         freemind freemind.database.graphics
 */

public class HistoryNode extends JPanel
{

   public HistoryNode( String text )
   {
      super();
      this.text = text;
   }

   private double x;
   private double y;
   private double width;
   private double height;

   private String text;

   private Double r;

   @Override
   public int getHeight()
   {
      return ( int ) height;
   }

   @Override
   public int getWidth()
   {
      return ( int ) width;
   }

   @Override
   public int getX()
   {
      return ( int ) x;
   }

   @Override
   public int getY()
   {
      return ( int ) y;
   }

   @Override
   public void paintComponent( Graphics g )
   {
      super.paintComponent( g );
      Graphics2D g2d = ( Graphics2D ) g;

      g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING,
         RenderingHints.VALUE_ANTIALIAS_ON );
      FontRenderContext frc = g2d.getFontRenderContext();
      Font font = g2d.getFont().deriveFont( 12f );
      g2d.setFont( font );

      List<String> lines = new ArrayList<String>();
      StringTokenizer tokenizer = new StringTokenizer( text, "," );
      float sw = 0.0f;
      float sh = 0.0f;
      List<Float> depths = new ArrayList<Float>();
      List<Float> widths = new ArrayList<Float>();
      List<Float> descents = new ArrayList<Float>();
      while ( tokenizer.hasMoreTokens() )
      {
         String s = tokenizer.nextToken();
         float sb = ( float ) font.getStringBounds( s, frc ).getWidth();
         widths.add( sb );
         if ( sb > sw )
         {
            sw = sb;
         }
         lines.add( s );
         LineMetrics lm = font.getLineMetrics( s, frc );
         float depth = lm.getAscent() + lm.getDescent();
         depths.add( depth );
         if ( depth > sh )
         {
            sh = depth;
         }
         descents.add( lm.getDescent() );
      }
      width = sw + 10;
      double padding = sh;
      height = ( descents.size() ) * sh + padding;
      r = new Rectangle2D.Double( x, y, width, height );
      g2d.setColor( getBackground() );
      g2d.fillRect( getX(), getY(), getWidth(), getHeight() );
      g2d.setColor( Color.black );
      g2d.draw( r );
      float dy = 0.0f;
      for ( int i = 0; i < depths.size(); i++ )
      {
         sh = depths.get( i );
         sw = widths.get( i );
         float descent = descents.get( i );
         // scale text to fit and center in r
         float sx = ( float ) ( r.x + ( r.width - sw ) / 2 );
         float sy = dy + ( float ) ( r.y + sh + padding / 2 );
         dy += sh;
         String s = lines.get( i );
         g2d.drawString( s, sx, sy );
      }
   }

   /**
    * @param startX
    * @param startY
    */
   public void setPosition( int startX, int startY )
   {
      x = startX;
      y = startY;
   }
}

现在,事情运作得相当好,除了我在HistoryGraph上得到一个额外的区域,我无法解释位于(0,0)。我已经将HistoryNodes橙色着色以查看发生了什么,并且它位于第一个节点之上。我检查过我只创建了3个节点,只绘制了3个节点。

以下是我得到的照片:

http://jwooten37830.com/~woo/problems/HistoryGraph.JPG

另外,我应该如何设置面板的大小以使外框小于HistoryGraph,但是会有滚动条?我拥有它的方式总是“正确”的大小。如果我的图表变长,我想将外部大小限制为500深,但内部可能是1000。

1 个答案:

答案 0 :(得分:0)

你有两个问题。

第一个是g2.fillRect( getX(), getY(), getWidth(), getHeight() );,第二个是你没有打电话给super.paintComponent

fillRect调用的问题是,当您调用任何绘制方法时,图形上下文已经被转换为组件坐标空间(即组件位置)

这意味着当您致电fillRect时,您实际上是在呼叫getX() + getX(), getY() + getY()

这意味着所有的痛苦都是在组件的左上角位于0x0的概念下完成的。

通过致电super.paintComponent,您将有效地完成您想要实现的目标。

请记住,默认情况下,图形上下文设置为组件背景颜色和字体。因此,如果要将组件绘制为特定颜色,则应设置组件背景颜色(绘制方法的外侧)

请查看Performing Custom PaintingPainting in AWT and Swing了解详情

<强>更新

我很尴尬地说我错过了这个,但是,你不应该这样做......

@Override
public int getHeight()
{
   return ( int ) height;
}

@Override
public int getWidth()
{
   return ( int ) width;
}

@Override
public int getX()
{
   return ( int ) x;
}

@Override
public int getY()
{
   return ( int ) y;
}

Swing框架内部使用这些来定位和调整组件的大小。他们还需要在更改时提供事件通知。改变它们(以你的方式)会产生意想不到的结果(你正在遭受痛苦)......

相关问题