3

今週の土曜日に予定されている学校のプロジェクトに取り組んでいるときに、これまでに遭遇した中で最も厄介なバグに遭遇しました。World Wide Web のどこにも解決策が見つからないようです。私の古き良き友人である Google でさえ、私をがっかりさせているようです。それで、ここに質問があります:

私は JTabbedPane で作業しています。この JTabbedPane では、さまざまな JPane を表示し、それぞれの情報を示します。JPanes の 1 つで、棒グラフを描画しています。

棒グラフを個別にテストすると、すべて正常に動作します。JTabbedPane の右側のタブで自分の情報をロードするときにも同様です。ただし、このタブに戻るとすぐに、ペイント中に棒グラフが上に移動し、すべてが歪んで見えます (写真を参照)。

私は常に正しい座標で描画していることを知っているので、JTabbedPane のタブの代わりに JPanel を使用する必要があります。この奇妙な動作の原因について何か考えはありますか?

ここに画像の説明を入力 右:あるべき姿。左: このタブに戻った後の外観。

私の 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 によって 1 回呼び出されます。ここですべてのコンテンツをロードします (他のタブも)

EDIT Okeなので、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と関係がありますか?この問題の解決策はありますか?

4

3 に答える 3

3

Ok。それはトリッキーでした:

問題は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();

また、独自の Charts ライブラリを作成する代わりに、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 ディスカッション フォーラムで回答が見つかりました:

Graphics の現在の変換を無視しています。setTransform() の代わりに以下を使用してください。

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

これで私の問題はすべて解決しました。

于 2012-06-01T13:35:52.313 に答える