ルービックキューブ
以前作ったルービックキューブのシミュレーションプログラムを Java Web Start で起動できるようにしてみました。ただし、セキュリティ証明書は 証明書発行期間から取得したわけではない、いわゆるオレオレ証明書。 しかも6ヶ月で期限切れになる。対策はそのうち考えます。
画面下のボタンを押すか、色名のキーを押すと、 その色が中心にある面をその面の上から見て 時計回りに90度回転します。以前作ったルービックキューブのシミュレーションプログラムを Java Web Start で起動できるようにしてみました。ただし、セキュリティ証明書は 証明書発行期間から取得したわけではない、いわゆるオレオレ証明書。 しかも6ヶ月で期限切れになる。対策はそのうち考えます。
画面下のボタンを押すか、色名のキーを押すと、 その色が中心にある面をその面の上から見て 時計回りに90度回転します。Canvas の内容をそのまま保存することはできない。 BufferedImage に書き込んで、Canvas には drawImage() で書き込むことにしておく。 その状態で、image を BufferedImage のインスタンスとして、
FileOutputStream output = new FileOutputStream("test.jpg");
JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(output);
jpeg.encode(image);
output.flush();
output.close();
とすればよい。ただし、IOException を throw するので例外処理が必要。
サンプルソース
参照。
Canvas に図形を描画するときに、直接 Graphics に書き込むのではなく、 バッファーとして Image オブジェクトを作成し、その Graphics に書き込んでから drawImage メソッドで Canvas の Graphics に書き込む。
具体的には、Canvas のフィールド変数として、
Image image; // イメージの保存
Graphics g0; // image に描画するための Graohics
を追加し、paint() メソッドは
public void paint(Graphics g){
// image が初期化されていたいときは初期化する
if(image == null){
image = createImage(getSize().width,
getSize().height);
// Graphics の取得
g0 = image.getGraphics();
}
// image を表示する
g.drawImage(image,0,0,this);
}
とし、実際の描画は
g0.fillRect(20,20,50,50);
getGraphics().drawImage(image,0,0,this);
のように g0 に書き込んでから drawImage で Canvas に書き込めばよい。
アプレットを作るときに、わざわざhtmlファイルを書いてブラウザで 動作を確認するのは面倒である。(appletviewer をつけばちょっと楽だが) そんなときはアプレットとして作ったプログラムをアプリケーションとして実行 させよう。
次のアプレットはボタンを押せばメッセージが出ると言う定番のアプレットだが、 これをアプリケーションとして動くようにするために、main メソッドを付け足 している。そこでは、Frame を生成し、Applet を張り付けているだけである。
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class HelloAppletcation extends Applet{
Button bt;
TextField tf;
public static void main(String args[]){
Frame fr = new Frame("Hello Applet");
fr.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
Applet app = new HelloAppletcation();
app.init();
fr.add(app);
fr.setSize(400,100);
fr.setVisible(true);
app.start();
}
public void init(){
bt = new Button("PUSH");
tf = new TextField(30);
add(bt);
add(tf);
bt.addActionListener(new HelloButton());
}
class HelloButton implements ActionListener{
public void actionPerformed(ActionEvent e){
tf.setText("Hello, Java World!!");
}
}
}
動的に Applet として実行しているか Application として実行しているかを
判定したい場合は、Applet クラスの getCodeBase() メソッドを呼ぶとよい。
Application の場合は例外が発生する。
実行時にクラスを呼ぶ例を挙げよう。 まず A(String str,double x) と言うコンストラクタを持つようなクラス A を考えよう。このクラス A を動的に呼んでインスタンス化するには次のようにする。 ここで、ClassLoader クラスは抽象クラスなので、それを継承したクラスを ClassLoadTest とする。
ClassLoader loader = new ClassLoadTest();
Class c = loader.loadClass("A");
Constructor con = c.getDeclaredConstructor(
new Class[]{String.class,double.class});
A a = (A)con.newInstance(new Object[]{"circle",new Double(3.14)});
例外処理に付いては省略した。
外のクラス名.this でアクセスできる。
class InnerOuter{
String str = "Outer";
A a;
InnerOuter(){
a = new A();
}
class A{
String str = "Inner";
void outerMessage(){
System.out.println(InnerOuter.this.str);
}
void innerMessage(){
System.out.println(this.str);
}
}
public static void main(String args[]){
InnerOuter inn = new InnerOuter();
inn.a.outerMessage();
inn.a.innerMessage();
}
}
これをコンパイルして実行すると、
のように出力される。$ java InnerOuter Outer Inner
この手の実行時型判定は instanceof または Class クラスの isInstance() メソッドまたは Class クラスの isAssignableFrom() メソッドを使う。 次の3つは全て同じ意味で、オブジェクト a がクラス A またはそのサブクラスの インスタンスのときに true を返す。
RMI の例として、クライアント側の名前を登録、解除、および 現在登録されている名前全てを得る RMI サーバを作成。 チャットなどに応用できるだろう。
とした後に、$ javac MyRemote.java $ javac MyServer.java $ javac MyClient.java $ rmi MyServer
と実行し、 同じホスト上で、$ java MyServer
とすると、$ java MyClient
のように表示されるはず。server> John Lennon ------------------------- server> John Lennon server> Paul McCartney server> George Harrison server> Ringo Starr ------------------------- server> Paul McCartney server> Ringo Starr -------------------------
Thread の制御には wait() と notify() が用意されているが、 多くのサンプルでは Thread を起動するたびにインスタンス化して、不要になったら null を代入することで実現している。それでできてしまうのだから問題ないと言う 考え方もあるだろうが、ここでは wait() notify() を使う方法を考えてみよう。
同じスレッドの wait() と notify() を実行することと、実行するときに syncronized(スレッドのオブジェクト)で同期させる。 以下にアプレットでスレッドを使うときの例を挙げる。
/*
<applet code="AppletOnOff" width="100" height="100">
</applet>
*/
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class AppletOnOff extends Applet{
TextField tf;
long n = 0;
SuspendableThread th;
Button btn;
public void init(){
add(btn = new Button("START"));
add(tf = new TextField(Long.toString(n),10));
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt){
if(btn.getLabel().equals("START")){
th.restartThread();
btn.setLabel("STOP");
}else{
th.suspendThread();
btn.setLabel("START");
}
}
});
th = new SuspendableThread();
th.start();
}
class SuspendableThread extends Thread{
boolean flag = false;
public void suspendThread(){
flag = false;
}
public void restartThread(){
flag = true;
synchronized(this){
notify();
}
}
public void run(){
while(true){
try{
th.sleep(100);
if(!flag){
synchronized(this){
wait();
}
}
}catch(InterruptedException e){
}
n++;
tf.setText(Long.toString(n));
}
}
}
}