【问题标题】:Java Background gaps between frame and image框架和图像之间的Java背景间隙
【发布时间】:2013-12-23 18:51:18
【问题描述】:

通过各种布局/空值和其他方法进行过渡很有趣,试图让我的背景图像完美地适合我的框架,而不会出现迄今为止我无法清除的恼人间隙。每一次尝试都导致了更大的差距。如果布局设置为左侧,图像不可避免地会填充左侧的空白,但会扩大右侧的空白,最后一次尝试通过将图像添加到框架直接完美填充它,但导致屏幕上的其他元素不再接收重绘调用

目前我的游戏设置了一个 jframe,创建了扩展 JPanel 的游戏系统类,并且游戏系统类创建了处理开始屏幕或实际游戏屏幕元素的内部类。在系统创建的游戏容器类内部是绘制背景的地方。

缩短的代码提取

主类:

    public class Test extends JPanel {

////////////////
////Variables //
////////////////////////////
/**/private static Test test;
/**/private static JFrame stage;
/**/private static Container CurrentMenu;
/**/private boolean isRunning = true; //used to state whether game is running
////////////////////////////////////

////////////////
// initialize //
////////////////
/**/public static void main(String[] args) {
/**/stage = new JFrame("Touhou FBE");//creates game window
/**/stage.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//sets up default handler for closing window
/**/test = new Test();//creates an object of our game
/**/stage.getContentPane().add(test);//add game object to frame 
/**/stage.pack();
/**/stage.setVisible(true);//sets frame to visible
/**/stage.setResizable(false);
/**/test.Game_loop();
/**/}
////////////////////////////

/////////////////
// constructor //
/////////////////
/**/public Test(){
/**////////////////////////////////
/**/// create starting game menu //
/**////////////////////////////////          //////////////////
/**/CurrentMenu = new Container(this,stage);     // swap GameMenu with GameContainer to be able to see difference with painting
/**/this.add(CurrentMenu);                   //////////////////
/**/}
///////////////////////


    ////////////////////////////////////////////
    // Game loop which manages object updates //
    ////////////////////////////////////////////
    /**/public void Game_loop(){
    /**/while (isRunning) {
    /**/test.repaint();
    /**/}
    /**/}
    /////////////////////////////////////////////////

    /////////////////////////////////
    // Rendering canvas for images //
    /////////////////////////////////
    /**/public void paint(Graphics g) {
    /**/super.paint(g); //Refresh Panel
    /**/}
    /////////////////////////////////////////////////////// 

容器类:

    //////////////////////////
// game container class //
//////////////////////////
/**/public class Container extends JPanel{
/**/    
///////////////
//Variables //
///////////////
/**/public Test Game; 
/**/public JFrame stage; 
/**/private Image img;  

////////////////
//Constructor //
////////////////
/**/public Container(Test game, JFrame Stage){
/**/Game = game;
/**/stage = Stage;  
/**/img = (new ImageIcon("resources/background.png").getImage());
/**/Dimension size = new Dimension(700, 400);
/**/setPreferredSize(size);
/**/setMinimumSize(size);
/**/setMaximumSize(size);
/**/setLayout(null);
/**/setSize(size);
/**/}
/**/    
////////////////////////////

//////////////////
//Paint sprite //
//////////////////
/**/public void paintComponent(Graphics g) {
/**///super.paint(g);
/**/g.drawImage(img, 0,0, this);
/**/}
////////////////////////////////////
}

程序和示例中使用的图像(重命名为背景) http://img716.imageshack.us/img716/6410/seq6.png

目前我已经达到了如果必须的话,我会留下空白,因为它不会影响整个游戏,但是它让我非常烦恼,并且每次尝试交换布局,删除 hgap/ vgap,强制图像的位置或遵循教程导致没有真正的变化。非常感谢您的帮助,并将帮助确保我再也不会遇到这样的问题。

【问题讨论】:

  • 1) 为了尽快获得更好的帮助,请发帖 SSCCE。 2) 例如,获取图像的一种方法是热链接到this answer 中看到的图像。
  • 我喜欢你用 //// 和 /**/ 组织代码的方式
  • 我认为这两个类组成了一个 SSCCE,因为它实际上是受影响代码的基本框架,但仍然需要学习如何制作更有效的 SSCCE。我也想用图像,如果我链接原始背景图像是你所要求的,这会有所帮助。
  • 我还没有通读你的代码,所以我可能在这里不太关键......你不能只是pack()你的JFrame吗?
  • 在代码中,我使用 stage 作为对 JFrame 的引用,我使用了 pack() 方法,但是这些差距仍然是后记,我在另一篇文章中读到的一件事是那个包() 显然留下 5px 间隙/边框作为默认值?不完全确定这是否是问题所在。

标签: java swing paintcomponent repaint


【解决方案1】:

调用setResizable 会改变框架的大小。

请尝试先调用setResizable,然后再调用packsetVisible

例如...

更新

持续的“填充”是由于Test 扩展自JPanel 并添加了Container 造成的。

JPanel 的默认布局管理器是 FlowLayout,默认情况下,它会在容器周围添加 5 个像素。

根据您的需要,我会将Test 的布局管理器更改为BorderLayout,或者直接将Container 添加到框架中(默认情况下使用BorderLayout

例如...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestResize {

    private JFrame stage;
    private Container CurrentMenu;
    private boolean isRunning = true; //used to state whether game is running

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestResize();
            }
        });
    }

    public TestResize() {
        CurrentMenu = new Container(this, stage);     // swap GameMenu with GameContainer to be able to see difference with painting
        stage = new JFrame("Touhou FBE");//creates game window
        stage.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//sets up default handler for closing window
        stage.add(CurrentMenu);
        stage.setResizable(false);
        stage.pack();
        stage.setVisible(true);//sets frame to visible
        // This needs to be started in a separate thread
//        test.Game_loop();
    }

    public void Game_loop() {
//        while (isRunning) {
//            test.repaint();
//        }
    }

    public class Container extends JPanel {

        public TestResize Game;
        public JFrame stage;
        private Image img;

        public Container(TestResize game, JFrame Stage) {
            Game = game;
            stage = Stage;
            img = (new ImageIcon("resources/background.png").getImage());
        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = img == null ? new Dimension(700, 400) : new Dimension(img.getWidth(this), img.getHeight(this));
            return size;
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(img, 0, 0, this);
            g.setColor(Color.RED);
            g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);            
        }
    }
}

【讨论】:

  • +1,你似乎是对的。至少在我测试不同应用程序的情况下
  • 正如您在上面和这个问题中提到的,通过更改 setResizable 方法的顺序,现在填充了左/右和底部间隙,但是上面的 4-5px 间隙仍然存在。我通过使用 getter 发现了一件事,实际上图像是在 (0,0) 处绘制的,所以无论出于何种原因,JFrame 上的实际类被分流了 5px,这与布局有关吗?
  • 您缺少一部分代码(测试),因此无法确定。可能是有一个边框或测试的首选尺寸大于图像。我不知道您为什么要覆盖绘画,因为它什么也没做,您应该调用 super.paintComponent 以确保在绘画之前正确准备图形上下文...
  • 在影响框架的情况下,此测试代码与我的实际项目之间的唯一区别是我忘记了我曾调用 Dimension getPreferredSize() 将其尺寸设置为 700,400 相同的大小如图。除此之外我没有设置边框,除非有默认,取消注释 super.paint 组件,最初它在轻微重叠的情况下绘制图像两次,现在它没有。
  • 刚刚尝试在 (0,0) 处的测试类中绘制一个简单的正方形,在左上角正确绘制,所以无论出于何种原因,当容器类添加到JFrame,它被向下移动了 5px,因此当背景图像在 (0,0) 处绘制时,它实际上是在 (0,5) 处绘制的