title: Function being called twice without reason
body: <p>Im making a quiz application. And when i press a key inside a view the model gets updated via the controller. But the function in the models gets called 1 time at first. 2 times next time i press a key, 3 times next time,... etc.</p>
  
  <p>I absolutely have no idea how this is happening. I've tried debugging it and it doesn't get called from multiple places. Just from 1 place. It's almost like the key events get stacked and keep calling the method.</p>
  
  <p>Here is my code of multiple classes.</p>
  
  <p>The quiz view where the key events get picked up :</p>
  
  <pre><code>/**
   * This class will show the questions and react on the keyboard events
   * @author Matthias Claes
   *
   */
  public class QuizView extends JPanel implements View {
  private Observable $model;
  private Controller $controller;
  
  private Question $question;
  
  private boolean $isPressed; /* To check if we already listened to a key press event */
  
  
  public QuizView(Observable model, Controller controller){
      setFocusable(true);
  
      $model = model;
  
      if (controller == null)
          $controller = new QuizController(model);
      else
          $controller = controller;
  
      $question = null;   
      $isPressed = false;
  
      /* Add a keylistener for every team */
      addKeyListener(new KeyAdapter() {
          public void keyTyped(KeyEvent e) {
              int teamSize; /* team size*/
              teamSize = ((QuizModel) getModel()).getTeams().size();
              if (Character.getNumericValue(e.getKeyChar()) &lt;= teamSize) { /* If you pressed a number under the teamsize we listen to it, and there hasn't been pressed before */
  
                  buttonPressed(Character.getNumericValue(e.getKeyChar()));
  
                  // Else ignore the key stroke
              }
          }
      }); 
  
  }
  
  /**
   * If a button gets pressed we call this function
   * @param team the team that pressed their button
   */
  protected void buttonPressed(int team) {
      /* Check if a button is pressed */
      if(((QuizModel) getModel()).getTeamPressed() &gt; 0)
          $isPressed = true;
      else
          $isPressed = false;
  
      /* If there hasn't been pressed yet and the question is not null */
      if(!$isPressed &amp;&amp; $question != null){
          minimizeFrame(); /* Minimize the frame */
  
          /* If this question has a media path we need to pause the audio/video, we also check if the user has installed vlcplayer and selected the right path */
          if($question.getMediaPath() != null &amp;&amp; QuizSoftwareModel.$vlcPath != null)
              ((QuizController)getController()).pause(); /* Pause the video */
  
          /* Give a pop up message to the admin that a team has pushed their button */
          ((QuizController)getController()).showScoreView(team);
      }
  
  }
  
  public void update(Observable arg0, Object arg1) {
      $question = (Question) arg1;
  
      System.out.println("CALLED");
  
      if(((QuizModel) getModel()).getMaximize()) /* Only maximize the JFrame when needed */
          maximizeFrame(); /* Maximize the frame first */     
  
      repaint();
  }
  
  
  /**
   * Maximize the parent JFrame so the teams can see the question
   */
  protected void maximizeFrame() {
      JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
      topFrame.setState(JFrame.MAXIMIZED_BOTH);
  
  }
  
  /**
   * Minimize the parent JFrame so the teams can't see the question anymore 
   */
  protected void minimizeFrame() {
      JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
      topFrame.setState(JFrame.ICONIFIED);
  
  }
  </code></pre>
  
  <p>A view thats shows a pop up window with a button to go the next question or replay the same question when the answer is wrong. Pushing the resume button is creating the problem.</p>
  
  <pre><code>public class GiveScoreView extends JFrame implements View {
  Observable $model;
  Controller $controller;
  
  private Question $question; /* Saves the question that is passed by the update */
  
  /*GUI elements */
  ArrayList&lt;JLabel&gt; $answerLabels;
  ArrayList&lt;JCheckBox&gt; $checkBoxes;
  JLabel $questionLabel;
  JLabel $teamPressedLabel;
  
  /* 2 buttons to resume/end the question */
  JButton $resumeButton;
  JButton $calculateButton;
  
  public GiveScoreView(Observable model, Controller controller) {
  
      setModel(model);
      setController(controller);
  
      $answerLabels = new ArrayList&lt;JLabel&gt;();
      $checkBoxes = new ArrayList&lt;JCheckBox&gt;();
      $questionLabel = new JLabel();
  
      $teamPressedLabel = new JLabel();
  
      $resumeButton = new JButton("Resume question"); /* TODO messagebundle */
      $calculateButton = new JButton("Calculate score"); /* TODO messagebundle */
  
  
      initializeFrame();
  }
  
  /**
   * Initializes the frame
   */
  private void initializeFrame() {
      setTitle("Give a score to the teams"); /* TODO languagebundle, Change the title of the frame */
  
      getContentPane().setLayout(new GridBagLayout());/* Set the layout to gridbaglayout */
  
      addWindowListener(new WindowAdapter() {
          @Override
          public void windowClosing(WindowEvent e) {
              dispose();
          }
      });
  
      pack();
      setVisible(false); /* Don't display it on default */
  
  }
  
  @Override
  public void update(Observable arg0, Object arg1) {
      $question = (Question) arg1;
  
      /* Now we need to display this frame */
      if(((QuizModel) getModel()).getDisplayScoreView()){
          $teamPressedLabel.setText("Team " + Integer.toString(((QuizModel) getModel()).getTeamPressed()) + " is ready to answer!"); /* TODO messagebundle */
          $teamPressedLabel.setFont(new Font("Serif", Font.PLAIN, 34)); /* Change the font */
          displayScoreView();
          setVisible(true); /* Now display the JFrame */
      }
  }
  
  
  private void displayScoreView() {
      Multipleanswer multipleanswerQuestion; /* a multiple answer question to display the multipleanswer questions */
      Multiplechoice multiplechoiceQuestion; /* a multiple choice question to display the multiplechoice questions */
      ArrayList&lt;String&gt; answers = null;
  
      GridBagConstraints c = new GridBagConstraints();
  
      /* Set the position of the JFrame so it's centered */
      Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
  
      // Determine the new location of the window
      int w = getSize().width;
      int h = getSize().height;
      int x = (dim.width - w) / 2;
      int y = (dim.height - h) / 2;
      int i = 0;
  
      // Move the window
      setLocation(x - 150, y - 150);
  
      /* Set size */
      setSize(550, 300);
  
  
      /* If the question isn't empty */
      if (!($question == null)) {
          c.anchor = GridBagConstraints.NORTHWEST; 
  
          $questionLabel.setText($question.getQuestion()); /* Set the text of the JLabel to the question itself */
          $questionLabel.setFont(new Font("Serif", Font.PLAIN, 26)); /* Change the font */
  
          getContentPane().add($teamPressedLabel,c); /* Add the label to the JFrame, the team that has pressed it's button */
  
          c.weighty = 1.0;
  
          /* Display the question under the team pressed text */
          c.gridx = 0;
          c.gridy = 1;
  
          getContentPane().add($questionLabel,c); /* Add the label to the JFrame, the question itself */
  
          /* If the type of the question is multipleanswer */
          if ($question.getType() == QuestionType.MULTIPLEANSWER) {
  
              /* Cast it to multipleanswer question */
              multipleanswerQuestion = (Multipleanswer) $question;
  
              /* Get the answers */
              answers = multipleanswerQuestion.getAnswers();
          } else if ($question.getType() == QuestionType.MULTIPLECHOICE) {
  
              /* Cast it to multiplechoice question */
              multiplechoiceQuestion = (Multiplechoice) $question;
  
              /* Get the answers */
              answers = multiplechoiceQuestion.getAnswers();
          }
  
          /* Speed questions don't show answers so we only display answers if it's not a speed question */
          if ($question.getType() != QuestionType.SPEED) {
              /* Make a JLabel and JCheckBox for each answer */
              for (i = 0; i &lt; answers.size(); i++) {
                  $answerLabels.add(new JLabel(answers.get(i))); /* Make a new JLabel with answer string as text */
                  $checkBoxes.add(new JCheckBox()); /* Make a new JCheckBox */
  
                  $answerLabels.get(i).setFont(new Font("Serif", Font.PLAIN, 16));
                  c.gridx = 0;
                  c.gridy = i + 2;
                  getContentPane().add($answerLabels.get(i),c); /* Add the label to the JFrame */
                  c.gridx = 1;
                  c.gridy = i + 2;
                  getContentPane().add($checkBoxes.get(i),c); /* Add the checkbox to the JFrame */
  
              }
          }
  
          /* Add actionlisteners to the buttons */
          $resumeButton.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {
                  if($question.getMediaPath() != null &amp;&amp; QuizSoftwareModel.$vlcPath != null) /* If there is an audio/video piece */
                      ((GiveScoreController)getController()).resumeMP(); /* Resume the mediaplayer if there is an audio/video piece */
  
                  ((GiveScoreController)getController()).resumeQuestion(); /* Resume the question */
                  closeFrame(); /* Close the frame */
              }
          });
  
          $calculateButton.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent e) {
                  if($question.getMediaPath() != null &amp;&amp; QuizSoftwareModel.$vlcPath != null) /* If there is an audio/video piece */
                      ((GiveScoreController)getController()).closeMP(); /* Close the mediaplayer */
                  ((GiveScoreController)getController()).nextQuestion(); /* Go on to the next question */
                  closeFrame(); /* Close the frame */
              }
          });
          /* Place the buttons */
          c.gridx = 0;
          c.gridy = i + 2;
  
  
          getContentPane().add($resumeButton);
  
          c.gridx = 1;
          c.gridy = i + 2;
  
          getContentPane().add($calculateButton);
      }
  }
  </code></pre>
  
  <p>The controller of the giveScoreView :</p>
  
  <pre><code>/**
   * This class represents the controller of the GiveScoreView
   * @author Matthias Claes
   *
   */
  public class GiveScoreController extends AbstractController {
  
  public GiveScoreController(Observable model) {
      super(model);
  }
  
  /**
   * Resume the question so other teams can answer it
   */
  public void resumeQuestion() {
      ((QuizModel) getModel()).resumeQuestion(); /* Resume the question */
  
  }
  
  }
  </code></pre>
  
  <p>The quiz model :</p>
  
  <pre><code>/**
   * The model of the quiz
   * @author Matthias Claes
   *
   */
  
  public class QuizModel extends Observable {
  private ArrayList&lt;Question&gt; $questions;
  private ArrayList&lt;Team&gt; $teams;
  private Question $currentQuestion;
  private MediaPlayer $mp;
  private int $i; /* The position in the questions, at which question we are at the moment */
  private int $teamPressed; /* The team that pressed their button */
  private boolean $running;
  private boolean $displayScoreView;
  private boolean $maximize; /* A boolean that tells the QuizView if we need to maximize this JFrame again */
  
  
  /**
   * Constructor for QuizModel
   * @param questions a list of questions
   */
  public QuizModel(ArrayList&lt;Question&gt; questions){
  
      $mp = new MediaPlayer(this, null); /* null -&gt; Give the default controller as parameter */
      this.addObserver($mp);
  
      $teams = new ArrayList&lt;Team&gt;();
      if (questions != null) {
          $questions = questions;
      }
      else 
          $questions = new ArrayList&lt;Question&gt;();
  
      $currentQuestion = null;
  
      $teamPressed = 0; /* Default value*/
      $maximize = false; /* Default value */
  
      $i = 0;
      $running = false;
      $displayScoreView = false;
  }
  
  
  
  
  /**
   * Starts the quiz
   */
  public void start() {
  
      if (initialized()) {// quiz properly initialized
          $running = true;
          nextQuestion();
  
      }
      else {
          // TODO what happens when the quiz isn't properly initialized yet
      }
  }
  
  
  /**
   * Will create a view where the admin can choose the score if the answer was right, resume if the answer was false.
   * @param i the team that pushed the button 
   */
  public void showScoreView(int i) {
      $teamPressed = i;
      setDisplayScoreView(true);
  
      /* Update the view */
      System.out.println("show score view");
      setChanged();
      notifyObservers($currentQuestion);
  
  }
  
  /**
   * Get the boolean displayScoreView
   * @return returns true of false, depending on the displayScoreView boolean
   */
  public boolean getDisplayScoreView(){
      return $displayScoreView;
  }
  
  /**
   * Set the $displayScoreView boolean
   * @param displayScoreView the new value of $displayScoreView
   */
  public void setDisplayScoreView(boolean displayScoreView){
      $displayScoreView = displayScoreView;
  }
  
  
  /**
   * Goes to the next question in the quiz
   */
  public void nextQuestion(){
      if($running == true &amp;&amp; $i &lt; $questions.size()){
          $currentQuestion = $questions.get($i);
  
          $i++;
          /* This question has a mediaPath but the user doesn't have vlc installed or selected the wrong folder, so they can't use this question, so we go to the next one */
          if($currentQuestion.getMediaPath() != null &amp;&amp; QuizSoftwareModel.$vlcPath == null){
              JOptionPane.showMessageDialog(null, QuizSoftwareModel.$messages.getString("videoDisplayError"));
              nextQuestion(); /* go the next question */
  
          }
          /* Display the question */ 
          else{
              System.out.println("Diplay first question");
              setChanged();
              notifyObservers($currentQuestion);
          }
  
      } /* End of the quiz */
      else{
          /* Show winner TODO */
      }
  
  }
  
  
  public Question getCurrentQuestion() {
      return $currentQuestion;
  }
  
  public int getI() {
      return $i;
  }
  
  
  /**
   * Resume the question
   */
  public void resumeQuestion() {
      $teamPressed = 0; /* Reset the team that has pressed so other teams can press aswell */
      $maximize = true; /* Maximize the screen again */
      $displayScoreView = false;
  
      /* TODO SAVE THE TEAM INTO AN ARRAY SO THIS TEAM CAN'T PRESS AGAIN */
      System.out.println("RESUME");
      this.setChanged();
      this.notifyObservers($currentQuestion);
  }
  
  
  /**
   * Return the $maximize boolean
   * @return returns the $maximize boolean
   */
  public boolean getMaximize() {
      return $maximize;
  }
  
  }
  </code></pre>
  
  <p>The output i get is like this :
  <br/>Diplay first question <br/>
  CALLED<br/>
  show score view<br/>
  CALLED<br/>
  RESUME<br/>
  CALLED<br/>
  show score view<br/>
  CALLED<br/>
  RESUME<br/>
  CALLED<br/>
  RESUME<br/>
  CALLED<br/></p>
  
  <p>So the resume method in the quizmodel is getting called multiple times.</p>
  
  <p>I don't know if anyone can help me with this, but thanks already.
  My apologies for the very long post but i don't know how to show it else to you guys.</p>