生物屋さんのためのゼロからのプログラミング

―忘れないための覚書 (たま~に更新)―

フリーハンドでROIを描く。

今回はフリーハンドでROIを描くコードを書いてみた。

仕様としては、画像を取り込み、画像の上にマウスでROIを描けるようにした。


実際のソースコードは下記。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;

public class FreeHandROI extends JFrame implements ActionListener {
	
	BufferedImage img;
	MyPanel mypane;
	int h, w;
	int x0, x1, x2, y0, y1, y2;
	
	//画像を開く
	public void OpenImage () {
		try {
			File openFile = new File("開くファイル名");
			img = ImageIO.read(openFile);
			h = img.getHeight();
			w = img.getWidth();
		} catch (IOException ex) {
			System.out.println("miss");
		}
		
		//画像をフレームに貼る
		JFrame imgFrame = new JFrame ("Open Image");
		imgFrame.setBounds (300, 100, w, h);
		imgFrame.setVisible(true);
		mypane = new MyPanel (w, h);
		imgFrame.getContentPane().add(mypane, BorderLayout.CENTER);
		
		mypane.addMouseListener(new MouseCheck());
		mypane.addMouseMotionListener(new MouseCheck());
	}
	
	//マウスの動きをモニター
	class MouseCheck extends MouseInputAdapter {
		
		//マウスが押された時の反応 :始点を得る
		public void mousePressed (MouseEvent e) {
			x0 = x1 = x2 = e.getX();
			y0 = y1 = y2 = e.getY();
		}		
		
		//マウスがドラッグされた時の反応 : ドラッグしている部分に線を引く
		public void mouseDragged (MouseEvent e) {
			Graphics g = mypane.getGraphics();
			x2 = e.getX();
			y2 = e.getY();
			g.setColor(Color.RED);
			g.drawLine(x1, y1, x2, y2);  //(x1, y1)から(x2, y2)に線を引く		
			x1 = e.getX();   //新しいx1の定義
			y1 = e.getY();   //新しいy1の定義
		}
		
		//マウスが離された時の反応 : 終点から始点に線を引く
		public void mouseReleased (MouseEvent e) {
			Graphics g = mypane.getGraphics ();
			x2 = e.getX();
			y2 = e.getY();
			g.setColor(Color.RED);
			g.drawLine(x2, y2, x0, y0); //マウスを離したpointからマウスを押したpointまでに線を引く
		}			
	}
 	
	//画像を貼りつける用のツール
	public class MyPanel extends JPanel {
		public MyPanel (int width, int height) {
			setSize(width, height);
		}
		
		public void paintComponent (Graphics g) {
			g.drawImage(img, 0, 0, this);
		}
	}
	
	//ボタンを押した時のイベント:画像の取り込み
	public void actionPerformed (ActionEvent ae) {
		String cmd = ae.getActionCommand ();
		if (cmd.equals("Open")) {
			OpenImage();
		}
	}
	
	FreeHandROI () {
		JButton button = new JButton ("Open");
		button.addActionListener(this);
		button.setActionCommand("Open");
		button.setBounds(40, 10, 90, 30);
		JPanel pane = new JPanel();
		pane.setLayout(null);
		pane.add(button);
		getContentPane().add(pane, BorderLayout.CENTER);		
	}
	
	public static void main (String[] args) {
		FreeHandROI frame = new FreeHandROI ();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(10, 10, 180, 80);
		frame.setVisible(true);
	} 
}

この部分で、ドラッグした場所に線を引き、マウスを離すとドラッグ開始点まで線を引く。

	//マウスの動きをモニター
	class MouseCheck extends MouseInputAdapter {
		
		//マウスが押された時の反応 :始点を得る
		public void mousePressed (MouseEvent e) {
			x0 = x1 = x2 = e.getX();
			y0 = y1 = y2 = e.getY();
		}		
		
		//マウスがドラッグされた時の反応 : ドラッグしている部分に線を引く
		public void mouseDragged (MouseEvent e) {
			Graphics g = mypane.getGraphics();
			x2 = e.getX();
			y2 = e.getY();
			g.setColor(Color.RED);
			g.drawLine(x1, y1, x2, y2);  //(x1, y1)から(x2, y2)に線を引く		
			x1 = e.getX();   //新しいx1の定義
			y1 = e.getY();   //新しいy1の定義
		}
		
		//マウスが離された時の反応 : 終点から始点に線を引く
		public void mouseReleased (MouseEvent e) {
			Graphics g = mypane.getGraphics ();
			x2 = e.getX();
			y2 = e.getY();
			g.setColor(Color.RED);
			g.drawLine(x2, y2, x0, y0); //マウスを離したpointからマウスを押したpointまでに線を引く
		}			
	}

とりあえず、画像を取り込んでROIが描けるのでOKとした。
次回はROIの中の輝度値の取得を目指そうと思う。

System.currentTimeMillisを用いた処理時間の取得

あるタスクをクリアするのに要した時間を測定するためのソースコードを書いてみた。

ソースコードは下記。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TimeGet extends JFrame implements ActionListener {
	
	static TimeGet frame;
	long startMs;
	
	public void actionPerformed (ActionEvent e) {
		String cmd = e.getActionCommand();
		
		if (cmd.equals("start")) {
           //startボタンが押された時間の取得
			startMs = System.currentTimeMillis();
			System.out.println("SartTime = " + startMs);	
		
		} else if (cmd.equals("end")) {
           //endボタンが押された時間の取得
			long endMs = System.currentTimeMillis();        
			System.out.println("EndTime = " + endMs);

                      //startボタンが押された時間とendボタンが押された時間の差を表示
            System.out.println("interval = " + (endMs - startMs)/1000);
			System.out.println("Time = " + (endMs-startMs)/60000 + " min " + ((endMs-startMs)%60000)/1000 + " sec." );
		}
	}
	
	TimeGet () {
		setTitle("TimeGet");
		setSize(150, 180);		
		JPanel pane = new JPanel ();
		pane.setLayout(null);
		JButton startB = new JButton ("Push");
		JButton endB = new JButton ("End");
		startB.setBounds(20, 20, 80, 40);
		endB.setBounds(20, 70, 80, 40);
		startB.addActionListener (this);
		endB.addActionListener(this);
		startB.setActionCommand("start");
		endB.setActionCommand("end");
		pane.add(startB);
		pane.add(endB);
		getContentPane().add(pane);		
	}

	public static void main(String[] args) {
		frame = new TimeGet();
		frame.setVisible(true);
	}
}

このコードを実行すると、下記のようにStartボタンを押してからEndボタンを押すまでの時間を表示してくれる。

  SartTime = 1484701481739
  EndTime = 1484701685181
  interval = 203
  Time = 3 min 23 sec.


日時の取得は、java.util.Dateクラスを下記の様に用いることで、

  Date date1 = new Date();
  System.out.println("Date = " + date1);
  Date = Wed Jan 18 06:34:47 JST 2017

のように、このコードが実行された日時を取得できるが、この方法で処理時間を計算するのは面倒なため、
ここでは、“System.currentTimeMillis()”を使用した。
この“System.currentTimeMillis()”の戻り値は、ミリ秒で測定した現在時刻と協定世界時UTC 1970 年 1 月 1 日深夜零時との差である。そのため、下記のコードで

  (endMs-startMs)/60000 //分の表記
  ((endMs-startMs)%60000)/1000 //秒の表記

分秒単位で表示するようにした。

Rを使った、データの読み込み、フィッティング、データの書き出し

Rでの解析方法についての覚書。

まずは、Rを使ったデータの読み込み方法。
(1) テキストファイルからのデータの読み込み

   > data = read.table("C:\\------.txt"(ファイルの指定), header = F)

ここでの"data"は読み込んだデータの入れ物。

   header = F

これは、第1行に変数名がないことを指定している。(もし、変数名がある場合は”T”にする)
このコードでは、"C:\\------.txt"のように開くファイルをタイプする必要がある。(打ち間違えのリスクもあり面倒)
そのため、

  > data = read.table(file.choose(), header = F)

のようにfile.choose()を使用すると、「ファイルを開く」ダイアログが表示されファイルを選択できるようになり便利。

  > data = read.table(file.choose(), header = F)


(2) Excelファイルからのデータの読み込み
 (a) Excelファイルを指定して、データを読み込む
まず下準備として、Rの“パッケージ”から“パッケージのインストール”をクリック。Packagesの中から“xlsx”を選択。

 > library (xlsx)
  > data2 = read.xlsx(file.choose(), 1, stringsAsFactors = F, header = F)

Excelファイルを開くには、

 > library (xlsx)

で、“xlsx”を呼び込む必要がある。(Rの起動時毎に)
途中にある“1”はシート番号、第1行に変数名がない場合は“stringsAsFactors = F, header = F”にしておく。

 (b) Excelファイル上の特定のデータを読み込む
まず下準備として、Excelファイル上の解析したいデータをコピーしておく。

 > data3 = read.table("clipboard", header = F)

このようにして、Excelファイル上の特定のデータを読み込む場合は、“library (xlsx)”の必要はない。



読み込んだデータは、

 > data

で、確認できる。

ここでは、次のようなデータを読み込んだ。

  V1 V2
1 12  0
2 10  1
3  8  2
4 11  3
5  6  4
6  7  5
7  2  6
8  3  7
9  3  8


次に、読み込んだデータをグラフにする

 > x = data[[1]]
 > y = data[[2]]
 > attach (data)
 > plot (x, y, pch = 16)

このコードで、下記のようなグラフが書ける。
f:id:Aki-Miya:20170105113345p:plain

 > x = data[[1]]
 > y = data[[2]]

では、取り込んだデータの1列目を“x”、2列目を“y”としている。

 > plot (x, y, pch = 16)

この部分で、x-yのグラフを描かせ、表示を黒丸(pch = 16)にしている。




読み込んだデータの線形回帰

 > fm <- lm (y ~ x)
 > abline(fm)

このコードにより下記のように回帰直線を求めて引くことが出来る。
f:id:Aki-Miya:20170105114221p:plain

 lm (y ~ x)

この部分で、どの変数が応答変数で(ここではy)、どの変数が説明変数(ここではx)なのかを、Rに教える。
線形回帰の場合は“lm”を用いて、非線形回帰の場合は“nls”を使用する。


線形回帰の結果は

 > summary (fm))

で呼び出すことができ、ここでは下記の様になった。

Call:
lm(formula = y ~ x)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.2775 -0.9143 -0.5735  1.0745  1.7561 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   8.6184     0.9296   9.271 3.52e-05 ***
x            -0.6704     0.1205  -5.565 0.000846 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.257 on 7 degrees of freedom
Multiple R-squared:  0.8157,    Adjusted R-squared:  0.7893 
F-statistic: 30.97 on 1 and 7 DF,  p-value: 0.0008461


最後に、解析結果をエクセル等に書き出す

 > names(fm)

で、解析結果の中身を調べることが出来、結果が下記。

 [1] "coefficients"  "residuals"     "effects"       "rank"         
 [5] "fitted.values" "assign"        "qr"            "df.residual"  
 [9] "xlevels"       "call"          "terms"         "model" 

この中で、[1]"coefficients"が回帰直線の傾きと切片を示し、

 > fm$coefficients

上記のコードで、下の様に、その値のみを呼び出すことが出来る。

 (Intercept)           x 
  8.6183673  -0.6704082 

解析結果は、

 > write.xlsx(fm$coefficients, file.choose(), col.names = T, row.names = T)

とすることで、excelファイルとして保存できる。ここでは、

  file.choose()

を使用しているため、任意の名前で保存できる。(但し、拡張子(.xlsx)を付け忘れないように)

 col.names = T, row.names = T

この部分は、行と列の名前を出力するかどうかを指定する箇所で、出力しない場合は“F”にする。



最後に、コードの全体を書く。

> library (xlsx)
> data = read.xlsx(file.choose(), 1, stringsAsFactors = F, header = F)
> attach (data)
> x = data[[1]]
> y = data [[2]]
> plot (x, y, pch = 16)
> fm <- lm(y ~ x)
> abline(fm)
> write.xlsx(fm$coefficients, file.choose(), col.names = T, row.names = T)


Javaで書くよりもかなりスッキリしている。


(注:今回使ったデータは、「統計学:Rを用いた入門書」(共立出版)から拝借しました。)

JavaでnewAudioClipを使ってサウンドを再生する。

かなり久しぶりの投稿。なので、単純なコードを書いてみた。

何かしらのタスクの終了時に音が出るようにしたいので、とりあえずボタンを押すと音が出るコードを書いてみた。

import java.applet.AudioClip;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SoundTest extends JFrame implements ActionListener {

	AudioClip ac = null;


    //ボタンのアクッションの設定
	public void actionPerformed (ActionEvent e) {
		String cmd = e.getActionCommand ();
		if (cmd.equals("push")) {
			ac.play(); //Soundをならす
		}
 	}

	SoundTest () {
		ac = java.applet.Applet.newAudioClip(SoundTest.class.getResource("Kane.wav"));  //音を取り込む
		JButton button = new JButton ("Push");
		button.addActionListener(this);
		button.setActionCommand("push");
		button.setBounds(40, 40, 80, 40);
		JPanel pane = new JPanel ();
		pane.setLayout(null);
		pane.add(button);
		getContentPane().add(pane, BorderLayout.CENTER);
	}

	public static void main(String[] args) {
		SoundTest frame = new SoundTest();
		frame.setTitle ("Sound");
		frame.setBounds(10, 10, 180, 170);
		frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		frame.setVisible (true);
	}
}

サウンドを再生するコードは下記の部分

   AudioClip ac = null;
   ac = java.applet.Applet.newAudioClip(SoundTest.class.getResource("Kane.wav"));  //音を取り込む

   ac.play();

再生するサウンド(ここでは"Kane.wav")をソースコードと同じディレクトリに入れればOK。

   ac.play();

は一度だけの再生だが、この部分を

   ac.loop();

にすれば、繰り返し再生になる。

newAudioClipでは、midiやwav等のファイルが再生可能らしい。


今回は、サウンドとして“鐘の音”を使ったので、なかなか趣のある感じになった。

JSliderを使って、画像の輝度を変える。

ここでは、JSliderを使って画像の輝度値を変えてみた。
まずは、ソースを記す。

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputAdapter;

public class SlideInt extends JFrame implements ChangeListener {

	JFrame showFrame;
	JFrame changeFrame;
	JSlider slide;
	JLabel labe;
	JLabel value;
	BufferedImage img;
	BufferedImage img1;
	MyPanel mypane;
	MyPanel1 mypane1;
	int h;
	int w;
	int x0;
	int y0;

	//画像を開く
	public void OpenImage () {
		try {
			img = ImageIO.read(new File("C:\\Users\\aki-miya\\Desktop\\GFP-KDEL.png"));
			img1 = ImageIO.read(new File("C:\\Users\\aki-miya\\Desktop\\GFP-KDEL.png"));
			h = img.getHeight(); //画像の高さを取得
			w = img.getWidth(); //画像の幅を取得

			showFrame = new JFrame("Raw Image");
			changeFrame = new JFrame ("Change Intensity");
			showFrame.setSize (w, h);
			changeFrame.setSize (w, h);
			showFrame.setBounds (300, 100, w, h);
			changeFrame.setBounds (600, 100, w, h);
			showFrame.setVisible(true);
			changeFrame.setVisible(true);
			mypane = new MyPanel (w, h);
			mypane1 = new MyPanel1(w, h);
			mypane1.addMouseListener(new MouseCheck());
			mypane1.addMouseMotionListener(new MouseCheck());
			showFrame.getContentPane().add(mypane, BorderLayout.CENTER);
			changeFrame.getContentPane().add(mypane1, BorderLayout.CENTER);

		} catch (IOException ex) {
			System.out.println("Miss");
		}
	}

	//確認用にマウスを置いたポイントの輝度値を取得し、表示
	class MouseCheck extends MouseInputAdapter {
		public void mouseMoved (MouseEvent me) {
			x0 = me.getX();
			y0 = me.getY();
			value.setText(String.valueOf(img1.getRaster().getDataBuffer().getElem(y0*w + x0)));
		}
	}

	//画像を描画するツール
	public class MyPanel extends JPanel {
		public MyPanel (int w, int h) {
			setSize(w,h);
		}

		public void paintComponent (Graphics g) {
			g.drawImage(img, 0, 0, w, h, this);
		}
	}

	//画像を描画するツール
	public class MyPanel1 extends JPanel {
		public MyPanel1 (int w, int h) {
			setSize(w,h);
		}

		public void paintComponent (Graphics g) {
			g.drawImage(img1, 0, 0, w, h, this);
		}
	}


//スライダーのノブを動かした時のイベント
	public void stateChanged (ChangeEvent e) {

		labe.setText("Val = " + slide.getValue());

		//輝度値を変える
		for (int i = 0; i < w*h; i++) {
			if (img.getRaster().getDataBuffer().getElem(i) < slide.getValue()) {
				img1.getRaster().getDataBuffer().setElem(i, slide.getValue());
			} else {
				img1.getRaster().getDataBuffer().setElem(i, img.getRaster().getDataBuffer().getElem(i));
			}
		}
	mypane1.repaint();
	}

	SlideInt () {
		slide = new JSlider (0, 64000); //開いた画像が16bitなので、この値に設定
		labe = new JLabel ("val slide = 0");
		value = new JLabel ("val = null");
		slide.addChangeListener (this);  //Slideを可変にする
		JPanel pane = new JPanel ();
		pane.setLayout(null);
		slide.setBounds(10, 10, 100, 30);
		labe.setBounds(30, 50, 200, 30);
		value.setBounds(30, 80, 100, 30);
		pane.add(slide);
		pane.add(labe);
		pane.add(value);
		getContentPane().add(pane);
		OpenImage();
	}

	public static void main(String[] args) {
		SlideInt frame = new SlideInt ();
		frame.setTitle ("Test");
		frame.setBounds(100, 100, 180, 200);
		frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}


このコードでは、下記の部分で

//スライダーのノブを動かした時のイベント
	public void stateChanged (ChangeEvent e) {

		labe.setText("Val = " + slide.getValue());

		//輝度値を変える
		for (int i = 0; i < w*h; i++) {
			if (img.getRaster().getDataBuffer().getElem(i) < slide.getValue()) {
				img1.getRaster().getDataBuffer().setElem(i, slide.getValue());
			} else {
				img1.getRaster().getDataBuffer().setElem(i, img.getRaster().getDataBuffer().getElem(i));
			}
		}
	mypane1.repaint();
	}

JSliderの値よりも画像の輝度が小さい部分の輝度を、JSliderの値に変換している。
また、輝度値を変える用の画像"img1"と、参照用の画像"img"を用意することで画像を元に戻せるようにしている。


ここで開いた画像は16bitのため、下記の部分で

slide = new JSlider (0, 64000); //開いた画像が16bitなので、この値に設定

JSliderの範囲を“0~64000”に設定している。

また、輝度値の確認のために、

	//確認用にマウスを置いたポイントの輝度値を取得し、表示
	class MouseCheck extends MouseInputAdapter {
		public void mouseMoved (MouseEvent me) {
			x0 = me.getX();
			y0 = me.getY();
			value.setText(String.valueOf(img1.getRaster().getDataBuffer().getElem(y0*w + x0)));
		}
	}

も盛り込んだ。

JSliderとイベントを連動させるためには、
(1) ChangeListenerのimplements
(2) public void stateChanged (ChangeEvent e) {}の作成
(3) slide.addChangeListener (this); の設定
の3点が必要となる。

次回は、このコードを改良してもう少し使えそうなコードを書く予定。

少し余談:Javaで英語用のディクテーション用紙を作成する。

英語のリスニングの勉強においてディクテーションは非常に有効だと思うのだが、なかなか良い教材がないと思う。
無料 英語・英会話 無料 リスニングプラザ(ディクテーション勉強法)ヒアリング/listening/hearingのようなサイトはかなり有用であるが、リスニング教材数が少なく感じられるし、また、英語リスニング無料学習館は教材数は多いものの、各センテンスが短い。
長文を聴くとしても、やはりリスニングプラザのような単語を括弧で表記してくれた方が何かとやり易く感じる。


上記のような「リスニングプラザのような形式と分量で、多くのディクテーションをこなしたい」という個人的な需要から、自分でディクテーション用紙を作ることにした。

まずは、コードを記す。

import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

public class DictKun extends JFrame implements ActionListener {

	String tx;

	public void Open () {
		JFileChooser fc = new JFileChooser();
		fc.setAcceptAllFileFilterUsed(false);
		FileNameExtensionFilter filter = new FileNameExtensionFilter("Wordファイル", "docx");
		fc.addChoosableFileFilter(filter);
		int selected = fc.showOpenDialog(this);
		if (selected == JFileChooser.APPROVE_OPTION) {
			File file = fc.getSelectedFile();

			try {
				FileInputStream infile = new FileInputStream(file);
				XWPFDocument doc = new XWPFDocument (infile);
				XWPFWordExtractor ex = new XWPFWordExtractor(doc);
				XWPFDocument exDoc = new XWPFDocument ();
				XWPFParagraph para = exDoc.createParagraph();

				XWPFRun run = para.createRun();
				tx = ex.getText();

				//文字の置換
				tx = tx.toUpperCase();
				tx = tx.replace (" ", " )  ( ");
				tx = tx.replaceAll ("[A-Z]", "  ");
				tx = tx.replaceAll(", \\)" ,  " ),"); //コンマを括弧の外に出す。
				tx = tx.replaceAll("\\?", " ) ?");
				tx = tx.replace(".", " )."); //ピリオドを括弧の外に出す。
				tx = tx.replace(". )" , ".");  //ピリオドが最後ではない場合の置き換え

				//改行部分で番号を付けて分ける
				String [] txs = tx.split("\n");
				StringBuilder sb = new StringBuilder();
				for ( int i = 0; i < txs.length; i++) {
					sb = new StringBuilder();
					sb.append((i + 1) + " : (" + txs[i]  );
					run.setText(new String(sb));
					run.addCarriageReturn();
				}

				FileOutputStream fo = new FileOutputStream(this.writeFile());
				exDoc.write(fo);

			} catch (IOException e) {
				System.out.println("Open Miss");
			}
		}
	}

	//保存用の名前を付ける
	String writeFile() {
		FileDialog fd = new FileDialog(new Frame(), "保存 (末尾に.docxを付けてください)", FileDialog.SAVE);
		fd.setVisible(true);
		String path = fd.getDirectory() + fd.getFile();
		fd.dispose();
		return path;
	}

	public void actionPerformed (ActionEvent e) {
		String cmd = e.getActionCommand();

		if (cmd.equals("open")) {
			Open();
		}
	}

	DictKun () {
		JButton button = new JButton ("Open & Create");
		button.addActionListener(this);
		button.setActionCommand("open");
		button.setBounds(30, 15, 120, 30);
		JPanel pane = new JPanel ();
		pane.setLayout(null);
		pane.add(button);
		getContentPane().add(pane);
	}

	public static void main(String[] args) {
		DictKun frame = new DictKun();
		frame.setTitle("DictKun");
		frame.setBounds (100, 100, 200, 100);
		frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}

例として、下記のコナンドイルの「赤毛連盟」の冒頭 (Wordファイル)を、
f:id:Aki-Miya:20150520204027p:plain

本コードで、ディクテーション用紙に変換した結果が次である。
f:id:Aki-Miya:20150520204202p:plain

このコードでは、改行ごとに番号を振り段落を分けることで、ディクテーションし易くした。

会話部分の「“」がカギ括弧内に入っているため若干見栄えが悪いが、リスニングプラザのように、カギ括弧の大きさが単語の文字数を反映しており、使用する上では問題無いと思う。

本コードによって、洋書の音読サイトやリスニングCDをディクテーションの教材にすることができる。(ただし、原文のWordファイルを準備する必要があるが。)


英語の原文をディクテーション用紙にするために、下記の部分で

//文字の置換
    tx = tx.toUpperCase();
    tx = tx.replace (" ", " )  ( ");
    tx = tx.replaceAll ("[A-Z]", "  ");
    tx = tx.replaceAll(", \\)" ,  " ),"); //コンマを括弧の外に出す。
    tx = tx.replaceAll("\\?", " ) ?");
    tx = tx.replace(".", " )."); //ピリオドを括弧の外に出す。
    tx = tx.replace(". )" , ".");  //ピリオドが最後ではない場合の置き換え

アルファベットを空欄にし、その前後に括弧を書くようにした。

JavaでWordを読み書きする。

以前、Javaでエクセルを編集するコードを書いたが、今回はWordを読み書きしてみる。
JavaでWordを取り扱うには、エクセルの時と同様に“Apache POI”をインストールする必要がある。(ダウンロードは
Apache POI - the Java API for Microsoft Documentsからできる)

まずは、既存のWordファイルを開き、文章を取得し、新しいWordファイルにコピーするコードを書いた。

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

public class WordInOut {

	public static void main  (String[] args) throws Exception {
		XWPFDocument doc = new XWPFDocument (
				new FileInputStream("C:\\Users\\aki-miya\\Desktop\\Test file.docx"));
		XWPFWordExtractor ex = new XWPFWordExtractor(doc);
		XWPFDocument exDoc = new XWPFDocument ();
		XWPFParagraph para = exDoc.createParagraph();

		XWPFRun run = para.createRun();

		String tx = ex.getText();
		run.setText(tx);
		System.out.println(tx);
		exDoc.write(new FileOutputStream("C:\\Users\\aki-miya\\Desktop\\Test file-copy.docx"));
	}
}

ただし、このコードでは下記のような文章のWordファイルを読み込むと

Test file
Hellow world
おはよう

次のように、改行が反映されない形で新しいWordファイルにコピーされてしまった。

Test file Hellow world おはよう

そこで、次に“改行が反映された形で新しいWordファイルにコピーする”方法を下記に書く。

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

public class WordSplit {

	static StringBuilder sb;

	public static void main  (String[] args) throws Exception {
		XWPFDocument doc = new XWPFDocument (
				new FileInputStream("C:\\Users\\aki-miya\\Desktop\\Test file.docx"));
		XWPFWordExtractor ex = new XWPFWordExtractor(doc);
		XWPFDocument exDoc = new XWPFDocument ();
		XWPFParagraph para = exDoc.createParagraph();

		XWPFRun run = para.createRun();

		String tx = ex.getText();

		String [] txs = tx.split("\n");
		StringBuilder sb = new StringBuilder();
		for ( int i = 0; i < txs.length; i++) {
			sb = new StringBuilder();
			sb.append((i + 1) + " : " + txs[i]);
			run.setText(new String(sb));
			run.addCarriageReturn();
		}

		exDoc.write(new FileOutputStream("C:\\Users\\aki-miya\\Desktop\\Test file-copy2.docx"));
	}
}

このコードでは、上述の下記の文章が

Test file
Hellow world
おはよう

下記のように、改行されるたびに("\n"があるたびに)、番号が振られ改行できるようになった。

1 : Test file
2 : Hellow world
3 : おはよう 

今回は、

for ( int i = 0; i < txs.length; i++) {
    sb = new StringBuilder();

の部分で、各行ごとに新たな"StringBuilder();"を作ることで改行できるようにしたが、もっとキレイな方法がありそう。