3

在做一个学校项目时,由于这个星期六,我遇到了我遇到过的最烦人的错误。我似乎无法在万维网上的任何地方找到解决方案。甚至我的好老朋友谷歌似乎也让我失望了。那么,问题来了:

我正在使用 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 有关,并且有人有解决此问题的方法吗?

4

3 回答 3

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而不是编写自己的图表库。

于 2012-05-31T18:27:50.367 回答
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 讨论论坛中找到答案:

您忽略了图形上的当前变换,使用以下内容而不是 setTransform():

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

这解决了我所有的问题。

于 2012-06-01T13:35:52.313 回答
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在这种情况下不需要处理

于 2014-02-22T20:34:07.237 回答