2009-07-24 11 views
2

Ich weiß, dass viele Menschen dieses Problem erleben, aber die Lösungen, die ich online gefunden habe, scheinen nicht meine zu lösen. Ich habe eine Zusammensetzung, die drei Knöpfe hat. Was ich will, ist folgendes: Wenn ich auf eine Schaltfläche klicke, möchte ich, dass eine andere Schaltfläche ausgegraut wird (setEnabled (false)) und nach einer Weile (nach einer Methodenausführung) möchte ich, dass die Schaltfläche wieder aktiviert wird.SWT Update/Neuzeichnen/Layout Problem

Viele solche Probleme werden durch Aufrufen der layout() -Methode für den übergeordneten Container gelöst, oder this very similar one wird durch Aufrufen von Display.getCurrent() gelöst. Update();

einfach, könnte meinen Code wie folgt zusammengefasst werden:


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(); 
      } 
     } 
    } 
} 

Was passiert ist, die Taste nach dem Ende der widgetSelected() -Methode deaktiviert wird erreicht ist. Das Label wird jedoch häufig ohne Probleme aktualisiert (selbst wenn die Methode label.update() nicht vorhanden ist)

Weitere Informationen: Sagen wir, ich deaktiviere die Schaltfläche, dann ein Thread.sleep() und dann aktivieren Sie die Taste ; es schläft zuerst und dann schnell deaktiviert und aktiviert die Schaltfläche. Ich glaube also, dass alle diese Farbanfragen in der Warteschlange stehen und am Ende der Ausführung verarbeitet werden.

Nützliche Informationen: Ich erkannte, dass, wenn ich eine MessageBox direkt nach meiner Anzeige zu erstellen und anzuzeigen, die Anzeige Änderungen auftreten. Also, wenn ich die folgende Änderung in meiner widgetSelected Methode:


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

die Taste, sobald grau dargestellt wird, wie die widgetSelected() -Methode aufgerufen wird. Dies lässt mich glauben, dass meine Lösung in den Display.getCurrent() -Methoden liegt. Ich versuchte jedoch

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

Methoden und sie lösten nicht mein Problem.

Danke, Ege

Antwort

3

Ok, ich habe die Antwort von ginu korrigiert.

New Runnable() laufen(), um nichts eigentlich nicht viel, aber die Idee ist richtig:

Sie brauchen einen neuen Thread, um Ihre Arbeit zu erledigen. Problem ist, dass Sie von diesem Thread nicht setEnabled auf den Schaltflächen aufrufen können, da dies nur innerhalb des SWT-Event-Threads durchgeführt werden kann.

Sie brauchen also ein anderes runnable um die Tasten zurückzusetzen. Das zweite Runnable wird an Display.callAsync übergeben und kehrt zurück, bevor es tatsächlich ausgeführt wird, aber das spielt hier keine Rolle. Sie könnten auch Display.callSync (Runnable) verwenden, dieser Aufruf würde Ihren aufrufenden Thread blockieren, bis der runnable zurückkehrt.

Getestet in Eclipse, sieht soweit gut aus.

Edit: Btw, der Grund warum Aufruf Layout() oder Display.update() nicht funktionierte ist, dass Sie derzeit den SWT-Thread mit Ihrer Arbeit blockieren, so dass die Aufrufe zu Layout/Update nur in die Warteschlange eingereiht werden ausgeführt, wenn Sie den Event-Handler verlassen. Blockiere niemals einen Event-Handler, um lange zu arbeiten. :)

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

Vielen Dank, es funktioniert. Ich konnte deine Erklärung jedoch immer noch nicht zu 100% erhalten. Ich weiß, dass es nicht möglich ist, SWT-Aktionen in einem anderen Thread als dem SWT-Thread auszuführen. Wenn ich eine SelectionAdapter schreiben, dass ersten deaktiviert alle Tasten dann einen Schlaf führt (in dem gleichen Thread, ohne einen neuen Faden zu schaffen) und ermöglicht dann werden alle Tasten zeigt es indeterministischen Verhalten. Manchmal deaktiviert es die 3. Schaltfläche, schläft und aktiviert sie alle. Manchmal deaktiviert es den 2. Knopf, schläft und aktiviert sie dann alle, usw. Kannst du mir dieses indeterministische Verhalten erklären? Danke nochmal. –

0

Es scheint nicht, dass Ihr Snippet abgeschlossen ist, aber ein paar Dinge in den Sinn kam in Bezug auf Ihr Problem. Sie können wahrscheinlich setEnabled verwenden, wie im folgenden Ausschnitt zu sehen ist. Für weitere Dinge könnten Sie GridLayout und GridData mit der .exclude-Eigenschaft in Verbindung mit setVisible betrachten. Als Referenz ist die SWT Snippets page wirklich großartig.

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

Hallo Jared, Vielen Dank für Ihre Antwort, aber das ist mein Problem nicht lösen. Mein Problem ist das Aktivieren und Deaktivieren einer Schaltfläche (mit einer Pause dazwischen) innerhalb eines gleichen Funktionskörpers (widgetSelected-Methode). (d. h. in der Methode widgetSelected von button1, zuerst die Taste3 aktivieren und dann pausieren und dann die Taste3) –

0

Ich bin nicht wirklich sicher, wenn Sie ein Problem mit der Aktivierung/Deaktivierung der Tasten haben oder die Verzögerung zwischen dem Ausführungsfluss.

Ich habe Jareds Code oben geändert, um beide genannten Operationen durchzuführen. Bitte sehen Sie sich das an und lassen Sie mich wissen, ob Sie das suchen.

Prost. :-)

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

Hallo Ginu, Mein Ziel ist es, einige Taste zu aktivieren - etwas Arbeit - deaktivieren Sie die Taste erneut. Genauer gesagt möchte ich eine Abbrechen-Schaltfläche, die nur während eines Prozesses aktiviert ist. Wenn der Prozess startet, möchte ich, dass der Benutzer die Schaltfläche abbrechen kann. Und wenn der Prozess endet, sollte die Abbrechen-Schaltfläche deaktiviert werden. Vielen Dank für Ihre Antwort, aber es hat auch nicht funktioniert. Was passiert ist, ist, ändert es nicht den Zustand der Taste, bis Dummy-Schlaf getan wird. Und wenn es fertig ist, führt es alle Updates auf der Schaltfläche gleichzeitig aus. Sie können sehen, dass es blinkt (es wird nacheinander deaktiviert und aktiviert). Danke aber –