2012-05-31 3 views
3

Во время работы над школьным проектом, в связи с этим в субботу, я столкнулся с самой досадной ошибкой, с которой я когда-либо сталкивался. Я не могу найти решение в любой точке мира. Даже мой добрый старый друг Google, похоже, подвел меня. Итак, вот вопрос:Содержание перехода JTabbedPane после переключения

Я работаю с JTabbedPane. В этой JTabbedPane я покажу несколько JPanes, каждый из которых показывает их информацию. В одном из JPanes я рисую гистограмму.

При проверке гистограммы отдельно, все работает отлично. Это также происходит, когда я загружаю свою информацию, находясь на правой вкладке JTabbedPane. Однако, как только я вернусь к этой вкладке, гистограмма сдвинется во время рисования, и все выглядит искаженно и т. Д. (См. Рис.).

Я знаю, что я всегда рисую в правильных координатах, поэтому это должен быть мой JPanel, состоящий из вкладок JTabbedPane. У вас есть какие-то представления о том, что вызывает это странное поведение?

enter image description here Право: как это должно быть. Слева: как это выглядит после переключения на эту вкладку.

Мой BarGraphPanel класс настоящий хаос, вот код:

/* 
* To change this template, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package gui; 

import java.awt.Color; 
import java.awt.FontMetrics; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.geom.AffineTransform; 
import java.text.DecimalFormat; 
import java.util.ArrayList; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 

/** 
* 
* @author Scuba Kay 
*/ 
public class BarGraphPanel extends JPanel implements ManagementPanel { 


private ArrayList<String[]> info; 
    private String infoName; 
    private double maxValue; 
    private int size; 
    private int barWidth; 
    private double left; 
    private double right; 
    private double width; 
    private double height; 
    private double bottom; 
    private double top; 
    private int barSpacing; 
    private double barPart; 
    private double graphHeight; 
    private double graphWidth; 
    private int cap; 

    public BarGraphPanel(){ 
     super(); 

     width = 600; 
     height = 480; 
     setSize((int) width, (int) height); 

     // The maximum number of results to show 
     cap = 30; 

     this.infoName = "Management information"; 
     this.add(new JLabel("This query is not suited for Bar Graph view: please select another one.")); 
    } 

    /** 
    * Sets both x and y, min and max and the info list 
    * @author Kay van Bree 
    * @param info 
    */ 
    @Override 
    public void setManagementInfo(ArrayList<String[]> info) { 
     reset(); 
     this.info = info; 

     // Set important values 
     this.maxValue = getMaxValue(info); 
     this.size = info.size(); 

     setSizes(); 
     repaint(); 
    } 

    /** 
    * Resets the panel, taken from TablePanel 
    * @author Joepe Kemperman 
    */ 
    public void reset() { 
     removeAll(); 
     invalidate(); 
     validate(); 
    } 

    /** 
    * Set the sizes needed for calculating bar heights etc. 
    * @author Kay van Bree 
    */ 
    protected void setSizes(){  
     left = (width/100) * 7; 
     right = width - left*3; 
     top = (height/100) * 7; 
     bottom = height - top*3; 

     // The dimensions of the graph 
     graphHeight = bottom - top; 
     graphWidth = right - left; 

     // barWidth is... Just guess what it is. 
     barWidth = (int) ((double) (graphWidth/size) * 0.95); 

     // barSpacing is the space between the bars 
     barSpacing = (int) (graphWidth - (barWidth*size))/size; 
     if(barSpacing == 0){ 
      barSpacing++; 
      barWidth--; 
     } 

     // barPart is the height of a bar of value 1 
     barPart = graphHeight/maxValue; 
    } 

    /** 
    * Return the max value of the info arraylist 
    * @author Kay van Bree 
    * @param info 
    */ 
    private int getMaxValue(ArrayList<String[]> info){ 
     int max = 0; 
     for(String[] row: info){  
      if(Integer.valueOf(row[1]) > max){ 
       max = Integer.valueOf(row[1]); 
      } 
     } 
     return max; 
    } 

    /** 
    * Draw the damn thing! 
    * @author Kay van Bree 
    * @param g 
    */ 
    @Override 
    protected void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     if(info != null){ 
      g.setColor(Color.BLACK); 
      drawTitle(g); 
      drawBlocks(g); 
      if(size <= cap){ 
       drawBars(g); 
      } else { 
       drawError(g); 
      } 
      drawAxes(g); 
     } else { 
      this.setInformationNotSuitable(); 
     } 
    } 

    /** 
    * Set an error displaying to many results 
    * @author Kay van Bree 
    * @param g 
    */ 
    private void drawError(Graphics g){ 
     g.setColor(Color.BLACK); 
     g.drawString("Too many results to show!", (int)(right-left*2)/2, (int)(bottom-top*2)/2); 
    } 

    /** 
    * Draw the names under the bars 
    * @author Kay van Bree 
    * @param g 
    */ 
    private void drawName(Graphics g, String name, int x){ 
     Graphics2D g2d = (Graphics2D)g; 

     // clockwise 90 degrees 
     AffineTransform at = new AffineTransform(); 
     // thanks to M.C. Henle for the bug fix! 
     at.setToRotation(Math.PI/2.0, x + (barWidth/4), bottom + 3); 
     g2d.setTransform(at); 

     g2d.setColor(Color.BLACK); 
     g2d.drawString(name, (int) (x + (barWidth/4)), (int) bottom + 3); 

     g2d.setTransform(new AffineTransform()); 
    } 

    /** 
    * Draw the lines behind the bars 
    * @author Kay van Bree 
    * @param g 
    */ 
    private void drawBlocks(Graphics g){ 
     g.setColor(Color.lightGray); 
     // Ten parts 
     double part = maxValue/10; 
     double total = maxValue; 

     // Draw the numbers 
     for(int i=0; i<10; i++){ 
      double y = (((bottom-top)/10)*i)+top; 
      g.drawLine(((int) left)-5, (int) y, ((int) right), (int) y); 
     } 
     g.drawLine((int) right, (int) top, (int) right, (int) bottom); 
    } 

    /** 
    * Draw the title of the Graph 
    * @author Kay van Bree 
    * @param g 
    */ 
    private void drawTitle(Graphics g){ 
     int tLeft = 100; 
     g.drawString(infoName, tLeft, (int) top/2); 
    } 

    /** 
    * Draw the axes of this Bar Graph 
    * @author Kay van Bree 
    * @param g 
    */ 
    private void drawAxes(Graphics g){ 
     g.setColor(Color.BLACK); 
     // draw lines from (x, y) to (x, y) 
     g.drawLine((int) left, (int) top, (int) left, (int) bottom); 
     g.drawLine((int) left, (int) bottom, (int) right, (int) bottom); 

     // Ten parts 
     double part = maxValue/10; 
     double total = maxValue; 

     // Draw the numbers 
     for(int i=0; i<10; i++){ 
      double y = (((bottom-top)/10)*i)+top; 
      String number = round(total); 
      FontMetrics fontMetrics = g.getFontMetrics(); 
      g.drawString(number, (int) (left * 0.80) - fontMetrics.stringWidth(number), ((int) y)+5); 
      total = (total - part); 
      g.drawLine(((int) left)-5 , (int) y, ((int) left), (int) y); 
     } 
    } 

    /** 
    * Rounds the number to 1 decimal 
    * @author Kay van Bree 
    * @param number 
    * @return 
    */ 
    private String round(double number){ 
     DecimalFormat df = new DecimalFormat("#.#"); 
     Double dubbel = new Double(number); 
     return df.format(dubbel); 
    } 

    /** 
    * Round a number, make it int 
    * @author Kay van Bree 
    * @param number 
    * @return 
    */ 
    private int roundToInt(double number){ 
     DecimalFormat df = new DecimalFormat("#"); 
     Double dubbel = new Double(number); 
     return Integer.valueOf(df.format(dubbel)); 
    } 


    /** 
    * We need info right? 
    * Then draw the damn bars already! 
    * @author Kay van Bree 
    * @param g 
    */ 
    private void drawBars(Graphics g){  
     double currentX = left + barSpacing + 1; 
     for(String[] row: info){ 
      double value = Integer.valueOf(row[1]); 
      double barHeight = (value * barPart); 

      System.out.println("Value: " + value + " height: " + barHeight + " top: " + top); 
      double barStart = bottom - barHeight; 
      System.out.println("Barstart: " + barStart); 
      barHeight = ((int) bottom - (int) barStart); 
      g.setColor(Color.BLUE); 
      g.fillRect((int) currentX, (int) barStart, (int) barWidth, roundToInt(barHeight)); 
      drawName(g, row[0], (int) currentX); 

      currentX = (currentX + barSpacing + barWidth); 
     } 
    } 

    public void setInformationNotSuitable() { 
    //  JOptionPane.showMessageDialog(this, "This query is not suited for Bar Graph view. Please select another", "INSANE WARNING!", JOptionPane.WARNING_MESSAGE); 
    } 
} 

Некоторые полезны информация:

setManagementInformation вызывается один раз в JTabbedPane. Здесь он загружает все содержимое (также другие вкладки)

EDIT Оке, поэтому ответ Xeon в почти фиксированная моя проблема. Границы моего графика теперь идеально выравниваются каждый раз, когда я переключаюсь обратно на эту вкладку. Тем не менее, имена под строкой все еще смещаются при переключении назад. Вот мой обновленный код:

/** 
* Draw the names under the bars 
* @author Kay van Bree 
* @param g 
*/ 
private void drawName(Graphics g, String name, int x){ 
    Graphics2D g2d = (Graphics2D) g.create(); 

    // Clockwise 90 degrees 
    AffineTransform at = new AffineTransform(); 
    // Rotate the text 
    at.setToRotation(Math.PI/2.0, x + (barWidth/4), bottom + 3); 
    AffineTransform prev = g2d.getTransform(); 
    g2d.setTransform(at); 

    g2d.setColor(Color.BLACK); 
    g2d.drawString(name, (int) (x + (barWidth/4)), (int) bottom + 3); 

    g2d.dispose(); 
} 

Таким образом, делает это также что-то делать с AffineTransform, и кто-нибудь есть решение этой проблемы?

+0

FYI, в будущем, добавьте [домашнее задание] тег вещи для школьных проектов. (Я добавил его для вас на этот раз.) –

+0

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

+0

Чтобы лучше помочь, опубликуйте [SSCCE] (http://sscce.org/). –

ответ

1

После выполнения некоторых исследований, а также с помощью ответа Xeon в:

/** 
* Draw the names under the bars 
* @author Kay van Bree 
* @param g 
*/ 
private void drawName(Graphics g, String name, int x){ 
    Graphics2D g2d = (Graphics2D) g.create(); 

    // Rotate 
    g2d.rotate(Math.PI/2.0, x + (barWidth/4), bottom + 3); 

    // Print 
    g2d.setColor(Color.BLACK); 
    g2d.drawString(name, (int) (x + (barWidth/4)), (int) bottom + 3); 

    // Reset transformation 
    g2d.dispose(); 
} 

Ответ нашел в OTN Discussion Forums:

Вы игнорируете текущее преобразование на графике, используйте следующую вместо SetTransform() :

g2D.rotate(-Math.PI/2.0, 0, 0); 

Это решение всех моих проблем.

3

Хорошо. Это было сложно:

Проблема заключается в методе drawName - вы преобразовываете экземпляр graphics и не восстанавливаете его - вы просто сбрасываете матрицу преобразования (все значения равны 0).

Вы должны восстановить его:

private void drawName(Graphics g, String name, int x) { 
    Graphics2D g2d = (Graphics2D) g; 

    // clockwise 90 degrees 
    AffineTransform at = new AffineTransform(); 
    // thanks to M.C. Henle for the bug fix! 
    at.setToRotation(Math.PI/2.0, x + (barWidth/4), bottom + 3); 
    AffineTransform prev = g2d.getTransform(); 
    g2d.setTransform(at); 

    g2d.setColor(Color.BLACK); 
    g2d.drawString(name, (int) (x + (barWidth/4)), (int) bottom + 3); 

    g2d.setTransform(prev); 
} 

или вы можете даже использовать:

Graphics2D g2d = (Graphics2D) g.create(); 
    ... 
    // free to manipulate Graphics2D 
    ,,, 
    d2d.dispose(); 

И я предлагаю использовать JFreeChart вместо написания библиотеки собственных диаграмм.

+1

+1 за предложение JFreeChart. –

+0

Проблема в том, что мы не можем использовать сторонние библиотеки, потому что это школьный проект. Вероятно, я бы использовал его. –

+0

Спасибо, это фиксировало мои бары и топоры! Однако имена все еще искажены, поэтому я редактировал свой вопрос. –

0

записочку, если кто-то будет использовать AffineTransform непосредственно:

protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    final Graphics2D g2d = (Graphics2D) g; 
    final AffineTransform oldT = g2d.getTransform(); 
    try { 
     final AffineTransform t = g2d.getTransform(); // returns a copy! of current transform 
     t.concatenate(viewMatrix); // so we can modify it 
     g2d.setTransform(t); 
     // draw... 
    } finally { 
     // restoring transform 
     g2d.setTransform(oldT); 
    } 
} 

Располагая Graphics2D это не обязателен в этом случае

Смежные вопросы