在做一个学校项目时,由于这个星期六,我遇到了我遇到过的最烦人的错误。我似乎无法在万维网上的任何地方找到解决方案。甚至我的好老朋友谷歌似乎也让我失望了。那么,问题来了:
我正在使用 JTabbedPane。在这个 JTabbedPane 中,我将展示不同的 JPanes,每个都显示它们的信息。在其中一个 JPanes 中,我正在绘制条形图。
单独测试条形图时,一切正常。当我在 JTabbedPane 的右侧选项卡中加载我的信息时也会这样做。但是,一旦我切换回此选项卡,条形图就会在绘画过程中向上移动,并且看起来全是扭曲的东西(见图)。
我知道我总是在绘制正确的坐标,所以它一定是我的 JPanel 代替了 JTabbedPane 的选项卡。你们对导致这种奇怪行为的原因有任何想法吗?
正确的:它应该是怎样的。左:切换回此选项卡后的样子。
我的 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);
}
}
一些有用的信息:
JTabbedPane 调用一次 setManagementInformation。在这里它加载所有内容(还有其他选项卡)
编辑 Oke,所以至强的回答几乎解决了我的问题。每次我切换回此选项卡时,我的图表条现在都完美对齐。但是,当切换回来时,栏下方的名称仍在移动。这是我更新的代码:
/**
* 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 有关,并且有人有解决此问题的方法吗?