CardLayout显示两个面板,闪烁 [英] CardLayout showing two panels, flashing

查看:165
本文介绍了CardLayout显示两个面板,闪烁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to use CardLayout to show two JPanels, a main menu, and a controls screen. When I add two JPanels to my cards JPanel, it just shows two with flashing images. Here is my code:

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:

公共类MazeGamePanel扩展JPanel实现Runnable {

public class MazeGamePanel extends JPanel implements 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:

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) {
        }
    }
}

}

推荐答案

这是一个问题:

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

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

Don't use a java.util.Timer in a Swing program as you will have threading problems. Instead use a Swing Timer.

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

Also, you're making Swing calls in background threads and using Graphics object obtained by calling getGraphics() on a component, two no-nos for Swing programs.

EDIT

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

EDIT
Here is a program that I worked on that swaps components with a CardLayout, but fades one component out as it fades the other one in. What it does:


  • 该程序使用JPanel将所有交换组件添加到CardLayout。

  • 它还添加了一个SwappingImgPanel,一个用于绘制两个图像的JPanel ,淡出的组件之一,以及淡入的组件之一。

  • 当你交换组件,您创建两个组件的图像,当前可见的组件,以及下一个可见的组件。

  • 您将图像发送到SwappingImgPanel实例

  • 在SwappingImgPanel实例上调用 swap()

  • SwappingImgPanel将绘制两个图像但使用Swing Timer更改Graphic对象的复合值。这就是导致图像部分可见的原因。

  • 当SwappingImgPanel的Timer完成时,调用 done()方法将SwappingImgPanel的State设置为State.DONE。

  • 主GUI正在侦听SwappingImgPanel的状态值,当它实现State.DONE时,主GUI显示实际的下一个组件(而不是它的形象。)。

  • The program adds all the swapping components to the CardLayout using JPanel.
  • It also adds a single SwappingImgPanel, a JPanel created to draw two images, one of the component that is fading out, and one of the component that is fading in.
  • When you swap components, you create images of the two components, the one currently visible, and the one that will next be visible.
  • You send the images to the SwappingImgPanel instance
  • You call swap() on the SwappingImgPanel instance.
  • The SwappingImgPanel will then draw both images but uses a Swing Timer to change the Graphic object's composite value. This is what causes an image to be partially visible.
  • When the SwappingImgPanel's Timer is done, a done() method is called which sets the SwappingImgPanel's State to State.DONE.
  • The main GUI is listening to the SwappingImgPanel's state value, and when it achieves State.DONE, the main GUI shows the actual next component (and not an image of it).
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
}

这篇关于CardLayout显示两个面板,闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆