2012-12-14 11 views
6

Jestem nowy na huśtawce, każda pomoc doceniona.Poprawnie aktualizujesz komponenty zamachowe?

W tym kawałku kodu odwracam kartę do góry, jeśli okaże się, że nie pasują, chcę, aby odwrócili ją ponownie twarzą do dołu.

W tej chwili co się dzieje: 1. po kliknięciu pierwsza karta odwraca 2. gdy druga karta kliknięciu jednej z dwóch rzeczy dzieją (a) jeżeli są one takie same oboje zatrzymać się co jest co chcę (b) jeśli nie są one takie same, nigdy nie widzę drugiej karty, ponieważ natychmiast wyświetla ona ponownie tył karty (i tył poprzedniej karty również zgodnie z definicją w mojej metodzie).

Pomyślałem, że wprowadzenie timera uśpienia może spowodować, że druga karta będzie wyświetlana przez pewien czas, zanim się odwróci, ale tak się nie stanie.

Podjęto próbę użycia contentPane.revalidate(); & contentPane.repaint(); ale nic nie zmienia.

Włożyłem w niektórych wyjściach konsoli:

Console output: 
Card: 0 set 
Card: 6 set 
Sleeping now 
Card: 6 unset 
Card: 0 unset 

powyżej jest Wynikiem konsola po kliknięciu dwie karty, które nie pasują

@Override 
public void actionPerformed(ActionEvent e) 
{ 
    String buttonPressed = e.getActionCommand(); 
    int pos = Integer.valueOf(buttonPressed); 
    action = Control.model.ReceiveCardsTurned(pos); 

    keypadArray[pos].setIcon(myIcons[pos]);  
    System.out.println("Card: "+pos+" set"); 
    currentTime.setText("" + Control.model.time); 
    currentScore.setText("" + Control.model.score); 

    //contentPane.revalidate(); 
    //contentPane.repaint();   

    if(Control.model.twoCardsTurned == false) 
    { 
     if (action == "unturn") 
     { 
      System.out.println("Sleeping now"); 

      try 
      { 
       Thread.sleep(1000); 
      } 

      catch (InterruptedException e1) 
      { 
       e1.printStackTrace(); 
      } 

      keypadArray[pos].setIcon(back); 
      keypadArray[Control.model.lastCard].setIcon(back); 
      System.out.println("Card: "+pos+" unset"); 
      System.out.println("Card: "+Control.model.lastCard+" unset"); 
     } 
    } 
} 

Odpowiedz

6

Istnieje kilka ważnych pojęć, których brakuje.

  1. Swing to środowisko napędzane zdarzeniami. Oznacza to, że nie ma żadnych środków (lub przynajmniej tylko nielicznych), że można "poczekać" na dane wprowadzane przez użytkownika, zazwyczaj wystarczy zareagować na ich interakcję.
  2. Swing jest sterowany przez pojedynczy wątek, zwany wątkiem dyspozytorskim zdarzeń (AKA EDT). Obowiązkiem tego wątku jest wysyłanie/przetwarzanie zdarzeń przychodzących do aplikacji do odpowiednich części aplikacji, aby mogły one podjąć działanie.
  3. Menedżer odmalowania wysyła swoje żądania aktualizacji do EDT.

WSZYSTKIE działania, które można podjąć, które powstrzymują EDT od wykonania tej pracy, sprawiają, że aplikacja wygląda jak zawieszona.

NIGDY nie wolno wykonywać żadnych czasochłonnych operacji (takich jak I/O, pętle lub Thread#sleep) w EDT, spowoduje to, że aplikacja "pauza", która nigdy nie jest ładna.

Przeczytać Concurrency in Swing, aby uzyskać więcej informacji.

Teraz masz wiele możliwości. Możesz użyć numeru Thread, aby "czekać" w tle i odwrócić karty, lub możesz użyć numeru SwingWorker lub javax.swing.Timer.

Innym problemem, który masz, jest to, że NIGDY nie należy aktualizować żadnych składników interfejsu użytkownika z żadnego innego urządzenia niż.Oznacza to, że jeśli użyjesz Thread, będziesz odpowiedzialny za ponowną synchronizację tego wątku z EDT. Choć nie jest to trudne, staje się po prostu chaotyczne.

SwingWorker i javax.swing.Timer mają funkcjonalność, która to znacznie ułatwia.

Wątki i SwingWorker doskonale nadają się do przetwarzania w tle i po prostu są przesadzone w przypadku tego problemu. Zamiast tego idealnie pasowałby tutaj model javax.swing.Timer.

if (!Control.model.twoCardsTurned) 
    { 
     if ("unturn".equals(action)) 
     { 
      new Timer(1000, new ActionListener() { 
       public void actionPerformed(ActionEvent evt) { 
        keypadArray[pos].setIcon(back); 
        keypadArray[Control.model.lastCard].setIcon(back); 
        System.out.println("Card: "+pos+" unset"); 
        System.out.println("Card: "+Control.model.lastCard+" unset"); 
       } 
      }).start(); 
     } 
    } 

To naprawdę prosty przykład. Być może zechcesz wprowadzić pewne elementy sterujące, które uniemożliwią użytkownikowi klikanie czegokolwiek, dopóki timer nie odpali, na przykład;)

+0

Jeszcze raz dziękuję, bardzo pomocna i bardzo pouczająca odpowiedź. Będę musiał jeszcze trochę przeczytać na temat podstawowych pojęć związanych z huśtaniem – Ron

7

Nie można spać w wątku wysyłki wydarzenie , ponieważ twój GUI zamrozi. Musisz użyć Swing Timer. W przypadku zadań wykonywanych w tle prawdopodobnie będziesz musiał się martwić w przyszłości, spójrz na SwingWorker.

+0

@HovercraftFullOfEels Poprawiłem odpowiedź, dziękuję za twoją notatkę. – Behnil

+0

Zgadzam się z poduszkowcem, myślę, że 'SwingWorker' jest po zabiciu za ten prosty problem – MadProgrammer

+0

Dzięki za pomoc kumpla – Ron

Powiązane problemy