2009-07-24 46 views
2

多くの人がこの問題を経験していますが、私がオンラインで見つけた解決策は私の問題を解決してくれないようです。私は3つのボタンを持つコンポジットを持っています。私が欲しいのは次のとおりです: ボタンを1つクリックすると、他のボタンをグレーアウト(setEnabled(false))してしばらくして(メソッド実行後)ボタンを再度有効にします。SWTの更新/再描画/レイアウトの問題

このような問題の多くは、親コンテナでlayout()メソッドを呼び出すか、this very similar oneを呼び出すことで解決されます。Display.getCurrent()。update();

される何が起こる

import org.eclipse.swt.events.SelectionEvent; 
import org.eclipse.swt.events.SelectionListener; 
import org.eclipse.swt.layout.GridData; 
import org.eclipse.swt.layout.GridLayout; 
import org.eclipse.swt.widgets.Display; 
import org.eclipse.swt.widgets.Label; 
import org.eclipse.swt.widgets.Shell; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.widgets.Button; 


public class app1 { 

    protected Shell shell; 

    /** 
    * Launch the application. 
    * @param args 
    */ 
    public static void main(String[] args) { 
     try { 
      app1 window = new app1(); 
      window.open(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * Open the window. 
    */ 
    public void open() { 
     Display display = Display.getDefault(); 
     createContents(); 
     shell.open(); 
     shell.layout(); 
     while (!shell.isDisposed()) { 
      if (!display.readAndDispatch()) { 
       display.sleep(); 
      } 
     } 
    } 

    /** 
    * Create contents of the window. 
    */ 
    Button button1 , button2 , button3; 
    Label label; 
    protected void createContents() { 
     shell = new Shell(); 
     shell.setSize(450, 300); 
     shell.setText("SWT Application"); 
     shell.setLayout(new GridLayout(1,false)); 
     { 
      final Composite composite = new Composite(shell, SWT.NONE); 
      composite.setLayout(new GridLayout(3,false)); 
      GridData gd_composite = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL); 
      gd_composite.grabExcessHorizontalSpace = true;   
      gd_composite.horizontalSpan = 10; //? 
      gd_composite.verticalIndent = 5; 
      composite.setLayoutData(gd_composite); 
      GridData gd_button; 

      { 
       button1 = new Button(composite, SWT.NONE); 
       button1.setText("Button 1"); 
       gd_button = new GridData(SWT.FILL, GridData.BEGINNING, false, false); 
       gd_button.horizontalSpan = 1; 
       button1.setLayoutData(gd_button); 
       button1.addSelectionListener(new SelectionListener(){ 
        public void widgetSelected(SelectionEvent e){ 
         try{ 
         button2.setEnabled(false); 
         button2.redraw(); 
         button2.update(); 

         //composite.redraw(); 
         //composite.update(); 
         //composite.layout(); 

         shell.redraw(); 
         shell.update(); 
         shell.layout();      
         Display.getCurrent().update(); 
         } catch (Exception e2) { 
          System.err.println("exception e : " + e2.toString()); 
         } 

         System.out.println("basla"); 


         try { 
          System.out.println("sleep1"); 
          Thread.sleep(100); 
         } catch (InterruptedException e1) { 
          e1.printStackTrace(); 
         } catch (Throwable th) { 
          System.err.println("th: " + th.toString()); 
         } 
         try { 
          System.out.println("sleep2"); 
          Thread.sleep(100); 
         } catch (InterruptedException e1) { 
          e1.printStackTrace(); 
         } catch (Throwable th) { 
          System.err.println("th: " + th.toString()); 
         } 
         try { 
          System.out.println("sleep3"); 
          Thread.sleep(100); 
         } catch (InterruptedException e1) { 
          e1.printStackTrace(); 
         } catch (Throwable th) { 
          System.err.println("th: " + th.toString()); 
         } 

         for(int i=0 ; i < 10000 ; i++) 
         { 
          System.out.println(i); 
         } 
        } 
        public void widgetDefaultSelected(SelectionEvent e) { 
         System.err.println("widgetDefault !"); 
        } 
       }); 
      } 
      { 
       button2 = new Button(composite, SWT.NONE); 
       button2.setText("Button 2"); 
       gd_button = new GridData(SWT.FILL, GridData.CENTER, false, false); 
       gd_button.horizontalSpan = 1; 
       button2.setLayoutData(gd_button); 
       button2.addSelectionListener(new SelectionListener(){ 
        public void widgetSelected(SelectionEvent e){ 
         button1.setEnabled(false); 
         composite.layout(); 
         for (int i=1; i<=100; i++) { 
          try { 
            Thread.sleep(10); 
          } catch (Throwable th) {} 
          label.setText(i + " %"); 
          label.update(); 
         } 
        } 
        public void widgetDefaultSelected(SelectionEvent e) {} 
       }); 
      } 

      { 
       label = new Label(composite , SWT.NONE); 
       label.setText("0 %"); 
       label.update(); 
      } 
     } 
    } 
} 

は、ボタンに到達するwidgetSelected()メソッドの終了後に無効になります:次のように

だけで、私のコードをまとめることができました。ただし、label.update()メソッドがない場合でも、ラベルは問題なく頻繁に更新されます。

追加情報:ボタンを無効にしてから、Thread.sleep()を有効にしてボタン;最初にスリープした後すぐにボタンを無効にして有効にします。だから、私はそのようなペイント要求はすべてキューに入れられ、実行の終わりに処理されると信じています。

便利な情報:私は、表示が変更された直後にMessageBoxを作成して表示すると、表示が変更されることに気付きました。だから、私は私のwidgetSelectedの方法で、以下の変更を加えた場合:

ボタンは、すぐwidgetSelected()メソッドが呼び出されるとグレー表示されます

button2.setEnabled(false) 
MessageBox mBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.ICON_INFORMATION | SWT.OK); 
mBox.setText("Information"); 
mBox.setMessage("Buttons updated!"); 
mBox.open(); 

。これは私の解決策がDisplay.getCurrent()メソッド内にあると私に信じさせる。しかし、私は試した

 
Display.getCurrent().getActiveShell().redraw() 
Display.getCurrent().getActiveShell().update() 
Display.getCurrent().getActiveShell().layout() 

メソッドと私の問題を解決しませんでした。

おかげで、 エーゲ

答えて

3

[OK]を、私はginuから答えを修正しました

あなたの仕事をするには新しいスレッドが必要です。問題は、そのスレッドからSWT-Eventスレッド内でのみ行うことができるため、ボタン上でsetEnabledを呼び出すことができないことです。

ボタンをリセットするには別の実行可能ファイルが必要です。 2番目のランナブルはDisplay.callAsyncに渡され、実際に実行される前に戻りますが、ここでは関係ありません。また、Display.callSync(Runnable)を使用することもできます。その呼び出しは、実行可能ファイルが返るまで呼び出しスレッドをブロックします。

Eclipseでテストしましたが、これまでのところよく見えます。

編集:Btw、layout()またはDisplay.update()を呼び出す理由があなたの仕事で現在SWTスレッドをブロックしているため、レイアウト/更新の呼び出しがキューに入れられ、イベントハンドラから離れるときに実行されます。長い時間をかけてイベントハンドラをブロックしないでください。 :)

package test; 

import org.eclipse.swt.SWT; 
import org.eclipse.swt.events.SelectionAdapter; 
import org.eclipse.swt.events.SelectionEvent; 
import org.eclipse.swt.layout.GridData; 
import org.eclipse.swt.layout.GridLayout; 
import org.eclipse.swt.widgets.Button; 
import org.eclipse.swt.widgets.Display; 
import org.eclipse.swt.widgets.Shell; 

public class Test { 

public static void main(final String[] args) { 
    final Display display = new Display(); 
    final Shell shell = new Shell(display); 
    shell.setLayout(new GridLayout(3, false)); 
    final Button button1 = new Button(shell, SWT.PUSH); 
    button1.setText("Click"); 
    final Button button2 = new Button(shell, SWT.PUSH); 
    button2.setText("Me"); 
    final Button button3 = new Button(shell, SWT.PUSH); 
    button3.setText("Dude"); 

    button1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 
    button2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 
    button3.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 

    button2.setEnabled(false); 
    button3.setEnabled(false); 

    button1.addSelectionListener(new SelectionAdapter() { 
     @Override 
     public void widgetSelected(final SelectionEvent e) { 
      button1.setEnabled(false); 
      button2.setEnabled(true); 
      button3.setEnabled(true); 

      new Thread(new Runnable() { 
       public void run() { 
        try { 
         // Do your operation here. 
         // 
         // Dummy sleep performed here instead. 
         Thread.sleep(1000); 
        } catch (InterruptedException e1) { 
         e1.printStackTrace(); 
        } 
        shell.getDisplay().asyncExec(new Runnable() { 
         public void run() { 
          button1.setEnabled(true); 
          button2.setEnabled(false); 
          button3.setEnabled(false); 
         } 
        }); 
       } 
      }).start(); 
     } 
    }); 

    shell.open(); 
    shell.pack(); 
    while (!shell.isDisposed()) { 
     if (!display.readAndDispatch()) { 
      display.sleep(); 
     } 
    } 

} 

}

+0

ありがとう、それは動作します。しかし、私はまだあなたの説明を100%得ることができませんでした。 SWTスレッドとは異なるスレッドでSWTアクションを実行することはできません。 がすべてのボタンを最初に無効にするSelectionAdapterを書くと、 は新しいスレッドを作成せずに同じスレッド内でスリープを実行し、すべてのボタンを有効にします。 不確定的な動作を示します。ときには、3番目のボタンを無効にしてスリープ状態にして、それらをすべて有効にします。時には2番目のボタンを無効にし、スリープ状態にしてからすべてを有効にします。この不確定的な行動を教えてください。ありがとうございました。 –

0

は、あなたのスニペットが完了したことは表示されませんが、いくつかの事はあなたの問題に関して、頭に浮かびました。以下のスニペットに示すように、おそらくsetEnabledを使うことができます。より進歩したことについては、setVisibleと組み合わせて.excludeプロパティを使ってGridLayoutとGridDataを見ることができます。参考までに、SWTスニペットpageは本当に素晴らしいです。

import org.eclipse.swt.SWT; 
import org.eclipse.swt.events.SelectionAdapter; 
import org.eclipse.swt.events.SelectionEvent; 
import org.eclipse.swt.layout.GridData; 
import org.eclipse.swt.layout.GridLayout; 
import org.eclipse.swt.widgets.Button; 
import org.eclipse.swt.widgets.Display; 
import org.eclipse.swt.widgets.Shell; 

public class App2 { 

    public static void main(final String[] args) { 
     final Display display = new Display(); 
     final Shell shell = new Shell(display); 
     shell.setLayout(new GridLayout(3, false)); 
     final Button button1 = new Button(shell, SWT.PUSH); 
     button1.setText("Click"); 
     final Button button2 = new Button(shell, SWT.PUSH); 
     button2.setText("Me"); 
     final Button button3 = new Button(shell, SWT.PUSH); 
     button3.setText("Dude"); 

     button1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 
     button2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 
     button3.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 
     button2.setEnabled(false); 
     button3.setEnabled(false); 

     button1.addSelectionListener(new SelectionAdapter() { 
      @Override 
      public void widgetSelected(final SelectionEvent e) { 
       button1.setEnabled(false); 
       button2.setEnabled(true); 
       button3.setEnabled(false); 
      } 
     }); 

     button2.addSelectionListener(new SelectionAdapter() { 
      @Override 
      public void widgetSelected(final SelectionEvent e) { 
       button1.setEnabled(false); 
       button2.setEnabled(false); 
       button3.setEnabled(true); 
      } 
     }); 

     button3.addSelectionListener(new SelectionAdapter() { 
      @Override 
      public void widgetSelected(final SelectionEvent e) { 
       button1.setEnabled(true); 
       button2.setEnabled(false); 
       button3.setEnabled(false); 
      } 
     }); 

     shell.open(); 
     shell.pack(); 
     while (!shell.isDisposed()) { 
      if (!display.readAndDispatch()) { 
       display.sleep(); 
      } 
     } 

    } 
} 
+0

こんにちはジャレド、 ご回答いただきありがとうございますが、これは私の問題を解決していません。私の問題は、同じ関数本体(widgetSelectedメソッド)内のボタン(間にポーズを入れて)を有効または無効にすることです。 (つまり、ボタン1のwidgetSelectedメソッドで、最初にボタン3を有効にしてから、一時停止してからボタン3を無効にする) –

0

私はあなたが有効/ボタンの無効化、または実行フローの間の遅延を置くに問題がある場合は本当にわかりません。

私は上記の両方の操作を実行するために、上記のJaredのコードを変更しました。これを見て、あなたが探していたものがあれば教えてください。

乾杯。実際)(実行

新しいRunnableを()ない何もないくらい、しかし、アイデアは正しいです::。:-)

import org.eclipse.swt.SWT; 
import org.eclipse.swt.events.SelectionAdapter; 
import org.eclipse.swt.events.SelectionEvent; 
import org.eclipse.swt.layout.GridData; 
import org.eclipse.swt.layout.GridLayout; 
import org.eclipse.swt.widgets.Button; 
import org.eclipse.swt.widgets.Display; 
import org.eclipse.swt.widgets.Shell; 

public class app1 { 

    public static void main(final String[] args) { 
     final Display display = new Display(); 
     final Shell shell = new Shell(display); 
     shell.setLayout(new GridLayout(3, false)); 
     final Button button1 = new Button(shell, SWT.PUSH); 
     button1.setText("Click"); 
     final Button button2 = new Button(shell, SWT.PUSH); 
     button2.setText("Me"); 
     final Button button3 = new Button(shell, SWT.PUSH); 
     button3.setText("Dude"); 

     button1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 
     button2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 
     button3.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 

     button2.setEnabled(false); 
     button3.setEnabled(false); 

     button1.addSelectionListener(new SelectionAdapter() { 
      @Override 
      public void widgetSelected(final SelectionEvent e) { 
       button1.setEnabled(false); 
       button2.setEnabled(true); 
       button3.setEnabled(true); 

       new Runnable() { 
        public void run() { 

         try { 
          // Do your operation here. 
          // 
          // Dummy sleep performed here instead. 
          Thread.sleep(1000); 
         } catch (InterruptedException e1) { 
          e1.printStackTrace(); 
         } 

        } 
       }.run(); 

       button1.setEnabled(true); 
       button2.setEnabled(false); 
       button3.setEnabled(false); 
      } 
     }); 

     shell.open(); 
     shell.pack(); 
     while (!shell.isDisposed()) { 
      if (!display.readAndDispatch()) { 
       display.sleep(); 
      } 
     } 

    } 
} 
+0

こんにちは、Ginu、 私の目的は、いくつかのボタンを有効にすることです。具体的には、一部のプロセスでのみ有効になるキャンセルボタンが必要です。プロセスが始まると、ボタンをキャンセルできるようにします。プロセスが終了すると、キャンセルボタンが無効になります。 ご回答ありがとうございますが、問題が解決しませんでした。何が起こるかは、ダミースリープが完了するまでボタンの状態を変更しないということです。そして、それが完了すると、ボタン上のすべての更新を同時に行います。点滅しているのを見ることができます(無効になり、連続して有効になります)。しかし、ありがとうございます –

関連する問題