JFreeChartのサンプル

参考(ほぼコピペ)

http://kamifuji.dyndns.org/JSupport/JAVA_JFreeChart/BarChart/index.html

 

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

import javax.swing.*;
import java.awt.*;

public class JfcTraning extends JFrame {
public static void main(String[] args){
JfcTraning frame = new JfcTraning();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(10,10,500,500);
frame.setTitle("Sample Graph");
frame.setVisible(true);
}

JfcTraning(){
DefaultCategoryDataset datas = createData();
JFreeChart chart = ChartFactory.createLineChart("輸入量", "年度", "トン(t)",
datas, PlotOrientation.VERTICAL,true,false,false);

ChartPanel cPanel = new ChartPanel(chart);
getContentPane().add(cPanel, BorderLayout.CENTER);

}

private DefaultCategoryDataset createData(){
DefaultCategoryDataset datas = new DefaultCategoryDataset();
datas.addValue(300,"Canada","2010/1");
datas.addValue(500,"Canada","2010/2");
datas.addValue(null,"Canada","2010/3");
datas.addValue(120,"Canada","2010/4");
datas.addValue(240,"Canada","2010/5");

datas.addValue(150,"UK","2010/1");
datas.addValue(700,"UK","2010/2");
datas.addValue(200,"UK","2010/3");
datas.addValue(300,"UK","2010/4");
datas.addValue(100,"UK","2010/5");

 

return datas;
}
}

JSpinner(NumberFormat)の初期値をnullにする(見た目だけ)

目標

画面にJSpinnerが配置されているとする. このとき,初期値が入っていない状態にしたい.

コードサンプル

public class SpinnerGui extends JDialog{
    public static void main(String[] args) {
        SpinnerGui frame = new SpinnerGui();
        frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        frame.setBounds(10,10,300,200);
        frame.setTitle("すぴなー");
        frame.setVisible(true);

    }

    public SpinnerGui() {
        final JSpinner spinner = new JSpinner(new SpinnerNumberModel(0,0,10,1));
        final JTextField spinnerTF = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
        final Color spinnerForeground = spinnerTF.getForeground();
        final Color spinnerBackground = spinnerTF.getBackground();
        spinnerTF.setColumns(5);
        spinner.addChangeListener(new ChangeListener(){
            public void stateChanged(ChangeEvent ce){
                if(((Integer)spinner.getValue()).intValue() == 0){
                  spinnerTF.setForeground(spinnerBackground);
                }
                else spinnerTF.setForeground(spinnerForeground);
              }
            });
        spinnerTF.setForeground(spinnerBackground);
        JPanel p = new JPanel();
        p.add(spinner);
        getContentPane().add(p,BorderLayout.CENTER);
    }
}

だいたい,このページの中身通り.先人に感謝

Is it possible for a JSpinner to show no default value? (Swing / AWT / SWT forum at Coderanch)

Listから,親子関係のあるJTreeを作る

結論を言ってしまうと,TreeNodeをimplementsするのが早い.
間違っても,DefaultMutableTreeNodeだけで何とかしようとなんて思わないこと(3敗).

1.TreeNodeの実装クラス

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;

import javax.swing.tree.TreeNode;

public class MyTreeNode implements TreeNode{
    private String id;
    private MyTreeNode parent;
    private String parentName;
    private String indivisual;
    private List<MyTreeNode> children = new ArrayList<>();

    public MyTreeNode(String code, String indivisual, String parent) {
        this.id  = code;
        this.indivisual = indivisual;
        this.parentName = parent;
    }

    @Override
    public TreeNode getChildAt(int childIndex) {
        return children.get(childIndex);
    }

    @Override
    public int getChildCount() {
        return children.size();
    }

    @Override
    public TreeNode getParent() {
        if(Objects.nonNull(parent)){
            return this.parent;
        }else {
            return null;
        }
    }

    @Override
    public int getIndex(TreeNode node) {
        // TODO 自動生成されたメソッド・スタブ
        return 0;
    }

    @Override
    public boolean getAllowsChildren() {
        return true;
    }

    @Override
    public boolean isLeaf() {
        if(Objects.isNull(children)) {
            return true;
        }else {
            return false;
        }
    }

    @Override
    public Enumeration children() {
        return Collections.enumeration(this.children);
    }

    @Override
    public String toString() {
        return this.indivisual;
    }

    public void add(MyTreeNode futureChild) {
        //
        if(this.getChildCount()>0) {
            for(MyTreeNode node: this.children) {
                System.out.println(node.indivisual);
                if(node.indivisual.equals(futureChild.parentName)) {
                    node.add(futureChild);
                }
            }
        }

        //直属の子として追加
        if(this.indivisual.equals(futureChild.parentName)) {
            this.children.add(futureChild);
        }
    }

}

2. データとツリー作成部分

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;

public class MyTree extends JFrame {
    public static void main(String[] args){

        //List部分
        List<TreeObject> toList = new ArrayList<>();
        toList.add(new TreeObject("10", "root","GG"));
        toList.add(new TreeObject("20", "root","BB"));
        toList.add(new TreeObject("11", "GG", "Sol"));
        toList.add(new TreeObject("12", "GG", "Ky"));
        toList.add(new TreeObject("13", "GG", "Diz"));
        toList.add(new TreeObject("21", "BB", "Jin"));
        toList.add(new TreeObject("22", "BB", "Es"));

        MyTree frame = new MyTree(toList);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(10, 10, 300, 200);
        frame.setTitle("タイトル");
        frame.setVisible(true);
      }

    public MyTree(List<TreeObject> toList) {
        MyTreeNode top = new MyTreeNode("00", "root", "");

        for(TreeObject item: toList ) {
            top.add(new MyTreeNode(item.getCode(), item.getIndividual(), item.getParent()));
        }

        //い つ も の
        JTree tree = new JTree(top);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.getViewport().setView(tree);
        scrollPane.setPreferredSize(new Dimension(280, 180));

        JPanel p = new JPanel();
        p.add(scrollPane);

        getContentPane().add(p, BorderLayout.CENTER);
    }
}

3. 感想

自分がプログラマーじゃないんだなーと思った.
まあ,続けるんですけどね?この仕事.楽しくはあるので.

頑張ってサニタイズする

サニタイズじゃなくて,バリデートともいうらしい. 相変わらず未完.

public class SqlSanitizer {
    public static String spaceReplacer(String sentence) {
        String after = sentence.replace(" ", ",");
        after = after.replace(" ",",");
        return after;
    }

    public static String[] splitParser(String sentence) {
        String after = sentence.replaceAll(",+", ",");
        return after.split(",");
    }

    public static boolean kakkoChecker(String[] sentence) {
        int sCounter = 0;
        int eCounter = 0;
        for(String s: sentence) {
            if(s.equals("(")) sCounter++;
            if(s.equals(")")) eCounter++;
        }

        return sCounter == eCounter ? true:false;
    }
}

ローカルのJsonファイルを読み込む(JSonic利用)

Jsonicっていう,JavaJsonを扱うライブラリを利用することになりました.
相変わらず,分からない.ので調べた.

1.利用するデータ

{
    "x1":["Indigo","3"],
    "x2":["Rot","2"]
}

2.取り込み用クラス

json側のキー名と,フィールドのプロパティ名が一致していることが味噌.

public class ListData {

    private String[] x1;
    private String[] x2;
    public String[] getX1() {
        return x1;
    }
    public void setX1(String[] x1) {
        this.x1 = x1;
    }
    public String[] getX2() {
        return x2;
    }
    public void setX2(String[] x2) {
        this.x2 = x2;
    }
}

3.Json取得クラス

今回は,Mapとして調理します.迫真のクソコード

public class JsonPractice {
    private String filepath = "テキトーなファイルパス\\setjson.json";

    public Map getList() {

        FileInputStream fis;
        try {
            fis = new FileInputStream(filepath);
            Map ldata = (Map)JSON.decode(fis);
            return ldata;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }
}

4.結果

うまくとれてるっぽいですよ?

class JsonPracticeTest {

    @Test
    public void TestGetListdata() {
        JsonPractice jsp = new JsonPractice();
        Map<String,List<String>> ldata = jsp.getList();
        List<String> x1 = ldata.get("x1");
        assertThat(x1.get(0), is("Indigo"));
    }
}

もっと楽なjsonの扱い方ないんだろうか? 調べが雑なのは認める...

JComboBoxの状態に応じて,JPanelの中身を切り替える

やりたいことはタイトル通り
コードの解説的なものは,いつか書く
あと,割とクソコード
あと,コード間違ってる気がする(なら公開するな)

コードそのもの

public class PanelPractice extends JFrame{
    public static void main(String[] args) {
        PanelPractice frame = new PanelPractice();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(10, 10, 300, 100);
        frame.setTitle("タイトル");
        frame.setVisible(true);
    }

    private JTextField txt = new JTextField(3);
    private JComboBox comb2 = new JComboBox<String>();

    PanelPractice(){
        JButton button1 = new JButton("Button1");
        JButton button2 = new JButton("Button2");
        JButton button3 = new JButton("Button3");

        JPanel p = new JPanel();
        p.setLayout(new GridLayout());

        JPanel vpanel = new JPanel();
        vpanel.add(txt);

        //JCombo
        String[] data = {"Ky","Sol"};
        JComboBox cmb = new JComboBox<String>(data);
        cmb.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                String selectedItem = (String)cmb.getSelectedItem();
                Runnable changeComp = new Runnable() {

                    @Override
                    public void run() {
                        if(Objects.isNull(selectedItem)) {
                            return;
                        }else if(selectedItem.equals("Ky")) {
                            vpanel.remove(comb2);
                            vpanel.add(txt);
                            vpanel.validate();
                            pack();
                        }else {
                            vpanel.removeAll();
                            vpanel.add(comb2);
                            vpanel.validate();
                            pack();
                        }
                    }
                };
                SwingUtilities.invokeLater(changeComp);

            }
        });
        cmb.setSelectedItem(null);

        p.add(cmb);
        p.add(vpanel);
        p.add(button3);

        getContentPane().add(p, BorderLayout.CENTER);
    }
}

(投稿した1分後に,修正部分見つかったよ・・・)

Java Swingで,値検査(年月日)とフル桁遷移を実現する

業務でJava Swingを利用することになったんですが・・・.しらねえ. 基本的なことはググれば分かるんですが,タイトルのネタ二つがよくわからなかったので,調べてみた

1.値検査(年月日)

一言でいうと,JFormattedTextFieldっていうコンポーネントを使い,そのコンポーネントにDocumentListener()っていうリスナーを刺せばOK. JFormattedTextFieldは,引数として渡されたフォーマット形式(SimpleDateFormatとか)どおりに,書式を整えてくれるもの. DocumentLisnerは,テキストフィールドの変化(入力・削除など)に対するリスナー.

以下,具体的なコード.オリジナルのコードから,必要な部分を切り取っただけなので,動かないかも.

public class HavingDataChecker extends JFrame{
    private JFormattedTextField text1;

    public static void main(String[] args) {
        HavingDataChecker frame = new HavingDataChecker();

        //set close event
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //set window title
        frame.setTitle("JFormattedTextField Sample");

        //set frame coordinaiton
        frame.setBounds(100,200,450,250);

        //visible frame
        frame.setVisible(true);
    }

    public HavingDataChecker() {
        JPanel panelBase = new JPanel();

        //define format
        SimpleDateFormat nf1 = new SimpleDateFormat("MM");

        //create textfield
        text1 = new JFormattedTextField(nf1);

        //add listener to textfield
        text1.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void removeUpdate(DocumentEvent e) {
                // TODO 自動生成されたメソッド・スタブ
                checkMonth(text1);
            }

            @Override
            public void insertUpdate(DocumentEvent e) {
                // TODO 自動生成されたメソッド・スタブ
                checkMonth(text1);
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // TODO 自動生成されたメソッド・スタブ
                checkMonth(text1);
            }
        });

        //set item size
        text1.setPreferredSize(new Dimension(180,20));

        //add textfield to panel
        panelBase.add(text1);

        //add panel
        getContentPane().add(panelBase);

    }

    private void checkMonth(JTextField from) {
        Runnable docheck = new Runnable() {
            @Override
            public void run() {
                // TODO 自動生成されたメソッド・スタブ
                String insertedString = from.getText();
                if(!(insertedString.equals(""))) {
                    int value = Integer.parseInt(insertedString);
                    if(value > 12) {
                        from.setText("");
                    }
                }
            }
        };
        SwingUtilities.invokeLater(docheck);
    }
}

重要なのはこの辺

1-1. JFormattedTextField作成部分

//define format
SimpleDateFormat nf1 = new SimpleDateFormat("MM月");

//create textfield
text1 = new JFormattedTextField(nf1);

上の方で,書式(この場合は,年月日の「月」部分)を指定している. 下の部分で,JFormattedTextFieldを作成する.

1-2. 値検査

DocumentListenerの刺し方はこんな感じ.

//add listener to textfield
text1.getDocument().addDocumentListener(new DocumentListener() {

    @Override
    public void removeUpdate(DocumentEvent e) {
        // TODO 自動生成されたメソッド・スタブ
        checkMonth(text1);
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        // TODO 自動生成されたメソッド・スタブ
        checkMonth(text1);
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
        // TODO 自動生成されたメソッド・スタブ
        checkMonth(text1);
            }
});

今回は,「月」の型検査をやりたい.なので,「13」以上の値が入力されたら,空文字に置換する. ただ,EDTの関係があるので,処理はRunnableインタフェースを実装しなければいけない.

private void checkMonth(JTextField from) {
    Runnable docheck = new Runnable() {
        @Override
        public void run() {
            // TODO 自動生成されたメソッド・スタブ
            String insertedString = from.getText();
            if(!(insertedString.equals(""))) {
                int value = Integer.parseInt(insertedString);
                if(value > 12) {
                    from.setText("");
                }
            }
        }
    };
    SwingUtilities.invokeLater(docheck);

}

(「0月」を許容しているのはご愛嬌・・・.サンプルコードだから・・・)

2.フル桁遷移

年月日の「年」を入れたら,「月」のテキストフィールドに自動的に移動するやつのこと. 実装方法は, めっちゃ簡単.JTextField.getCaretPosition() っていうのを使えば,「現在のカーソル位置」を取得できる.何らかのリスナーを実行した後に,この値を取得すればいい. 移動先のテキストフィールドの指定は,JTextField.requestFocus()でOK. 私は,こんなコードにまとめた.遷移元と遷移先を指定する感じ.

private void goNext(JTextField from, JTextField to) {
    if(from.getCaretPosition() == 1) {to.requestFocus();};
}

とりあえず,こんな感じでおわり.

3. 既知の問題点

所定の値以外が入力された後の値がへん

例えば「13」っていれると,強制的に「12」が入る. 空文字を入れたはずなのに・・・

SimpleDateFormat("MM") をSimpleDateFormat("DD")に変えた後に, 「31」とかを入力すると, 「31」が入力されるので,SimpleDateFormatまたはJFormattedTextField側の問題だと推測している. 調べなきゃ・・・.

例外処理をしていないので「あああ」とかを入れると,実行時エラーが出る

NumberFormatException(?)が出ます.まじめに制御すればいいので,致命傷ではない(と思っている). いつか,解決版に更新するかも.