CardLayout显示两个面板,闪烁

时间:2014-03-08 21:41:07

标签: java swing user-interface jpanel cardlayout

我正在尝试使用CardLayout来显示两个JPanels,一个主菜单和一个控制屏幕。当我向卡JPanels添加两个JPanel时,它只会显示两个带有闪烁图像的卡片。这是我的代码:

package main;

public class MazeGame {

// Layout

public static JPanel cards = new JPanel();

// Window

public static JFrame window;
public static String windowLabel = "2D Maze Game - Before Alpha";

// Window Dimensions and Location

public static int WIDTH = 600;
public static int HEIGHT = 600;

public static Component center = null;
public static int exit = 3;

public static void main(String[] args) {
    window = new JFrame(windowLabel);

    window.setSize(new Dimension(WIDTH, HEIGHT));
    window.setResizable(false);
    window.setLocationRelativeTo(center);
    window.setDefaultCloseOperation(exit);

    cards.setLayout(new CardLayout());

    cards.add(new MazeGamePanel(), "main");
    cards.add(new MazeControlsPanel(), "controls");
    window.add(cards);

    CardLayout cl = (CardLayout) cards.getLayout();
    cl.show(cards, "main");



    window.setVisible(true);
}

}

MazeGamePanel:

公共类MazeGamePanel扩展了JPanel实现的Runnable {

private static final long serialVersionUID = 1L;


// Timer

public Timer timer;
// Font

public Font bitTrip;

public Thread thread;

public BufferedImage canvas;
public Graphics2D g;

public boolean running;

public int HEIGHT = MazeGame.HEIGHT;

public int WIDTH = MazeGame.WIDTH;

public int FPS = 30;

public int opacity = 255;

public int selectedOption = 0;
public String option1 = "Play";
public String option2 = "Controls";
public String option3 = "Quit";

public MazeGamePanel() {
    this.setFocusable(true);
    this.requestFocus();

    addKeyListener(new MazeGameKeyListener());

    try {
        bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
                "res/font/BitTrip7.TTF"));
    } catch (FontFormatException | IOException e) {
        e.printStackTrace();
    }

    /**
    ActionListener action = new ActionListener () {

        public void actionPerformed (ActionEvent e) {
        if(opacity != 0) {
            opacity--;
        } else {
            timer.stop();
            opacity = 0;
        }
    }
};  


timer = new Timer(10, action);
timer.setInitialDelay(0);
timer.start();
    */
}

public void addNotify() {
    super.addNotify();
    if (thread == null) {
        thread = new Thread(this);
        thread.start();
    }
}

public void run() {
    running = true;
    canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

    g = (Graphics2D) canvas.getGraphics();

    long startTime = 0;
    long millis = 0;
    long waitTime = 0;

    long targetTime = 1000 / FPS;

    while (running) {

        startTime = System.nanoTime();

        update();
        render();
        draw();

        millis = (System.nanoTime() - startTime) / 1000000;

        waitTime = targetTime - millis;

        try {
            Thread.sleep(waitTime);

        } catch (Exception e) {

        }
    }

}

// TODO
public void render() {
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, WIDTH, HEIGHT);

    bitTrip = bitTrip.deriveFont(40F);
    g.setFont(bitTrip);

    if (selectedOption == 0) {

        //Play
        g.setColor(Color.BLACK);
        g.drawString(option1, WIDTH / 2  - 200, HEIGHT / 2);

        //Controls
        g.setColor(Color.GRAY);
        g.drawString(option2, WIDTH / 2  - 200, HEIGHT / 2 + 50);

        //Quit
        g.setColor(Color.GRAY);
        g.drawString(option3, WIDTH / 2  - 200, HEIGHT / 2 + 100);

    } else if (selectedOption == 1) {

        //Play
        g.setColor(Color.GRAY);
        g.drawString(option1, WIDTH / 2  - 200, HEIGHT / 2);

        //Controls
        g.setColor(Color.BLACK);
        g.drawString(option2, WIDTH / 2  - 200, HEIGHT / 2 + 50);

        //Quit
        g.setColor(Color.GRAY);
        g.drawString(option3, WIDTH / 2  - 200, HEIGHT / 2 + 100);


    } else if (selectedOption == 2) {
        //Play
        g.setColor(Color.GRAY);
        g.drawString(option1, WIDTH / 2  - 200, HEIGHT / 2);

        //Controls
        g.setColor(Color.GRAY);
        g.drawString(option2, WIDTH / 2  - 200, HEIGHT / 2 + 50);

        //Quit
        g.setColor(Color.BLACK);
        g.drawString(option3, WIDTH / 2  - 200, HEIGHT / 2 + 100);
    }


    //g.setColor(new Color(0, 0, 0, opacity));
    //g.fillRect(0, 0, WIDTH, HEIGHT);
}

public void update() {

}

public void draw() {
    Graphics g2 = this.getGraphics();
    g2.drawImage(canvas, 0, 0, null);
    g2.dispose();

}

private class MazeGameKeyListener extends KeyAdapter {

    public void keyPressed(KeyEvent e) {

        if (e.getKeyCode() == KeyEvent.VK_UP) {
            if (selectedOption == 1) {
                selectedOption = 0;
            } else if (selectedOption == 2) {
                selectedOption = 1;
            }
        }

        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            if (selectedOption == 0) {
                selectedOption = 1;
            } else if (selectedOption == 1) {
                selectedOption = 2;
            }
        }

        if(e.getKeyCode() == KeyEvent.VK_ENTER) {
            if(selectedOption == 1) {
                MazeGame.window.removeAll();
                MazeGame.window.add(new MazeControlsPanel());
                MazeGame.window.validate();
            }
        }
    }
}

}

MazeControlsPanel:

包装屏幕;

public class MazeControlsPanel extends JPanel implements Runnable {

private static final long serialVersionUID = 1L;

// Font

public Font bitTrip;

public Thread thread;

public BufferedImage canvas;
public Graphics2D g;

public boolean running;

public int HEIGHT = MazeGame.HEIGHT;

public int WIDTH = MazeGame.WIDTH;

public int FPS = 30;

public int opacity = 255;

public int selectedOption = 0;

public MazeControlsPanel() {
    this.setFocusable(true);
    this.requestFocus();

    addKeyListener(new MazeControlsKeyListener());

    try {
        bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
                "res/font/BitTrip7.TTF"));
    } catch (FontFormatException | IOException e) {
        e.printStackTrace();
    }

    /**
    final Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {

        public void run() {
            if (opacity != 0) {
                opacity--;
            } else {
                timer.cancel();
                opacity = 0;
            }
        }

    }, 0, 4);

* /     }

public void addNotify() {
    super.addNotify();
    if (thread == null) {
        thread = new Thread(this);
        thread.start();
    }
}

public void run() {
    running = true;
    canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

    g = (Graphics2D) canvas.getGraphics();

    long startTime = 0;
    long millis = 0;
    long waitTime = 0;

    long targetTime = 1000 / FPS;

    while (running) {

        startTime = System.nanoTime();

        update();
        render();
        draw();

        millis = (System.nanoTime() - startTime) / 1000000;

        waitTime = targetTime - millis;

        try {
            Thread.sleep(waitTime);

        } catch (Exception e) {

        }
    }

}

// TODO
public void render() {
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, WIDTH, HEIGHT);

    bitTrip = bitTrip.deriveFont(40F);
    g.setFont(bitTrip);

    // Quit
    g.setColor(Color.BLACK);
    g.drawString("Main Menu", WIDTH / 2 - 200, HEIGHT / 2 + 100);

    //g.setColor(new Color(0, 0, 0, opacity));
    //g.fillRect(0, 0, WIDTH, HEIGHT);
}

public void update() {

}

public void draw() {
    Graphics g2 = this.getGraphics();
    g2.drawImage(canvas, 0, 0, null);
    g2.dispose();

}

private class MazeControlsKeyListener extends KeyAdapter {

    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
        }
    }
}

}

1 个答案:

答案 0 :(得分:4)

这是一个问题:

final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {

不要在Swing程序中使用java.util.Timer,因为您会遇到线程问题。而是使用Swing Timer

此外,您在后台线程中进行Swing调用,并使用通过在组件上调用getGraphics()获得的Graphics对象,为Swing程序调用两个no-nos。


修改
这是我使用CardLayout交换组件的一个程序,但是当一个组件淡入另一个组件时将其淡出。它的作用:

  • 程序使用JPanel将所有交换组件添加到CardLayout。
  • 它还添加了一个SwappingImgPanel,一个用于绘制两个图像的JPanel,一个淡出的组件,以及一个淡入的组件。
  • 当您交换组件时,您可以创建两个组件的图像,当前可见的组件和下一个可见的组件。
  • 您将图像发送到SwappingImgPanel实例
  • 您在SwappingImgPanel实例上调用swap()
  • 然后SwappingImgPanel将绘制两个图像,但使用Swing Timer更改Graphic对象的复合值。这是导致图像部分可见的原因。
  • 当SwappingImgPanel的Timer完成时,会调用done()方法,将SwappingImgPanel的状态设置为State.DONE。
  • 主GUI正在侦听SwappingImgPanel的状态值,当它达到State.DONE时,主GUI显示实际的下一个组件(而不是它的图像)。

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;


@SuppressWarnings("serial")
public class DimmingPanelSwaps extends JPanel {
   private static final int DELTA_TIME = 10;
   private static final int ELAPSED_TIME = 3000;
   private static final String SWAPPING_IMG_PANEL = "swapping img panel";
   private CardLayout cardlayout = new CardLayout();
   private JPanel cardHolderPanel = new JPanel(cardlayout);
   private DefaultComboBoxModel<String> comboModel = new DefaultComboBoxModel<>();
   private JComboBox<String> cardCombo = new JComboBox<>(comboModel);
   private Map<String, JComponent> componentMap = new HashMap<String, JComponent>();
   private String key = "";
   private SwappingImgPanel swappingImgPanel = new SwappingImgPanel(DELTA_TIME, ELAPSED_TIME);

   public DimmingPanelSwaps() {
      registerComponent(createComponentOne(), "one");
      registerComponent(createComponentTwo(), "two");      
      registerComponent(createComponentThree(), "three");
      registerComponent(createComponentFour(), "four");
      key = "one";
      cardHolderPanel.add(swappingImgPanel, SWAPPING_IMG_PANEL);

      JPanel southPanel = new JPanel();
      southPanel.add(cardCombo);

      setLayout(new BorderLayout());
      add(cardHolderPanel, BorderLayout.CENTER);
      add(southPanel, BorderLayout.SOUTH);

      swappingImgPanel.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if (pcEvt.getNewValue() == State.DONE) {
               cardlayout.show(cardHolderPanel, key);
               cardCombo.setEnabled(true);
            }
         }
      });

      cardCombo.addActionListener(new CardComboListener());
   }

   private JPanel createComponentFour() {
      int rows = 4;
      int cols = 4;
      int gap = 5;
      int tfColumns = 8;
      JPanel panel = new JPanel(new GridLayout(rows, cols, gap, gap));
      for (int i = 0; i < rows * cols; i++) {
         JTextField textField = new JTextField(tfColumns);
         JPanel tfPanel = new JPanel();
         tfPanel.add(textField);
         panel.add(tfPanel);
      }
      return panel;
   }

   private JLabel createComponentThree() {
      int biWidth = 200;
      BufferedImage img = new BufferedImage(biWidth, biWidth, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setPaint(new GradientPaint(0, 0, Color.red, 20, 20, Color.blue, true));
      g2.fillOval(0, 0, biWidth, biWidth);
      g2.dispose();
      Icon icon = new ImageIcon(img);
      JLabel label = new JLabel(icon);
      return label;
   }

   private JScrollPane createComponentTwo() {
      JTextArea textArea = new JTextArea(15, 40);
      JScrollPane scrollpane = new JScrollPane(textArea);
      scrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
      scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      return scrollpane;
   }

   private JPanel createComponentOne() {
      JPanel innerPanel = new JPanel(new GridLayout(1, 0, 5, 0));
      String[] btnTitles = {"One", "Two", "Three"};
      for (String btnTitle : btnTitles) {
         JButton btn = new JButton(btnTitle);
         innerPanel.add(btn);
      }
      JPanel panel = new JPanel(new GridBagLayout());
      panel.add(innerPanel);
      return panel;
   }

   @SuppressWarnings("hiding")
   private void registerComponent(JComponent jComp, String key) {
      cardHolderPanel.add(jComp, key);
      componentMap.put(key, jComp);
      comboModel.addElement(key);
   }

   private class CardComboListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         final String oldKey = key;
         key  = (String) cardCombo.getSelectedItem();
         cardCombo.setEnabled(false);

         final JComponent firstComp = componentMap.get(oldKey);
         final BufferedImage firstImg = extractComponentImg(firstComp);
         final JComponent secondComp = componentMap.get(key);
         final BufferedImage secondImg = extractComponentImg(secondComp);

         cardlayout.show(cardHolderPanel, SWAPPING_IMG_PANEL);
         swappingImgPanel.setFirstImg(firstImg);
         swappingImgPanel.setSecondImg(secondImg);
         swappingImgPanel.swap();

      }

      private BufferedImage extractComponentImg(final JComponent component) {
         Dimension size = component.getSize();
         BufferedImage img = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g2 = img.createGraphics();
         component.paint(g2);
         g2.dispose();
         return img;
      }
   }

   private static void createAndShowGui() {
      DimmingPanelSwaps mainPanel = new DimmingPanelSwaps();

      JFrame frame = new JFrame("Dimming Panel Swaps");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

/**
 * A JPanel that draws two images
 * When swap is called, the first image is shown
 * Then a Timer dims the first image while it reveals
 * the second image.
 * When the elapsed time is complete, it sets its state to State.DONE.
 * @author Pete
 *
 */
@SuppressWarnings("serial")
class SwappingImgPanel extends JPanel {
   public static final String STATE = "state";
   private BufferedImage firstImg;
   private BufferedImage secondImg;
   private int deltaTime;
   private int elapsedTime;
   // state is a "bound" property, one that is listened to via PropertyChangeSupport
   private State state = State.PENDING;
   private float alpha1;
   private float alpha2;

   public SwappingImgPanel(final int deltaTime, final int elapsedTime) {
      this.deltaTime = deltaTime;
      this.elapsedTime = elapsedTime;
   }

   public void swap() {
      setState(State.STARTED);
      if (firstImg == null || secondImg == null) {
         done();
      }
      alpha1 = 1.0f;
      alpha2 = 0.0f;
      new Timer(deltaTime, new ActionListener() {
         private int counter = 0;
         private int max = elapsedTime / deltaTime;

         @Override
         public void actionPerformed(ActionEvent e) {
            if (counter >= elapsedTime / deltaTime) {
               ((Timer)e.getSource()).stop();
               done();
               return;
            }
            // set new alpha composite values
            alpha1 = ((float)max - counter) / (float) max;
            alpha2 = (float) counter / (float) max;

            // make sure alphas are within bounds
            alpha1 = Math.min(1f, alpha1);
            alpha1 = Math.max(0f, alpha1);
            alpha2 = Math.min(1f, alpha2);
            alpha2 = Math.max(0f, alpha2);

            repaint();
            counter++;
         }
      }).start();

   }


   private void done() {
      firstImg = null;
      secondImg = null;
      setState(State.DONE);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (firstImg == null || secondImg == null) {
         return;
      }
      // create a new Graphics2D object with g.create()
      // to avoid any possible side effects from changing the 
      // composite of the JVM's Graphics object
      Graphics2D g2 = (Graphics2D) g.create();
      // set the first alpha composite, and draw the image
      g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha1));
      g2.drawImage(firstImg, 0, 0, this);
      // set the second alpha composite, and draw the image
      g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha2));
      g2.drawImage(secondImg, 0, 0, this);
      g2.dispose(); // can get rid of this Graphics because we created it
   }

   public void setFirstImg(BufferedImage firstImg) {
      this.firstImg = firstImg;
   }

   public void setSecondImg(BufferedImage secondImg) {
      this.secondImg = secondImg;
   }

   public State getState() {
      return state;
   }

   public void setState(State state) {
      State oldValue = this.state;
      State newValue = state; 
      this.state = state;
      firePropertyChange(STATE, oldValue, newValue);
   }
}

/**
 * Modeled on SwingWorker.StateValue
 * @author Pete
 *
 */
enum State {
   PENDING, STARTED, DONE
}