Propertiesクラスが散らかってるのが気に入らない人のためのクラス

設定ファイル要るな→Propertiesクラス便利→うわ順番めちゃくちゃやん
→作ろう

import java.io.*;
import java.util.ArrayList;

/**
 *
 * @author standstonecraft
 */
public class MyProperties {

    private ArrayList<String> keyList;
    private ArrayList<String> valList;

    public MyProperties() {
    }

    public void load(FileInputStream fis) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
        loadP(br);
    }

    public void load(FileInputStream fis, String encoding) throws UnsupportedEncodingException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(fis, encoding));
        loadP(br);
    }

    private void loadP(BufferedReader br) throws IOException {
        String s;
        keyList = new ArrayList<>();
        valList = new ArrayList<>();
        while ((s = br.readLine()) != null) {
            if (s.charAt(0) != '/') {
                String ss[] = s.split("=", 2);
                keyList.add(ss[0]);
                valList.add(ss[1]);
            }
        }
        br.close();
    }

    public String getProperty(String key, String value) {
        int i = keyList.indexOf(key);
        if (i > -1) {
            return valList.get(i);
        }
        return value;
    }

    public void setProperty(String key, String value) {
        int i = keyList.indexOf(key);
        if (i > -1) {
            keyList.remove(i);
            valList.remove(i);
        }
        keyList.add(key);
            valList.add(value);
    }

    public void setComment(String comment) {
        keyList.add(comment);
        valList.add(null);
    }

    public void store(FileOutputStream fos) throws IOException {
        String s;
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
        storeP(bw);
    }

    public void store(FileOutputStream fos, String encoding) throws UnsupportedEncodingException, IOException {
        String s;
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, encoding));
        storeP(bw);
    }

    public void store(FileOutputStream fos, String comment, String encoding) throws UnsupportedEncodingException, IOException {
        keyList.add(0, comment);
        valList.add(0, null);
        String s;
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, encoding));
        storeP(bw);
    }

    private void storeP(BufferedWriter bw) throws IOException {
        for (int i = 0; i < keyList.size(); i++) {
            String v=valList.get(i);
            if (v==null) {
                bw.write("//");
                bw.write(keyList.get(i));
            }else{
                bw.write(keyList.get(i)+"="+v);
            }
            bw.newLine();
        }
        bw.close();
    }
}

長々と書きました
これを使うと設定ファイルが格納した順になります
すでにPropertiesを使ってる場合Propertiesの頭にMyをつければ使えるようにしたかったのですが、
文字コード指定とかポリモルフィズムの関係で妥協してます
loadやstoreのあたりの引数にご注意ください

他に注意事項としては、
・本家と同じようにキーと値は=で分けること(ファイルを直接いじる場合の注意)
・行区切りにすること
・独自機能としてsetComment(String)すると文頭に//がついたコメントとして格納されること
・コメントはキーと同じように格納した順番、場所に格納されること
・キーはそれぞれ異なる名前でなければならないこと(被ってる場合上にある方が使われます)
・getPropertyで返ってくるのはもちろんString
XMLのメソッドとかキーリストを出すメソッドはないです

多分動きます
雑魚グラマなので冗長なところとか無駄なところとか要らないところとか間違ってるところとかあると思いますがご愛嬌です

設定ファイルを使う

コンフィグファイルが必要になる機会は結構多いですよね
特に記憶する内容がなくても、ウィンドウの位置や大きさは保持したいものです
テキストを入出力するクラスはあるし行単位で読みこめばそう難しいことでもないのですが、
設定ファイルを操作するPropertiesクラスがあります

//        読み込み-----------------------------
        Properties prop =new Properties();
        
        FileInputStream fis=new FileInputStream("setting.txt");
        prop.load(fis);
        fis.close();

//        文字コードを指定する場合は下記のように
//        InputStreamReader isr=new InputStreamReader(fis, "SJIS");
//        prop.load(isr);
//        isr.close();

//        値を読み込む
        String s1=prop.getProperty("hoge");//キーを指定して値を読み込みます(個人的に非推奨)
        String s2=prop.getProperty("bar", "zako");//キーが無かった時のデフォルト値を決めておきます(推奨)
        
//        したいことをする
        
//        書き込み-----------------------------
        prop.setProperty("hoge", s1);
        prop.setProperty("bar", s2);
        
        FileOutputStream fos=new FileOutputStream("setting.txt");
        prop.store(fos, "English only");//ファイル冒頭にコメントをつけることができる
        fos.close();

//        文字コードを指定する場合は下記のように
//        OutputStreamWriter osw=new OutputStreamWriter(fos, "SJIS");
//        prop.store(osw, "日本語おーけー");
//        osw.close();
    }

まあ便利です
文字コードについてはJava文字列メモ(Hishidama's Java String Memo)
に詳しく乗ってます。ひしだま様も神様ですね
この方とJavaの学習ならJavaDriveのTATSUO IKURA様お二方のサイトが潰れない限りなんでも作れる気がします
万が一のためにごっそり保存したいくらいです

ここにあるやり方でファイルを生成すると、bar=zakoみたいな形式で一行ずつ書かれたファイルができます
loadFromXMLとstoreToXMLを使えばxml形式にすることもできます

このクラスの唯一そして最大の欠点は、生成されるファイルは、キーを格納した順番にならないということです
もし細かい設定でアプリ上に設定項目がなく、変えたかったらファイルいじってね、と言う仕様の場合見難いことこの上ないです
最近それに耐えられなくなり、自分でパクリクラスを作りました
次回にでも紹介します

文字列を置換したい、でも制御文字だからできないそんなとき

Windowsでは、ファイルのパスを「C:\hoge\bar」などのように表します
しかし他のOSでは「/hoge/bar」などのように表します
JavaのいいところはどんなOSでも動くところ、でも気をつけないとこの記号の違いでファイル操作がうまくいきません
Windows限定のソフトなら、Fileクラスで\記号のまま扱えるのですが、配慮するなら記号を置換してURIクラスとかで操作する必要が出てきます
僕みたいなニワカはmac◯ね、iTunes少しは黙れ、とかUNIX系統は自分で作ればいいだろ、キモいソフト名でもつけて、など酷い偏見を抱きがちですが


このときニワカな僕だと最初にreplaceAll("\\","/");で余裕だと考え実行するのですがエラーがでてしまいます
こういう文字列を検索する系のメソッドは正規表現を用いるので\記号がそれにひっかかってしまうらしいです
そこで文字列をchar配列にして、一文字ずつ\が無いか探し、あれば/に置き換え、最後に配列を文字列に戻すメソッドを作ります

    public String tiltSlash(String src) {
        char[] c=src.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i]=='\\') {
                c[i]='/';
            }
        }
        return String.copyValueOf(c);
    }

気をつけるのは最後の行、NetBeansでサジェストされてc.toStringを使いたくなりますがこれだと意図しない文字列が返ってきます

ググるとすとりんぐばっふぁーとか小難しいのを使った長いメソッドが出てきますがこれで充分だと思います

次回はこれ使ってJavaでブラウザとかエクスプローラーを開く方法なんかを書こうかなと思います

ぐぐるで思い出した、tiltという単語をググると検索画面が…

7セグメントディスプレイにアルファベットを表示してみる

前回公開したクラスは何もいじらない状態では数字+記号2つしか表現できません
しかしラジカセ(化石)などでは"no disc"のようなメッセージが表示されます
7セグメントには一応アルファベットの対応が決められているんですが、相当読みづらいです
とりあえず自作の7セグに実装してみます

public class AlphabetsSegment {

    public ArrayList<boolean[]> alphabet;

    public AlphabetsSegment() {
        alphabet=new ArrayList<>();
        alphabet.add(new boolean[]{true, true, true, false, true, true, true});
        alphabet.add(new boolean[]{false, false, true, true, true, true, true});
        alphabet.add(new boolean[]{false, false, false, true, true, false, true});
        alphabet.add(new boolean[]{false, true, true, true, true, false, true});
        alphabet.add(new boolean[]{true, false, false, true, true, true, true});
        alphabet.add(new boolean[]{true, false, false, false, true, true, true});
        alphabet.add(new boolean[]{true, false, true, true, true, true, false});
        alphabet.add(new boolean[]{false, false, true, false, true, true, true});
        alphabet.add(new boolean[]{false, false, true, false, false, false, false});
        alphabet.add(new boolean[]{false, true, true, true, true, false, false});
        alphabet.add(new boolean[]{true, false, true, false, true, true, true});
        alphabet.add(new boolean[]{false, false, false, true, true, true, false});
        alphabet.add(new boolean[]{true, true, true, false, true, true, false});
        alphabet.add(new boolean[]{false, false, true, false, true, false, true});
        alphabet.add(new boolean[]{false, false, true, true, true, false, true});
        alphabet.add(new boolean[]{true, true, false, false, true, true, true});
        alphabet.add(new boolean[]{true, true, false, true, true, true, true});
        alphabet.add(new boolean[]{false, false, false, false, true, false, true});
        alphabet.add(new boolean[]{false, false, true, true, false, true, true});
        alphabet.add(new boolean[]{false, false, false, true, true, true, true});
        alphabet.add(new boolean[]{false, false, true, true, true, false, false});
        alphabet.add(new boolean[]{false, true, true, true, true, true, false});
        alphabet.add(new boolean[]{false, true, true, true, true, true, true});
        alphabet.add(new boolean[]{false, true, true, false, true, true, true});
        alphabet.add(new boolean[]{false, true, true, true, false, true, true});
        alphabet.add(new boolean[]{true, true, false, true, true, false, false});

    }
}

こんなクラスを作っておいて、

Seg7Character chara=new Seg7Character();
        AlphabetsSegment as=new AlphabetsSegment();
        for (int i = 0; i < 26; i++) {
            try {
                chara.addCharacter(as.alphabet.get(i));
            } catch (Exception ex) {
                Logger.getLogger(seg7Test.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

とこんな感じです
自作文字は順にアルファベットの名前がつくので奇跡的にa=aとなります
そんでもって表示してみます

iとsが苦しいですね。これでもwikipedia仕様なのに

次に作るべきは16セグメントディスプレイかもしれませんね
これだとすっごくわかりやすくなります

7セグメントディスプレイ公開

前回画像で紹介した、数字をデジタルに表示するためのライブラリを作りました
デジタル時計とかストップウォッチなんかを作るときに若干見栄えが良くなるので使って見て欲しいです(明らかな検索用)

プログラム例兼、簡単なレイアウト見本としてサンプルプログラムも入れてあります
ウィンドウの大きさを変えると連動して文字サイズも変わり、各種設定はボタンとツマミでできるので、線の太さや隙間などのパラメータの組み合わせなんかを決めたり、色の組み合わせを考えたりが少し楽になると思います
設定項目は多いですが基本的には初期値でもしっかり表示されるのですこしずつカスタムしていけると思います

ダウンロードはここから

特にやりたいことがなくても表示するだけでちょっと厨二心や創作意欲がわきますのでどうぞ

補足0
.jarファイルをダウンロード後、netbeansのプロジェクトのライブラリを右クリ、JAR/フォルダを追加をクリックしてファイルを指定すればOKです

補足1
普通の文字の大きさ(12pt前後)だと綺麗な表示が期待できません
また大きさは縦横比固定で、高さだけに依存しています

補足2
文字に対応したセグメントの情報は別クラスで管理しています
デフォルトでは0から9とハイフン"-"、空白" "が入っていて、オリジナルの文字を追加できます
Seg7クラスで文字をセットするときデフォルトはそのままの文字でセットできますが、追加した文字は順にアルファベット小文字の一文字で指定します(たとえば1個追加したならそれはa)
正直、このクラスに直接セグメント情報を書き込んだほうが楽

補足3
時計などで必要な「:」(コロン)は文字数1で作ってsetmode(1);すると作れます
また表示の有無はsetDot(boolean)とかtoggleDot()でできるので点滅も簡単です

図形を描画する(画像処理)

GUIを作っている時、画像を生成したり表示したりしたいときがあります
ペイントソフトが代表例として挙げられますが、画像を描くのが主目的でなくてもあると便利な場合はあります
今「あります」とタイプしながら何も思い浮かばなかったので自分の使用例をあげてみます


これは以前紹介したエニグマ暗号機のプラグボードと呼ばれる、要は1〜6の数字を入れ替えるものです
これを文字だけでやろうとすると「1→2、2→6」などと書くしかなく、どれがどうつながっているか想像しにくいです
手間はかかりますがロマンです


これはグラフ描画ソフトです
グラフといっても折れ線とか棒の数値を表すグラフではなく物の関連とか経路とかを視覚化するもので、このソフトでは彩色問題(繋がってる点同士が同じ色にならないよう最低限の色数で着色する問題)が解けます、といっても力技ですが


これは僕の自信作で7セグメントディスプレイを描画するAPIです
数字を書くソフトではなく、ストップウォッチとか電卓とかで見栄えがいいのを作りたい時に呼び出す関数群(という意味でカッコつけてAPIって言ってみたけど合ってるかわからない)です
作ってみたところわりと使いやすくて細かい設定(各種色、大きさ、太さ、傾きの有無、オリジナル文字作成)ができるようになったので、
javadoc(説明書)が書けたら公開しようと思います
本当は手前味噌をネットにぶちまけるなんて真似したくないんですが、「java 7セグメント」とかでググってもソースも画像も見つからなかったので、あったらいいのになと思っている同志が万が一いた時のために、です


ざっと見ただけで、曲線、(角丸)四角形、楕円、多角形など基本的な図形が色、太さ自由自在に描画できているのがわかると思います
プログラムで図形…と想像すると死ぬほど手間がかかりそうな予感がするものですがさすがJavaさんです
四角形一つ書くだけならほんの数行、初見でもコピペで数分で出来ます
すごくロマンなのでやってみてください

各種図形描画や座標変換など多数のメソッドを簡単に紹介したいとも思ったのですが、役不足(誤用)です

Java Drive - Java2Dによる画像処理

ここが驚くほど丁寧で行き渡っていて著者の方に惚れそうになります、というか惚れました
あまりにすぐれたサイトですしすでにこの方のサイトに行ったことがある人がほとんどではないでしょうか

というわけで今回具体的なテクニックはありませんが上記の大先生のところへ行けば万事解決ですので、では