0

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

迄今为止,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。

4

1 回答 1

0

你有两个问题。

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

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

这意味着当你打电话时fillRect,你实际上是在打电话getX() + getX(), getY() + getY()

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

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

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

查看在 AWT 和 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 框架内部使用这些来定位和调整组件的大小。他们还需要在更改时提供事件通知。改变它们(以你的方式)可能会产生意想不到的结果(你正在遭受)......

于 2013-04-29T22:20:17.820 回答