スレッドとイベントに関するJava初心者の質問

このQ&Aのポイント
  • Java初心者がSwingを使ってアプリケーションを作成している際に、ボタンが配置されたダイアログ上でスレッドを作成していると、別のウィンドウでダイアログを再表示するとボタンが押せなくなる現象が起きる。
  • スレッドとイベントが関係している可能性があり、初心者なので理解が不足している。
  • 具体的なプログラムが提示できないため、分かりづらいが、アドバイスを求めている。
回答を見る
  • ベストアンサー

イベントとスレッド

Java初心者です。 イベントとスレッドに関する質問です。 Swingを使ったアプリケーションを作成しているのですが、 以下のような現象が起きています。 1. ボタンが配置されているダイアログ(A)で、そのボタンを押下する。 2. ボタンを押下したときに実行されるメソッドで、スレッドを作成する。 3. その作成されたスレッドで、JOptionPane#showOptionDialogを実行して、ダイアログ(B)を表示する。 4.(B)が表示されている状態で、別のウィンドウで隠し、再度表示させると、(B)に配置されているボタンが押せなくなる。 4.で(B)のボタンを押せるようにしたいのですが、 うまくいきません。 スレッドとかイベントが関係していると思うのですが、 何しろ初心者なもので、よく理解していません。 実際のプログラムをお見せすることが出来ないので分かりずらいかもしれませんが、何かお気づきのことがあれば 教えて頂けないでしょうか? よろしくお願い致します。

  • ns18
  • お礼率53% (55/102)
  • Java
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.1

はい。お気付きのことがあります。 Swingでは、スレッドは使えません! Swingのコンポーネントは、スレッドセーフではない…。 つまり、他のスレッドからメソッドを呼び出しても大丈夫なようにはできてないのです。 (例外はrepaint()で、これは他から呼び出しても大丈夫です) この性質によっておかしくなっているかどうかはわからないので、自信なしとしますが、 とにかくスレッドセーフとはなっていません。 Swingコンポーネントを、正規に他のスレッドから操作しようとすると、 SwingUtilityクラスのimvokeLater(もしくはinvokeAndWait)メソッドに、 Runnableのオブジェクトを与える…などの手間が 必要になります。(詳しくは該当APIドキュメントを参照ください) できればスレッドを使う以外の方法を考えてみてください。

ns18
質問者

お礼

回答ありがとうございます。 (A)にはプログレスバーが配置されていて、ボタンが押されたときに作られるスレッドで、 SwingUtility#imvokeLaterを使って更新するようなことをしています。 (A)には、もうひとつキャンセルボタンもあって、途中で動作を止める、というようなこともしています。 このあたりが複雑で、初心者には難解です。。。 とにかくありがとうございました。

関連するQ&A

  • モーダルとスレッド

    JOptionPaneでダイアログを出力する直前に新しいスレッドを作っておき、 その中でバックグラウンド用処理を行いたいと思っています。 色々ためしたのですが、ダイアログの了解ボタンを押すまで新たに作った スレッド内のバックグラウンド処理もブロックされる様です。 (スレッドのプライオリティ等も変更してみました。) モーダル画面を起動するとその画面が終了するまで、そのプロセス内の 全てのスレッドがブロックされるという事なのでしょうか? (勿論、モーダル画面からの入力受付となるEventDispatchThreadは動いて いるのでしょうけど) もし、「そうである」ならば、JOptionPaneはあきらめて、モードレスダイアログ を作成しようと思いますし、「いや、こういう手段がある」というのなら それを教えてください。 以上、よろしくお願いします。

    • ベストアンサー
    • Java
  • SwingとEDT(イベントディスパッチスレッド)

    多くのサイトを見て、色々考えているのですが、イマイチ理解が及びません。以下のような風に思っていていいのでしょうか。 ・Swingではメインとなるmainスレッド(表現は正しくないかもしれない)と、描画関係のイベントを実行するイベントディスパッチスレッドで出来てる。 ・描画関係のイベント(正確にはコンポーネントの可視化及び可視化したコンポーネントの描画)はイベントディスパッチスレッド上で実行しなければならない。 ・SwingUtilities.invokeLaterを使うことによってその中身のプログラムをイベントディスパッチスレッドで実行してくれる...? →setVisible(true)やsetText("")など全てSwingUtilities.invokeLaterを使って記述しなければならない.....???(面倒すぎじゃないでしょうか) ・Swingでのマルチスレッドを行うにはSwingWorkerを使う(ことは見つけているのですが、まずEDTについて理解しないと先に進めないと思い、まだあまりこれの内容は調べていません) ・描画系の命令を実行しないのならば、別スレッドを作成して使用しても良い....? こんなところでしょうか。 しかし、このとおりだとすると今までの自分の書いてきたプログラムは間違いだらけ(特に「全ての描画系命令をSwingUtilities.invokeLaterを使いEDTで実行する」点)になってしまいます。 ちゃんとした理解をしておきたいので、わかりやすい説明でも、上記の間違っている点でもご教示願います。

  • VB.NET開発(イベントプロシージャはマルチスレッドですか?)

    VB.NET開発(イベントプロシージャはマルチスレッドですか?) 以前より.NETのWindowsフォームの業務アプリ開発してますが、基本的な質問をさせて下さい。 イベントプロシージャの実行処理は、本体スレッド(実行時のスレッド)とは別のスレッドで動作しているのでしょうか。 例えば、ボタンのクリックイベントに何かしらの重い処理があったとします。このクリックイベントの処理ではボタンの制御をしていないので、イベントプロシージャの実行中は、処理中のボタンが押下可能な前提とします。この時、このボタンを3回押下して実行させると3つのスレッドが新規に作成されて実行していると考えて宜しいのでしょうか。 デリゲートやイベントに関するキーワードで検索して、いくつか資料を見たのですが、上記の疑問にぴったり合う解答がなく、質問させて頂きました。 業務アプリの開発で、今まで、あまりマルチスレッドなど意識せずやってきましたが、実は意識しなくても、マルチスレッドの開発をしていたことになるのでしょうか。 以前、VB6の開発もしておりました。 ちなみにVB6の場合も、イベントプロシージャはマルチスレッドで実行されていると考えて宜しいのでしょうか。 よろしくお願いします

  • ダイアログを終了させてもハンドルが1つ増加したまま。。。

    VC++のMFCを使ってダイアログベースのEXEを造っています。 ハンドルのリークが発生し、困っています。 <動作内容> メインのダイアログで、ボタン押下により別のダイアログを表示します。 DoModal()でモーダルダイアログを作成します。 別のプロセスからブロードキャストされるメッセージを処理したいため、 ボタン押下のルーチンで DoModal() せずに、スレッドを作成し、 そのスレッドで DoModal() を実行しています。 スレッド作成は AfxBeginThread() を使用しています。 <サンプルソース> ●メインダイアログ // ボタン押下のルーチン void CTestModalDlg::OnButton1() { AfxBeginThread( TestDlgThread, (LPVOID)this, THREAD_PRIORITY_NORMAL ); } // スレッド static UINT TestDlgThread(LPVOID pThis) { CTestDlg1 Dlg; Dlg.DoModal(); } ●DoModal() で表示されるダイアログ 何も手を加えてない、デフォルトのまま。 <結果> DoModal() で表示されたダイアログを CDialog::OnCancel() で終了させ、 メインのスレッドが終了しても、ハンドルカウントが1つ増加しています。 Sleep() を入れて値をみてみると、 ・スレッド作成:2増加 ・DoModal() でダイアログ表示:1増加 ・OnCancel() で終了:増減なし ・スレッド終了:2減少 =>結果、1増加となっていました。 以下のパターンでは問題ありませんでした。 ・スレッドを作成+終了(ダイアログ表示しない) ・スレッドを作成せずに、ボタン押下ルーチンから DoModal() でダイアログ表示+終了 ということで、AfxBeginThread()、DoModal() 自体は問題ないのですが、 スレッドを作成して DoModal() するとリークが発生します。 識者の方、原因、対策など、ご教授願います。

  • マウス移動イベントでMessageBox終了

    Visual C++ 2010 Expressでプログラム開発している初心者です。 現在、オペレータに確認させるため、MessageBox::Show()によりメッセージを表示して OKボタン押下により、MessageBoxを終了しておりますが、ボタン押下する前に マウス移動イベントにより、MessageBoxを終了できないか、調査しております。 MessageBoxのメソッドには、このような機能はないようなので、自前で作成するしか ないかな、と考えております。 その場合には、まず (1)ウィンドウを作成し、マウスイベントを取得できるプログラムを登録 (2)ウィンドウ(メッセージ含む)表示 (3)マウスイベントを取得 (4)イベント解析 (5)ウィンドウ終了 上記のように動かすには、初心者の自分にはとても難しいので 他に方法はないでしょうか? こんな方法があるよ、とヒントでも構いませんので、是非ご教示ください。 よろしくお願い致します。

  • スレッドの扱い方

    javaの初心者です。 質問ですが、 スレッドを使って再生ボタンを押すと画像が動き出すプログラムを作成しています。再生ボタンを押すとスレッドを立ち上げるようにしているのですが、再生ボタンを2回以上押すとどんどん画像の動くスピードが速くなってしまい困ってます。 ボタンが押されるたびにスレッドが立ち上げられているからだと思うのですが、どうしたら初期の状態に戻すことができるか教えていただけないでしょうか?

  • 別スレッドとイベントの終了手順について

    C#の質問になります。 メインフォーム上で別スレッドを起動し、別スレッドからのイベントで メインフォーム上のテキストボックスにメッセージを表示しています。 サンプルソースはフォームにボタン2個とテキストボックス1個を貼り 付けたものになり、ボタン1でスレッド起動、ボタン2で停止させてい ます。 正常パターンでボタン1とボタン2を交互に押下すると意図したとおり テキストボックスにメッセージが出力されます。 このプログラムで、ボタン1を押下し別スレッドが起動した状態で、 フォームの×ボタンを押下すると別スレッドの停止処理中にJoin() 呼び出しで永久に止まってしまいます。 止めるべきスレッド中でイベント(OnTraceEvent)を呼び出している のが問題のような気がします。(この処理がなければ正常) このような時の終了手順の王道的なものはありますでしょうか。   public partial class Form1 : Form   {     ThreadTest _thread = null;     public Form1()     {       InitializeComponent();     }     private void button1_Click( object sender, EventArgs e )     {       if ( this._thread == null )       {         this._thread = new ThreadTest();         this._thread.TraceEvent += new ThreadTest.TraceEventHandler( OnTrace );         this._thread.Open();       }     }     private void button2_Click( object sender, EventArgs e )     {       if ( this._thread != null )       {         this._thread.Close();         this._thread.TraceEvent -= new ThreadTest.TraceEventHandler( OnTrace );         this._thread = null;       }     }     private void OnTrace(String message)     {       if ( this.IsHandleCreated == false )       {         return;       }       MethodInvoker process = (MethodInvoker)delegate()       {         textBox1.AppendText( message + "\r\n" );       };       if ( this.InvokeRequired )       {         this.Invoke( process );       }       else       {         process.Invoke();       }       return;     }     private void Form1_FormClosed( object sender, FormClosedEventArgs e )     {       //フォームの×ボタンを押下した時にスレッドを停止しないと       //破棄されたコントロールを操作しようとするため下記を追加       if ( this._thread != null )       {         this._thread.Close();         this._thread.TraceEvent -= new ThreadTest.TraceEventHandler( OnTrace );         this._thread = null;       }     }   }   class ThreadTest   {     public delegate void TraceEventHandler( String message );     public event TraceEventHandler TraceEvent;     protected virtual void OnTraceEvent( String message )     {       TraceEventHandler TraceEventTemp = TraceEvent;       if ( TraceEventTemp != null )       {         TraceEventTemp( message );       }     }     private Thread _threadLoop = null;     private volatile Boolean _threadFlag = false;     public void Open()     {       //スレッド開始       if ( this._threadLoop == null )       {         this._threadLoop = new Thread( new ThreadStart( Loop ) );         this._threadLoop.Start();         while ( !this._threadLoop.IsAlive ) ;       }     }     public void Close()     {       //スレッド停止       if ( this._threadLoop != null )       {         this._threadFlag = false;         //this._threadLoop.Abort();//ここを有効にすればとりあえず終了する         this._threadLoop.Join();         this._threadLoop = null;       }     }     public void Loop()     {       this._threadFlag = true;       while ( this._threadFlag )       {         OnTraceEvent( DateTime.Now.ToString( "yyyy/MM/dd hh:mm:ss:fff" ) );         Thread.Sleep( 100 );       }     }   }

  • VB.NET スレッドからのイベント受信について

    はじめて質問させていただく、VB.NET初心者です。 ただいまスレッド、イベント処理を作成中で Form1にButton1、Label1を貼り付け以下の様なプログラムを記述しました。 (スレッドにて5秒ごとにイベントを発生させます。) 'イベント引数 Public Class EventArgs Inherits System.EventArgs Public nowTime As String End Class 'イベント発行 Public Class EventTest Public Event _event(ByVal sender As Object, ByVal e As EventArgs) Public Sub Go() Dim args As New EventArgs() args.nowTime = Now.ToString RaiseEvent _event(Me, args) End Sub End Class 'フォーム内処理 'スレッド宣言 Dim MyThread As New System.Threading.Thread(AddressOf _Thread) Private WithEvents _test As New EventTest() 'イベント受信   Private Sub Handler(ByVal sender As System.Object, ByVal e As EventArgs) Handles _test._event Label1.Text = e.nowTime End Sub 'スレッド(5秒間隔でイベント発行) Private Sub _Thread() Dim i As Integer For i = 0 To 99 System.Threading.Thread.Sleep(5000) _test.Go() Next End Sub 'スレッド起動 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click MyThread.Start() End Sub End Class 開発環境から普通に実行すれば正常に動作している様なのですが、 イベント受信部(Handler)のLabel1.Text = e.nowTime部に ブレークポイントを置いてLabel1のウォッチをするとその時点で 処理がとまってしまいます。なぜとまるのかが知りたいです。 作成方法がまずいのでしょうか? 皆様よろしくお願いいたします。

  • [java初心者です]ボタンのイベントの追加

    javaで、複数ボタンを表示し、クリックするとそれぞれのダイアログが表示されるプログラムを作っています。 サンプルを利用して、ボタンを追加するところまで出来たのですが そこからがうまくできません。 アクションリスナーがthisにしてあるため、どのボタンでも 同じダイアログが表示されてしまうのだと思いますが、 this以外にすることはできるのでしょうか? import javax.swing.*; import java.awt.BorderLayout; import java.awt.event.*; public class JOptionPaneTest8 extends JFrame implements ActionListener{ JLabel ansLabel; public static void main(String[] args){ JOptionPaneTest8 frame = new JOptionPaneTest8(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setTitle("タイトル"); frame.setVisible(true); } JOptionPaneTest8(){ JButton ichiButton = new JButton("○○○な時"); ichiButton.addActionListener(this); JButton niButton = new JButton("○○●な時"); niButton.addActionListener(this); JPanel p = new JPanel(); p.add(ichiButton); p.add(niButton); ansLabel = new JLabel("今の気分をクリック!"); JPanel ansPanel = new JPanel(); ansPanel.add(ansLabel); getContentPane().add(p, BorderLayout.CENTER); getContentPane().add(ansPanel, BorderLayout.PAGE_END); } public void actionPerformed(ActionEvent e){ ImageIcon icon = new ImageIcon("aka.gif"); int option = JOptionPane.showConfirmDialog(this, "赤を身の回りに置いて元気に!", "OK?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, icon); if (option == JOptionPane.YES_OPTION){ ansLabel.setText("ほかには?"); }else if (option == JOptionPane.NO_OPTION){ ansLabel.setText("今の気分をクリック!"); } } 気分をボタンとして表示して そのボタンをクリックすると効果的な色のアイコン(gif)と解決策?を ダイアログとして表示させたいです。 高校でついこの間javaを始めた初心者です(>_<) 提出期限が近づいていて焦っています; お手数ですが回答お願いいたします・・・!!

  • スレッドが実行中かどうかの確認

    画面の中にボタンを作成し、そのボタンを押すとスレッドが実行される機能を作成しました。 「一度ボタンを押してスレッドが実行中の場合は処理を実行しない」 という処理を実装したいです。 上記の処理を以下のソースで考えていますが(1)の部分がわかりません。 そもそも(1)のようなことが可能かもわかっていない状況です。 (1)のようなことは可能なのでしょうか? どなたか、知恵を貸していただければと思います。 よろしくお願い致します。 /* ソース */ public class ExThread1 extends Thread{  public void run() {   // 処理  } } public class TEST {  public static void main(String[] args){   ExThread1 thread1 = new ExThread1();   // (1)スレッドが実行中ならstartしない   if(スレッドが実行中ではない){    thread1.start();   }  } }

    • ベストアンサー
    • Java

専門家に質問してみよう