2015-06-18 4 views
-2

Я вызываю этот метод под названием check в одном из моих абстрактных классов, но по какой-то причине JLabel (проблема), которую я добавляю на панель JPanel (панель), не отображается. Почему это происходит? Любые объяснения, я использую как перерисовку, так и проверку методов, но пока ничего не появляется.Почему мой JLabel не отображается

+2

Просьба представить [MCVE] (http://stackoverflow.com/help/mcve) или [SSCCE] (http://sscce.org/) что мы можем скопировать-вставить и увидеть ту же проблему, что и вы. Этот код требует исправления путем удаления некоторых ненужных переменных, добавления библиотек и т. Д. Пожалуйста, помогите нам помочь вам. – Frakcool

+0

Ваш код меня беспокоит, либо вы нарушаете правила одиночного потока качания, либо блокируя EDT с помощью yr, тогда как петли и thread.sleep или изменение пользовательского интерфейса извне контекста EDT – MadProgrammer

ответ

-1

Если вы использовали Jframe для этого приложения, просто проверьте, добавили ли вы панель в рамку, вы только что добавили метку на панель, просто проверьте, добавили ли вы панель в Jframe , в противном случае он не будет отображаться

+0

уже сделали это. – user2451511

4

проблемы вы испытываете это вы блокирование события диспетчерские темы, предотвратить UI от обновлялись или какие-либо новые события из обработаны ...

он начинается здесь ...

 for(int i = 0; i < 15; i++) 
     { 
      //... 

      //Check to see if user has enetered anything 
      // And is compounded here 
      while(!answered) 
      { 
       Thread.sleep(duration); 
       //... 
      }   

Вы явно думаете о процедуре (как и для консольной программы), но это не то, как работают графические интерфейсы, графические интерфейсы управляются событиями, что-то происходит в какой-то момент времени, и вы отвечаете на него.

Мое предложение состоит в том, чтобы расследовать Swing Timer, что позволит вам запланировать обратный вызов в какой-то момент в будущем и выполнить какое-либо действие при его запуске, которое может быть использовано для изменения пользовательского интерфейса, поскольку оно выполнено в контекст EDT.

См Concurrency in Swing и How to use Swing Timers для получения более подробной информации

Я также рекомендую вам взглянуть на CardLayout, как это может сделать легче изменить между различными видами

См How to Use CardLayout для более подробной информации

Основы

Я очень много работаю над принципом «Код для интерфейса не реализации» и Model-View-Controller. Они в основном побуждают вас разделить и изолировать ответственность, поэтому изменение одной части не будет отрицательно влиять на другую.

Это также означает, что вы можете использовать plug'n'play, развязать код и сделать его более гибким.

Начните с основным, вам нужно что-то, что имеет какой-то текст (вопрос), правильный ответ и некоторые «параметры» (или неправильные ответы)

public interface Question { 

    public String getPrompt(); 
    public String getCorrectAnswer(); 
    public String[] getOptions(); 
    public String getUserResponse(); 
    public void setUserResponse(String response); 
    public boolean isCorrect(); 

} 

Так, довольно основной. Вопрос имеет подсказку, правильный ответ, некоторые неправильные ответы и может управлять ответом пользователя. Для простоты использования он также имеет метод isCorrect

Теперь нам нужна фактическая реализация. Это довольно простой пример, но вы можете иметь несколько различных реализаций и может даже включать дженерики для типа ответов (которые я на себя в качестве String ради аргумента)

public class DefaultQuestion implements Question { 

    private final String prompt; 
    private final String correctAnswer; 
    private final String[] options; 

    private String userResponse; 

    public DefaultQuestion(String prompt, String correctAnswer, String... options) { 
     this.prompt = prompt; 
     this.correctAnswer = correctAnswer; 
     this.options = options; 
    } 

    @Override 
    public String getPrompt() { 
     return prompt; 
    } 

    @Override 
    public String getCorrectAnswer() { 
     return correctAnswer; 
    } 

    @Override 
    public String[] getOptions() { 
     return options; 
    } 

    @Override 
    public String getUserResponse() { 
     return userResponse; 
    } 

    @Override 
    public void setUserResponse(String response) { 
     userResponse = response; 
    } 

    @Override 
    public boolean isCorrect() { 
     return getCorrectAnswer().equals(getUserResponse()); 
    } 
} 

Хорошо, что все хорошо и все, но что это на самом деле делает для нас? Ну, знайте, что вы можете создать простой компонент, единственной задачей которого является представить вопрос пользователю и обработать их ответ ...

public class QuestionPane extends JPanel { 

    private Question question; 

    public QuestionPane(Question question) { 
     this.question = question; 

     setLayout(new BorderLayout()); 

     JLabel prompt = new JLabel("<html><b>" + question.getPrompt() + "</b></html>"); 
     prompt.setHorizontalAlignment(JLabel.LEFT); 

     add(prompt, BorderLayout.NORTH); 

     JPanel guesses = new JPanel(new GridBagLayout()); 
     guesses.setBorder(new EmptyBorder(5, 5, 5, 5)); 
     GridBagConstraints gbc = new GridBagConstraints(); 
     gbc.gridwidth = GridBagConstraints.REMAINDER; 
     gbc.weightx = 1; 
     gbc.anchor = GridBagConstraints.WEST; 

     List<String> options = new ArrayList<>(Arrays.asList(question.getOptions())); 
     options.add(question.getCorrectAnswer()); 
     Collections.sort(options); 

     ButtonGroup bg = new ButtonGroup(); 
     for (String option : options) { 
      JRadioButton btn = new JRadioButton(option); 
      bg.add(btn); 

      guesses.add(btn, gbc); 
     } 

     add(guesses); 

    } 

    public Question getQuestion() { 
     return question; 
    } 

    public class ActionHandler implements ActionListener { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      getQuestion().setUserResponse(e.getActionCommand()); 
     } 

    } 

} 

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

Теперь нам нужен способ управления несколькими вопросами, викториной!

public class QuizPane extends JPanel { 

    private List<Question> quiz; 

    private long timeOut = 5; 
    private Timer timer; 
    private JButton next; 

    private CardLayout cardLayout; 
    private int currentQuestion; 

    private JPanel panelOfQuestions; 

    private Long startTime; 

    public QuizPane(List<Question> quiz) { 
     this.quiz = quiz; 
     cardLayout = new CardLayout(); 
     panelOfQuestions = new JPanel(cardLayout); 

     JButton start = new JButton("Start"); 
     start.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       currentQuestion = -1; 
       nextQuestion(); 
       timer.start(); 
      } 
     }); 

     JPanel filler = new JPanel(new GridBagLayout()); 
     filler.add(start); 
     panelOfQuestions.add(filler, "start"); 

     for (int index = 0; index < quiz.size(); index++) { 
      Question question = quiz.get(index); 
      QuestionPane pane = new QuestionPane(question); 
      panelOfQuestions.add(pane, Integer.toString(index)); 
     } 
     panelOfQuestions.add(new JLabel("The quiz is over"), "last"); 
     currentQuestion = 0; 
     cardLayout.show(panelOfQuestions, "start"); 

     setLayout(new BorderLayout()); 
     add(panelOfQuestions); 

     JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT)); 
     next = new JButton("Next"); 
     buttonPane.add(next); 
     next.setEnabled(false); 

     add(buttonPane, BorderLayout.SOUTH); 

     next.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       nextQuestion(); 
      } 
     }); 

     timer = new Timer(250, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       if (startTime == null) { 
        startTime = System.currentTimeMillis(); 
       } 
       long duration = (System.currentTimeMillis() - startTime)/1000; 
       if (duration >= timeOut) { 
        nextQuestion(); 
       } else { 
        long timeLeft = timeOut - duration; 
        next.setText("Next (" + timeLeft + ")"); 
        next.repaint(); 
       } 
      } 
     }); 
    } 

    protected void nextQuestion() { 
     timer.stop(); 
     currentQuestion++; 
     if (currentQuestion >= quiz.size()) { 
      cardLayout.show(panelOfQuestions, "last"); 
      next.setEnabled(false); 
      // You could could loop through all the questions and tally 
      // the correct answers here 
     } else { 
      cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion)); 
      startTime = null; 
      next.setText("Next"); 
      next.setEnabled(true); 
      timer.start(); 
     } 
    } 
} 

Хорошо, это немного сложнее, но основы, он управляет каким вопрос в настоящее время представлена ​​пользователю, управляет время и позволяет пользователю перейти к следующему вопросу, если они хотят.

Теперь это легко заблудиться в деталях ...

Эта часть коды фактически Сет до основного «вида», используя CardLayout

panelOfQuestions.add(filler, "start"); 

for (int index = 0; index < quiz.size(); index++) { 
    Question question = quiz.get(index); 
    QuestionPane pane = new QuestionPane(question); 
    panelOfQuestions.add(pane, Integer.toString(index)); 
} 
panelOfQuestions.add(new JLabel("The quiz is over"), "last"); 
currentQuestion = 0; 
cardLayout.show(panelOfQuestions, "start"); 

Кнопки start " конечный экран ", и каждый отдельный QuestionPane добавлен в panelOfQuestions, который управляется CardLayout, что позволяет легко« перевернуть »просмотры по мере необходимости.

Я использую простой метод, чтобы перейти к следующему вопросу

protected void nextQuestion() { 
    timer.stop(); 
    currentQuestion++; 
    if (currentQuestion >= quiz.size()) { 
     cardLayout.show(panelOfQuestions, "last"); 
     next.setEnabled(false); 
     // You could could loop through all the questions and tally 
     // the correct answers here 
    } else { 
     cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion)); 
     startTime = null; 
     next.setText("Next"); 
     next.setEnabled(true); 
     timer.start(); 
    } 
} 

В основном это увеличивает счетчик и проверяет, чтобы увидеть, если мы исчерпали вопросы или нет. Если у нас есть, он отключает следующую кнопку и отображает «последний» вид для пользователя, если нет, он переходит к следующему представлению вопроса и перезапускает таймер тайм-аута.

Теперь здесь приходит «волшебство» ...

timer = new Timer(250, new ActionListener() { 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (startTime == null) { 
      startTime = System.currentTimeMillis(); 
     } 
     long duration = (System.currentTimeMillis() - startTime)/1000; 
     if (duration >= timeOut) { 
      nextQuestion(); 
     } else { 
      long timeLeft = timeOut - duration; 
      next.setText("Next (" + timeLeft + ")"); 
     } 
    } 
}); 

Свинг Timer действует цикл псевдо, что означает, что он будет вызывать метод actionPerformed на регулярных базах, так же, как for или while цикла будет , но он делает это так, что он не блокирует EDT.

Этот пример добавляет немного больше «волшебства» в том, что он действует как таймер обратного отсчета, он проверяет, как долго вопрос был видимым для пользователя, и показывает отсчет до тех пор, пока он автоматически не перейдет к следующему вопросу, когда duration больше или равно timeOut (5 секунд в этом примере), он вызывает метод nextQuestion

Но как вы его используете, вы спрашиваете? Вы создаете List из Question с, создать экземпляр QuizPane и добавить, что в какой-то другой контейнер, который отображается на экране, например ...

public class QuizMaster { 

    public static void main(String[] args) { 
     new QuizMaster(); 
    } 

    public QuizMaster() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       List<Question> quiz = new ArrayList<>(5); 
       quiz.add(new DefaultQuestion("Bananas are:", "Yellow", "Green", "Blue", "Ping", "Round")); 
       quiz.add(new DefaultQuestion("1 + 1:", "2", "5", "3", "An artificial construct")); 
       quiz.add(new DefaultQuestion("In the UK, it is illegal to eat...", "Mince pies on Christmas Day", "Your cousin", "Bananas")); 
       quiz.add(new DefaultQuestion("If you lift a kangaroo’s tail off the ground...", "It can’t hop", "It will kick you in the face", "Act as a jack")); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new QuizPane(quiz)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

} 

И, наконец, потому что я знаю, что вы хотите один, полностью runable пример

QuizMaster

import java.awt.BorderLayout; 
import java.awt.CardLayout; 
import java.awt.EventQueue; 
import java.awt.FlowLayout; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collections; 
import java.util.List; 
import javax.swing.ButtonGroup; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JRadioButton; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.border.EmptyBorder; 

public class QuizMaster { 

    public static void main(String[] args) { 
     new QuizMaster(); 
    } 

    public QuizMaster() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       List<Question> quiz = new ArrayList<>(5); 
       quiz.add(new DefaultQuestion("Bananas are:", "Yellow", "Green", "Blue", "Ping", "Round")); 
       quiz.add(new DefaultQuestion("1 + 1:", "2", "5", "3", "An artificial construct")); 
       quiz.add(new DefaultQuestion("In the UK, it is illegal to eat...", "Mince pies on Christmas Day", "Your cousin", "Bananas")); 
       quiz.add(new DefaultQuestion("If you lift a kangaroo’s tail off the ground...", "It can’t hop", "It will kick you in the face", "Act as a jack")); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new QuizPane(quiz)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class QuizPane extends JPanel { 

     private List<Question> quiz; 

     private long timeOut = 5; 
     private Timer timer; 
     private JButton next; 

     private CardLayout cardLayout; 
     private int currentQuestion; 

     private JPanel panelOfQuestions; 

     private Long startTime; 

     public QuizPane(List<Question> quiz) { 
      this.quiz = quiz; 
      cardLayout = new CardLayout(); 
      panelOfQuestions = new JPanel(cardLayout); 

      JButton start = new JButton("Start"); 
      start.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        currentQuestion = -1; 
        nextQuestion(); 
        timer.start(); 
       } 
      }); 

      JPanel filler = new JPanel(new GridBagLayout()); 
      filler.add(start); 
      panelOfQuestions.add(filler, "start"); 

      for (int index = 0; index < quiz.size(); index++) { 
       Question question = quiz.get(index); 
       QuestionPane pane = new QuestionPane(question); 
       panelOfQuestions.add(pane, Integer.toString(index)); 
      } 
      panelOfQuestions.add(new JLabel("The quiz is over"), "last"); 
      currentQuestion = 0; 
      cardLayout.show(panelOfQuestions, "start"); 

      setLayout(new BorderLayout()); 
      add(panelOfQuestions); 

      JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT)); 
      next = new JButton("Next"); 
      buttonPane.add(next); 
      next.setEnabled(false); 

      add(buttonPane, BorderLayout.SOUTH); 

      next.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        nextQuestion(); 
       } 
      }); 

      timer = new Timer(250, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        if (startTime == null) { 
         startTime = System.currentTimeMillis(); 
        } 
        long duration = (System.currentTimeMillis() - startTime)/1000; 
        if (duration >= timeOut) { 
         nextQuestion(); 
        } else { 
         long timeLeft = timeOut - duration; 
         next.setText("Next (" + timeLeft + ")"); 
         next.repaint(); 
        } 
       } 
      }); 
     } 

     protected void nextQuestion() { 
      timer.stop(); 
      currentQuestion++; 
      if (currentQuestion >= quiz.size()) { 
       cardLayout.show(panelOfQuestions, "last"); 
       next.setEnabled(false); 
       // You could could loop through all the questions and tally 
       // the correct answers here 
      } else { 
       cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion)); 
       startTime = null; 
       next.setText("Next"); 
       next.setEnabled(true); 
       timer.start(); 
      } 
     } 
    } 

    public interface Question { 

     public String getPrompt(); 

     public String getCorrectAnswer(); 

     public String[] getOptions(); 

     public String getUserResponse(); 

     public void setUserResponse(String response); 

     public boolean isCorrect(); 
    } 

    public class DefaultQuestion implements Question { 

     private final String prompt; 
     private final String correctAnswer; 
     private final String[] options; 

     private String userResponse; 

     public DefaultQuestion(String prompt, String correctAnswer, String... options) { 
      this.prompt = prompt; 
      this.correctAnswer = correctAnswer; 
      this.options = options; 
     } 

     @Override 
     public String getPrompt() { 
      return prompt; 
     } 

     @Override 
     public String getCorrectAnswer() { 
      return correctAnswer; 
     } 

     @Override 
     public String[] getOptions() { 
      return options; 
     } 

     @Override 
     public String getUserResponse() { 
      return userResponse; 
     } 

     @Override 
     public void setUserResponse(String response) { 
      userResponse = response; 
     } 

     @Override 
     public boolean isCorrect() { 
      return getCorrectAnswer().equals(getUserResponse()); 
     } 
    } 

    public class QuestionPane extends JPanel { 

     private Question question; 

     public QuestionPane(Question question) { 
      this.question = question; 

      setLayout(new BorderLayout()); 

      JLabel prompt = new JLabel("<html><b>" + question.getPrompt() + "</b></html>"); 
      prompt.setHorizontalAlignment(JLabel.LEFT); 

      add(prompt, BorderLayout.NORTH); 

      JPanel guesses = new JPanel(new GridBagLayout()); 
      guesses.setBorder(new EmptyBorder(5, 5, 5, 5)); 
      GridBagConstraints gbc = new GridBagConstraints(); 
      gbc.gridwidth = GridBagConstraints.REMAINDER; 
      gbc.weightx = 1; 
      gbc.anchor = GridBagConstraints.WEST; 

      List<String> options = new ArrayList<>(Arrays.asList(question.getOptions())); 
      options.add(question.getCorrectAnswer()); 
      Collections.sort(options); 

      ButtonGroup bg = new ButtonGroup(); 
      for (String option : options) { 
       JRadioButton btn = new JRadioButton(option); 
       bg.add(btn); 

       guesses.add(btn, gbc); 
      } 

      add(guesses); 

     } 

     public Question getQuestion() { 
      return question; 
     } 

     public class ActionHandler implements ActionListener { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       getQuestion().setUserResponse(e.getActionCommand()); 
      } 

     } 

    } 

} 
+0

, но почему это не отображается, и какой код я мог бы добавить/удалить, чтобы исправить эту проблему? – user2451511

+0

Почему не появляется? Поскольку вы блокируете поток Dispatching Event, который отвечает за обработку, среди прочего, запросы на рисование. Какой код следует добавить/удалить? Удалите все, серьезно, вы должны полностью переосмыслить процесс. Вы не можете использовать циклы 'for' /' while' для управления потоком вопросов, вместо этого вам нужно использовать Swing 'Timer' в качестве псевдо-цикла для управления потоком. Это потребует, чтобы вы переосмыслили, как задаются вопросы и как вы отслеживаете вход пользователей. – MadProgrammer

+0

. Я бы начал с выяснения того, как вы собираетесь создавать пользовательский компонент, который мог бы спросить пользователя о вопросе и записать свой ответ как единый блок работы, таким образом, вы можете заранее создать вопросы заранее (прежде чем вы начнете показывать их пользователю) и просто используйте «Список» или массив в качестве механизма управления. Это позволит вам использовать «CardLayout», чтобы просто перевернуть между ними. – MadProgrammer

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