2009-07-24 7 views
2

Je sais que beaucoup de gens connaissent ce problème, mais les solutions que j'ai trouvées en ligne ne semblent pas résoudre le mien. J'ai un composite qui a trois boutons. Ce que je veux est la suivante: Lorsque je clique sur un bouton, je veux qu'un autre bouton soit grisé (setEnabled (faux)) et après un moment (après l'exécution d'une méthode), je veux que le bouton soit à nouveau activé.SWT update/redraw/layout prblem

Beaucoup de ces problèmes sont résolus en appelant la méthode layout() sur le conteneur parent, ou this very similar one est résolu en appelant Display.getCurrent(). Update();

Simplement, mon code pourrait se résumer comme suit:


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

Qu'advient est, le bouton désactivé obtient après la fin de la méthode widgetSelected() est atteinte. Cependant, l'étiquette est mise à jour fréquemment sans aucun problème (même lorsque la méthode label.update() n'est pas là)

Informations supplémentaires: Dites, je désactiver le bouton, puis mettre un Thread.sleep(), puis activer le bouton ; il dort d'abord puis désactive rapidement et active le bouton. Donc, je crois que toutes ces demandes de peinture sont en file d'attente et sont traitées à la fin de l'exécution.

Informations utiles: J'ai réalisé que, lorsque je crée et affiche un MessageBox juste après que mon affichage change, l'affichage change. Donc, si je fais le changement suivant dans ma méthode 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(); 

le bouton sera grisé dès que la méthode widgetSelected() est appelée. Cela me fait croire que ma solution se trouve dans les méthodes Display.getCurrent(). Cependant, j'ai essayé

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

et ils n'ont pas résolu mon problème.

Merci, Ege

Répondre

3

Ok, je l'ai corrigé la réponse de ginu.

New Runnable() run() ne fait pas grand-chose à rien, mais l'idée est correcte:

Vous avez besoin d'un nouveau thread pour faire votre travail. Problème: à partir de ce thread, vous ne pouvez pas appeler setEnabled sur les boutons, car cela ne peut être fait qu'à partir du thread SWT-Event.

Vous avez donc besoin d'une autre exécution pour réinitialiser les boutons. Le second exécutable est passé à Display.callAsync et retourne avant qu'il ne soit réellement exécuté, mais cela n'a pas d'importance ici. Vous pouvez également utiliser Display.callSync (Runnable), cet appel bloquerait votre thread appelant jusqu'à ce que le runnable retourne.

Testé dans Eclipse, semble bon jusqu'à présent. Editer: Btw, la raison pour laquelle appeler layout() ou Display.update() n'a pas fonctionné est que vous bloquez actuellement le SWT-Thread avec votre travail, donc les appels à layout/update sont mis en file d'attente et seulement exécuté lorsque vous quittez le gestionnaire d'événements. Ne bloquez jamais un gestionnaire d'événements pour effectuer un long travail. :)

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

Merci beaucoup, ça marche. Cependant, je ne pouvais toujours pas obtenir votre explication à 100%. Je sais qu'il n'est pas possible d'effectuer des actions SWT dans un thread différent du thread SWT. Lorsque j'écris un SelectionAdapter que désactive d'abord tous les boutons puis effectue un sommeil (dans le même thread, sans créer un nouveau thread) puis active tous les boutons il montre un comportement indéterministe. Parfois, il désactive le 3ème bouton, dort puis les active tous. Parfois, il désactive le 2ème bouton, dort puis les active tous, etc. Pourriez-vous m'expliquer ce comportement indéterministe? Merci encore. –

0

Il ne semble pas que votre extrait est terminé, mais quelques petites choses viennent à l'esprit au sujet de votre problème. Vous pouvez probablement utiliser setEnabled comme indiqué dans l'extrait ci-dessous. Pour plus de choses à l'avance, vous pouvez regarder GridLayout et GridData avec la propriété .exclude en conjonction avec setVisible. Pour référence, les extraits de SWT page sont vraiment géniaux.

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

Salut Jared, Merci pour votre réponse, mais cela ne résout pas mon problème. Mon problème est d'activer et de désactiver un bouton (avec une pause entre) dans un même corps de fonction (méthode widgetSelected). (c'est-à-dire dans la méthode widgetSelected de button1, en activant d'abord le bouton3 puis en le mettant en pause puis en le désactivant) –

0

Je ne suis pas vraiment sûr si vous avez un problème avec l'activation/désactivation des boutons, ou de mettre le retard entre le flux d'exécution.

J'ai modifié le code de Jared ci-dessus pour effectuer les deux opérations mentionnées. S'il vous plaît jeter un oeil à cela et laissez-moi savoir si ce que vous cherchiez.

Cheers. :-)

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

Hi Ginu, Mon but est d'activer certains boutons - de travailler - de désactiver à nouveau le bouton. Plus précisément, je veux un bouton d'annulation qui est activé uniquement pendant certains processus. Donc, quand le processus commence, je veux que l'utilisateur puisse annuler le bouton. Et lorsque le processus se termine, le bouton Annuler doit être désactivé. Merci pour votre réponse, mais cela n'a pas fonctionné non plus. Ce qui se passe est que cela ne change pas l'état du bouton tant que le sommeil artificiel n'est pas terminé. Et quand c'est fait, il fait toutes les mises à jour sur le bouton en même temps. Vous pouvez le voir clignoter (il est désactivé et activé consécutivement). Merci bien –