スレッドを使うと次の NewHeat1Dv3.java (実行は http://nalab.mind.meiji.ac.jp/~mk/labo/java/sample/NewHeat1Dv3.html) のようになる。
1 /*
2 * NewHeat1Dv3.java
3 * version 2.0: 計算スレッドを用意した。
4 * version 3.0: ボタン、テキスト・フィールドなどを用意して再計算可能にした。
5 * version 4.0: (予定) 陰解法、境界条件の一般化
6 * version 5.0: (予定) 初期条件の種類を増やす
7 */
8
9 import java.awt.Button;
10 import java.awt.Color;
11 import java.awt.Frame;
12 import java.awt.Graphics;
13 import java.awt.Image;
14 import java.awt.Label;
15 import java.awt.TextField;
16 import java.awt.event.ActionEvent;
17 import java.awt.event.ActionListener;
18 import java.awt.event.WindowAdapter;
19 import java.awt.event.WindowEvent;
20
21 public class NewHeat1Dv3 extends Frame implements Runnable,ActionListener {
22 /**
23 *
24 */
25 private static final long serialVersionUID = 1L;
26 /**
27 *
28 */
29 static final int ImgX = 500, ImgY = 500;
30 static final int WinX = ImgX + 200, WinY = ImgY;
31 Thread th = null;
32 Image im = null;
33 Graphics bg = null;
34 int i, n = -1, nMax;
35 int N;
36 double lambda, Tmax, dt, theta;
37 double h, tau;
38 int skip;
39 double [] x, u, newu;
40 double ratiox, ratioy, X0, Y0;
41 private String[] labelStr={"N", "lamba", "Tmax", "dt", "theta"};
42 private Label[] label;
43 private String[] txStr={"100", "0.5", "1.0", "0.01", "0.5"};
44 private TextField[] tf;
45 private String[] btStr = {"Start", "End"};
46 private Button[] bt;
47 private void readParameters() {
48 N = Integer.parseInt(tf[0].getText());
49 lambda = Double.valueOf(tf[1].getText()).doubleValue();
50 Tmax = Double.valueOf(tf[2].getText()).doubleValue();
51 dt = Double.valueOf(tf[3].getText()).doubleValue();
52 theta = Double.valueOf(tf[4].getText()).doubleValue();
53 }
54 public NewHeat1Dv3() {
55 this.setSize(WinX, WinY);
56 this.addWindowListener(new WindowAdapter() {
57 public void windowClosing(WindowEvent ev) {
58 System.exit(0);
59 }
60 });
61 setLayout(null);
62 bt = new Button[btStr.length];
63 for (int i = 0; i < bt.length; i++) {
64 bt[i] = new Button(btStr[i]);
65 bt[i].addActionListener(this);
66 bt[i].setBounds(ImgX, (i+2)*20, (WinX - ImgX)/2, 20);
67 add(bt[i]);
68 }
69 label = new Label[labelStr.length];
70 tf = new TextField[txStr.length];
71 for (int i = 0; i < labelStr.length; i++) {
72 label[i] = new Label(labelStr[i]);
73 tf[i] = new TextField(txStr[i]);
74 label[i].setBounds(ImgX, (i+bt.length+2)*20, (WinX - ImgX) / 3, 20);
75 tf[i].setBounds(ImgX + (WinX-ImgX)/3, (i+bt.length+2)*20, (WinX-ImgX)/2, 20);
76 add(label[i]);
77 add(tf[i]);
78 }
79 this.setVisible(true);
80 bt[0].setEnabled(false);
81 space(-0.1, -0.1, 1.1, 1.1);
82 // 計算開始の準備
83 initcomputation();
84 // 計算スレッドを開始する
85 this.start();
86 }
87 public void start() {
88 if (th == null) {
89 th = new Thread(this);
90 th.start();
91 }
92 }
93 public void stop() {
94 if (th != null) {
95 th = null;
96 }
97 }
98 public static void main(String[] args) {
99 new NewHeat1Dv3();
100 }
101 // 座標変換の仕組み
102 private void space(double x0, double y0, double x1, double y1) {
103 X0 = x0; Y0 = y0;
104 ratiox = ImgX / (x1 - x0);
105 ratioy = ImgY / (y1 - y0);
106 }
107 // x座標をユーザー座標からウィンドウ座標に
108 private int wx(double x) {
109 return (int)Math.rint(ratiox * (x - X0));
110 }
111 // y座標をユーザー座標からウィンドウ座標に
112 private int wy(double y) {
113 return ImgY - (int)Math.rint(ratioy * (y - Y0));
114 }
115 // 初期データ
116 private double f(double x) {
117 if (x <= 0.5)
118 return x;
119 else
120 return 1.0 - x;
121 }
122 // 現在の u[] をグラフ化する
123 private void drawGraph() {
124 if (bg == null)
125 repaint();
126 for (int i = 0; i < N; i++)
127 bg.drawLine(wx(x[i]), wy(u[i]), wx(x[i+1]), wy(u[i+1]));
128 }
129 // ダブルバッファリングの定跡
130 public void paint(Graphics g) {
131 if (im == null) {
132 // createImage() はコンストラクターでは使えず、このタイミングでするしかないとか。
133 im = this.createImage(this.getWidth(), this.getHeight());
134 bg = im.getGraphics();
135 }
136 g.drawImage(im, 0, 0, this);
137 }
138 private void initcomputation() {
139 // パラメーターを読む
140 readParameters();
141 // 刻み幅を決める
142 h = 1.0 / N;
143 tau = lambda * h * h;
144 //
145 skip = (int)Math.rint(dt / tau);
146 if (skip <= 0) skip = 1;
147 nMax = (int)Math.ceil(Tmax / tau);
148 // ベクトルを3本用意する
149 x = new double [N+1];
150 u = new double [N+1];
151 newu = new double [N+1];
152 //
153 n = -1;
154 System.out.println("init");
155 }
156 // 計算スレッド
157 public void run() {
158 while (th != null) {
159 if (n == -1) {
160 // 初期値を計算する
161 for (int i = 0; i <= N; i++)
162 x[i] = i * h;
163 for (i = 0; i <= N; i++)
164 u[i] = f(i * h);
165 n++;
166 repaint();
167 bg.setColor(Color.white);
168 bg.fillRect(0, 0, ImgX, ImgY);
169 bg.setColor(Color.black);
170 drawGraph();
171 repaint();
172 try {
173 Thread.sleep(10);
174 } catch (Exception ex) {
175 ex.printStackTrace();
176 }
177 }
178 else if (n < nMax) {
179 do {
180 for (i = 1; i < N; i++)
181 newu[i] = (1 - 2 * lambda) * u[i] + lambda * (u[i + 1] + u[i - 1]);
182 for (i = 1; i < N; i++)
183 u[i] = newu[i];
184 u[0] = 0.0;
185 u[N] = 0.0;
186 n++;
187 } while (n % skip != 0);
188 drawGraph();
189 repaint();
190 try {
191 Thread.sleep(10);
192 } catch (Exception ex) {
193 ex.printStackTrace();
194 }
195 // System.out.println(""+ n * tau);
196 }
197 Thread.yield();
198 }
199 }
200 public void actionPerformed(ActionEvent e) {
201 // TODO 自動生成されたメソッド・スタブ
202 if (e.getSource() == bt[0]) {
203 bt[0].setEnabled(false);
204 bt[1].requestFocus();
205 bt[1].setEnabled(true);
206 initcomputation();
207 start();
208 }
209 if (e.getSource() == bt[1]) {
210 bt[0].setEnabled(true);
211 bt[0].requestFocus();
212 bt[1].setEnabled(false);
213 stop();
214 }
215 }
216 }