2013-04-29 1 views
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.

ответ

0

У вас есть две проблемы.

Первый g2.fillRect(getX(), getY(), getWidth(), getHeight());, второй вы не вызывая super.paintComponent

Проблемы с вами fillRect вызовом является то, что к тому времени, любым из ваших методов рисований называется, графический контекст уже переведен скоординировать компоненты пространство (т.е. положение компонентов)

Это означает, что при вызове fillRect, вы фактически вызывая getX() + getX(), getY() + getY()

Это означает, что все painitng делается с концепцией, что верхний, левый угол компонента равен 0x0.

Позвонив по телефону super.paintComponent, вы будете эффективно выполнять то, что вы пытаетесь достичь.

Просто помните, что графический контекст установлен на цвет фона и шрифт компонентов по умолчанию. Так что если вы хотите, чтобы нарисовать ваш компонент определенного цвета, вы должны установить цвет фона компоненты (из стороны методов краски)

Посмотрите на Performing Custom Painting и Painting in AWT and Swing для получения более подробной информации

Обновленные

Я вроде embarressed сказать, что я пропустил это, но вы не должны быть doining это ...

@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; 
} 

это использование свинга framewo rk внутренне для размещения и размера вашего компонента. Они также обязаны предоставлять уведомление о событии при изменении. Изменение их (в том виде, как у вас есть) может иметь неожиданные результаты (которые вы страдаете) ...

+0

Спасибо за помощь. Наверное, я что-то не понимаю.Я удалил все fillRect и добавил super.paintComponent, где он отсутствовал. Теперь я устанавливаю фон HistoryGraph в основной программе. Я получаю полный зеленый фон, а HistoryNodes также зеленый, а квадрат lightGray в верхнем левом углу - 0,0. Как это получается? То есть без fillRects, я получаю то же самое, что и раньше, без апельсиновых квадратов и одного светло-серого в верхнем левом углу. –

+0

Я заметил, что он рисует правильно, но любое событие изменения размера приводит к появлению дополнительных фигур в верхнем левом углу, оставляя все остальное в одиночестве. Я прочитал источники, о которых вы упоминали, но ничего не видите о нескольких рисунках, как я делаю, и не вижу, где я отклонился. –

+0

При чтении, все еще не понимая, как я получаю HistoryGraph для отображения его компонента HistoryNodes. Документация говорит, что я не должен сам называть paintComponent. Если я не использую метод PaintComponent в HistoryGraph, узлы не получаются! Если да, то они рисуются правильно, но изменение размера создает артефакты. Что я не правильно храню в HistoryNode или HistoryGraph для перерисовки? –