From window, to wind

趣味のゲームとJavaプログラムなどについて 適当に書き綴るブログ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

メッセージを表示するクラス

ゲームなどでメッセージが1文字ずつ流れるように表示しているので、参考までに作製してみました。
実行画面
MessageSample.png

ソースコード
メインクラス

 


 

package program;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class MainRun {

    static JButton jb1, jb2;
    static MessageBox mb;
    static JTextArea jta;
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (ClassNotFoundException e2) {
            // TODO 自動生成された catch ブロック
            e2.printStackTrace();
        } catch (InstantiationException e2) {
            // TODO 自動生成された catch ブロック
            e2.printStackTrace();
        } catch (IllegalAccessException e2) {
            // TODO 自動生成された catch ブロック
            e2.printStackTrace();
        } catch (UnsupportedLookAndFeelException e2) {
            // TODO 自動生成された catch ブロック
            e2.printStackTrace();
        }
       
        Dimension sizeb = new Dimension(120,50);
       
        JFrame jf = new JFrame("MessageBox");
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        jta = new JTextArea(3, 50);
        jta.setLineWrap(true);

        JScrollPane jsp1 = new JScrollPane(jta);
       
        jb1 = new JButton("View(Erase)");
        jb1.setPreferredSize(sizeb);
        jb1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                jb1.setEnabled(false);
                jb2.setEnabled(false);
                mb.view(jta.getText(), true);
                jb1.setEnabled(true);
                jb2.setEnabled(true);
            }
        });
       
        jb2 = new JButton("View(no Erase)");
        jb2.setPreferredSize(sizeb);
        jb2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                jb1.setEnabled(false);
                jb2.setEnabled(false);
                mb.view(jta.getText(), false);
                jb1.setEnabled(true);
                jb2.setEnabled(true);
            }
        });
       
        mb = new MessageBox(3,50);
        mb.setBackground(Color.black);
        mb.setForeground(Color.white);
        JScrollPane jsp2 = new JScrollPane(mb);
       
        GBLayout.addGB(jb1, jf.getContentPane(), 0, 0, 1, 1);
        GBLayout.addGB(jb2, jf.getContentPane(), 0, 1, 1, 1);
        GBLayout.addGB(jsp1, jf.getContentPane(), 1, 0, 1, 1);
        GBLayout.addGB(jsp2, jf.getContentPane(), 1, 1, 1, 1);
       
        jf.pack();
        jf.setLocation(300, 300);
        jf.setVisible(true);
    }
}




メッセージを表示させるクラス

 


 

package program;

import javax.swing.JTextArea;

public class MessageBox extends JTextArea implements Runnable{

    private int speed = 100;
    private String viewstr ="";
    private String nowstr ="";
    Thread t;
   
    MessageBox(int rows, int columns){
        super(rows,columns);
        this.setLineWrap(true);
        this.setFocusable(false);
       
    }
   
    public void setSpeed(int sp){
        speed = sp;
    }
   
    public void erase(){
        setText("");
        viewstr="";
    }
   
    public void view(String str, Boolean er){
        if(er)erase();
        nowstr+=str+"\n";
        t = new Thread(this);
        t.start();
    }

    synchronized public void run() {
        while(!nowstr.equals("")){
            //表示に一文字足して、表示待ちを一文字減らす
            viewstr=viewstr+nowstr.substring(0,1);
            setText(viewstr);
            nowstr=nowstr.substring(1);
           
            //スクロールするようにする処理
            //JTextAreaのキャレットの位置を与えることでJScrollPaneの表示も変更される
            setCaretPosition(getText().length());
            try {
                Thread.sleep((long)speed);
            } catch (InterruptedException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
        } 
        
    }
   
}


解説



スレッドで文字を一文字ずつ表示させるようにしています。
このときスクロールが表示している文字に対応するようにキャレットの位置を変更しています。
setCaretPosition(getText().length());おそらくはこのメソッドを呼び出すことでスクロールペインの表示位置も変更しているのだと思われます。
コンストラクターにおいてメッセージを表示するのですから左右で折り返し、外から文字を入力させないようにフォーカスを外します。
this.setLineWrap(true);
this.setFocusable(false);
不完全な点としてはviewメソッドを呼び出すときに処理待ちができていない点です。だからボタンのイベントのところでsetEnabledを呼び出しているが効果がない状態です。スレッド処理が終わるまで待機することはできたのですが、その間メッセージボックスの再描画ができずスレッドが終了すると同時に表示されるようになってしまいました。何とか描画も呼び出せればよいのですが。できればメッセージボックス単独で記述できるようにしたい。


追加
メッセージを受け取るときに行末に改行文字を入れるように変更、run()をsynchronizedにした。これでview(no Erase)なら連続してボタンを押しても次の文章につながる。ただへんな処理だな。こういうときの正しい処理を探さないと。
スポンサーサイト

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバックURLはこちら
http://kagenyan.blog69.fc2.com/tb.php/26-4ea28e92
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。