2009-07-24 10 views
2

Я знаю, что многие люди испытывают эту проблему, но решения, которые я нашел в Интернете, похоже, не решают мою проблему. У меня есть композит, который имеет три кнопки. Я хочу следующее: Когда я нажимаю одну кнопку, я хочу, чтобы какая-то другая кнопка была выделена серым цветом (setEnabled (false)), и через некоторое время (после выполнения метода) я хочу, чтобы кнопка была снова включена.SWT update/redraw/layout prοblem

Многие из таких проблем решаются путем вызова метода 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:


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

кнопка будет недоступна, как только метод widgetSelected() вызывается. Это заставляет меня полагать, что мое решение лежит в методах Display.getCurrent(). Тем не менее, я пробовал

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

методов, и они не решили мою проблему.

Спасибо, Эге

ответ

3

Хорошо, я исправил ответ от ginu:.

Новый Runnable() запустить() на самом деле не так много, чтобы ничего, но идея правильная:

Вам нужен новый поток для выполнения вашей работы. Проблема в том, что из этого потока вы не можете вызвать setEnabled на кнопках, потому что это можно сделать только из потока SWT-Event.

Для того, чтобы сбросить кнопки, вам понадобится еще один запуск. Второй runnable передается в Display.callAsync и возвращается до его фактического выполнения, но это не имеет значения. Вы также можете использовать Display.callSync (Runnable), который будет блокировать ваш вызывающий поток до тех пор, пока не будет возвращен runnable.

Протестировано в Eclipse, пока что хорошо.

Редактировать: Btw, причина, по которой вызов layout() или Display.update() не работает, заключается в том, что вы в настоящее время блокируете SWT-Thread своей работой, поэтому вызовы макета/обновления помещаются в очередь и только выполняется, когда вы покидаете обработчик событий. Никогда не блокируйте обработчик событий, чтобы выполнять длительную работу. :)

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, то сначала отключает все кнопки , затем выполняет спящий режим (в том же потоке, не создавая новый поток) , а затем включает все кнопки , что показывает неопределенное поведение. Иногда он отключает третью кнопку, спит, а затем включает все. Иногда он отключает вторую кнопку, спит, а затем включает в себя все и т. Д. Не могли бы вы объяснить мне это неопределенное поведение? Еще раз спасибо. – 2009-09-16 22:32:38

0

Это не кажется, что ваш фрагмент является полным, но несколько вещей, которые пришли на ум по поводу вашей проблемы. Вероятно, вы можете использовать setEnabled, как показано в приведенном ниже фрагменте. Для более продвинутых вещей вы можете посмотреть GridLayout и GridData с свойством .exclude в сочетании с setVisible. Для справки SWT Snippets 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). (т. е. в виджетах button1Selected, сначала включив кнопку3, а затем приостанавливая, а затем отключая кнопку3) – 2009-08-14 14:10:53

0

Я не совсем уверен, если у вас есть проблемы с включением/отключением кнопок, или положить задержку между потоком выполнения.

Я изменил код Jared выше, чтобы выполнить обе указанные операции. Пожалуйста, взгляните на это и дайте мне знать, если это то, что вы искали.

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, Моя цель - включить некоторые кнопки - сделать некоторые работы - снова отключить кнопку. В частности, я хочу, чтобы кнопка отмены включалась только во время некоторого процесса. Поэтому, когда процесс начинается, я хочу, чтобы пользователь мог отменить кнопку. И когда процесс заканчивается, кнопка отмены должна быть отключена. Благодарим за отзыв, но это не сработало. Что происходит, это не изменяет состояние кнопки до тех пор, пока фиктивный сон не будет выполнен. И когда это будет сделано, он будет делать все обновления на кнопке одновременно. Вы можете видеть, что он мигает (он отключается и включается последовательно). Спасибо, хотя – 2009-08-25 17:09:53

 Смежные вопросы

  • Нет связанных вопросов^_^