2016-07-25 32 views
0

我有一个自定义的JLayeredPane,我正在重绘它在我的游戏循环中。 JLayeredPane中添加了两个自定义JPanel。这些是前景和背景JPanels。我怎样才能成功地只绘制一次背景JPanel(当重新调整窗口大小或任何其他原因时重绘)以减少对系统资源的影响,同时不断更新我的前景JPanel。如何成功绘制背景JPanel一次并不断更新前景JPanel?

要重新迭代,我不想在一个循环中不断重绘背景JPanel。因为背景没有改变,所以我只想重新绘制它。并且很大。

在我尝试做到这一点时,我只画了一次背景。然而。后台JPanel根本不可见。而前台JPanel更新正常。它几乎就像前景JPanel在背景JPanel上绘制,即使我将两个JPanel设置为setOpaque(false)

我已经制作了一个mvce,它显示了我的尝试只绘制一次背景JPanel,同时更新前景JPanel不断。

我的代码的问题是背景JPanel不显示。

现在。我知道,如果我不断绘制它会显示。但是这打破了我想要做的事情的目的。我试图只绘制一次,并同时被看到

我的代码成功只绘制了背景JPanel一次。问题是后台JPanel不显示。如何解决这个问题

import javax.swing.*; 

import java.awt.*; 
import java.awt.event.*; 

public class Main extends JLayeredPane { 
    static JFrame frame; 
    static Main main; 
    static Dimension screenSize; 
    public Main() {  
     JPanel backPanel = new BackPanel(); 
     JPanel frontPanel = new FrontPanel(); 
     add(backPanel, new Integer(7)); 
     add(frontPanel, new Integer(8)); 

     new Thread(() -> { 
      while (true){ 
       repaint(); 
      } 
     }).start(); 

    } 

    public static void main(String[] args) { 
     screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 

     frame = new JFrame("Game"); // Just use the constructor 

     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     main = new Main(); 
     frame.add(main, BorderLayout.CENTER); 

     frame.pack(); 
     frame.setSize(screenSize); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 

    } 
    public class BackPanel extends JPanel{ 
     public boolean drawn = false; 
     public BackPanel(){ 
      setVisible(true); 
      setOpaque(false); 
      setSize(screenSize); 
      JLabel test1 = new JLabel("Test1"); 
      JLabel test2 = new JLabel("Test2"); 
      add(test1); 
      add(test2); 
     } 
     @Override 
     public void paintComponent(Graphics g){ 
      super.paintComponent(g); 
      drawOnce(g); 
     } 
     public void drawOnce(Graphics g){ 
      if (!drawn){ 
       g.setColor(Color.red); 
       g.fillRect(0, 0, screenSize.width, 200); 
       drawn=true; 
      } 

     } 
    } 
    public class FrontPanel extends JPanel{ 

     public FrontPanel(){ 
      setVisible(true); 
      setOpaque(false); 
      setSize(screenSize); 
      JLabel test = new JLabel("Test"); 
      add(test); 
     } 
     @Override 
     public void paintComponent(Graphics g){ 
      super.paintComponent(g); 
      g.setColor(Color.blue); 
      g.fillRect(0+screenSize.width/2, 0, screenSize.width/4, 300); 
     } 
    } 
} 
+0

'增加FPS'为什么你需要增加帧率?考虑使用javax.swing.Timer来更好地控制fps并以特定帧速率刷新(比如60fps - 换句话说增加fps不一定有利) – copeg

+0

@copeg在我的实际项目中,我尝试访问尽可能最高的FPS,并不断更新我的游戏,每秒钟60次。我已经重申了我的答案,即表示使用更少的系统资源,而不是增加FPS。 – Colourfit

+1

Swing绘画系统设计为在必要时重新绘制 - 如果您的绘画例程比较复杂并且您希望仅执行一次,请考虑第一次绘制到BufferedImage,然后将图像绘制到JPanel – copeg

回答

0

尝试RepaintManager.currentManager(组件).markCompletelyClean(组件)。它会阻止组件重新粉刷。您可能需要在每次添加新组件后执行此操作。

http://docs.oracle.com/javase/6/docs/api/javax/swing/RepaintManager.html#markCompletelyClean%28javax.swing.JComponent%29

+0

我为什么要防止组件重新粉刷?这将如何解决后面的JPanel只在绘制一次时不可见的问题,并且在正面JPanel后面,正在不断重新绘制 – Colourfit

+0

我已成功地将其停止重新绘制!那不是我的问题!我的问题是,如果我重新绘制一次,它就会显示出来。 – Colourfit

+0

你能解释你的答案吗? – Colourfit

0

我不知道的代码

super.paintComponent(g); 
drawOnce(g); 

这两条线是问题的根源,我诚恳不记得的paintComponent是如何工作的(测试可能有所帮助),但尝试交换它们:

drawOnce(g); 
super.paintComponent(g); 

也许,您的原始版本,你告诉JVM绘制整个组件,并只有在AWTEvent中已经添加到队列中,以DRA你需要什么。 我想awt的文档会解释它。