【问题标题】:JFrame adding 22 pixel offset (java.awt.Insets) to top of the FrameJFrame 将 22 像素偏移量 (java.awt.Insets) 添加到 Frame 顶部
【发布时间】:2015-01-24 12:17:47
【问题描述】:

我正在创建一个简单的 Break Out 风格的游戏。主游戏扩展了 JFrame,我在框架中添加了一个 JPanel。

当我使用paint() 绘制游戏图形时,项目按预期位于窗口内(即通过它们的x、y 坐标)。

我更新了代码以使用 BufferStrategy,因为我正在闪烁。从那以后,渲染的图形偏移了 22px。

这意味着砖块不在屏幕顶部!

代码如下:

package BreakOut;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;


public class Game extends JPanel implements KeyListener{

GameStateManager gsm = new GameStateManager();
BufferStrategy strategy;

public Game() {

    //add menu state to GameStateManager
    gsm.add(new MenuState(gsm));
    createFrame();


    while(true)
    {
        gsm.update();
        //repaint();
        render();
        try{
            Thread.sleep(10);
        }
        catch(InterruptedException e)
        {

        }
    }
}


public void createFrame()
{
    JFrame frame = new JFrame("Mini Tennis");
    frame.setLayout(new BorderLayout());
    this.setPreferredSize(new Dimension(400,400));
    frame.add(this);        
    frame.pack();       
    frame.setBackground(Color.BLACK);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    addKeyListener(this);
    this.setFocusable(true);
    frame.createBufferStrategy(2);
    strategy = frame.getBufferStrategy();
    frame.setVisible(true);
    System.out.println(frame.getInsets());
}


public void render()
{
    Graphics g = strategy.getDrawGraphics();
    super.paint(g);
    gsm.render(g);
    g.dispose();
    strategy.show();
}


public void keyPressed(KeyEvent k) {
    switch(gsm.getState())
    {
        case MAIN_MENU:
        if(k.getKeyCode()==KeyEvent.VK_ENTER)
        {
            //add the PlayState to the Stack and update enum value
            gsm.add(new PlayState(gsm, this));
        }
        break;
        case PLAYING:
            if(k.getKeyCode()==KeyEvent.VK_P)
            {
                //add the PlayState to the Stack and update enum value
                gsm.add(new PauseState(gsm));
            }
            break;
        case PAUSE:
            if(k.getKeyCode()==KeyEvent.VK_P)
            {                   
                gsm.pop();
            }
            break;
        case GAME_OVER:
            if(k.getKeyCode()==KeyEvent.VK_ENTER)
            {                   
                gsm.pop();
            }
            break;
    }
    //send input to GameStateManager
    gsm.keyPressed(k.getKeyCode()); 
}

public void keyReleased(KeyEvent k) {
    gsm.keyReleased(k.getKeyCode());        
}

public void keyTyped(KeyEvent k) {
    gsm.keyTyped(k.getKeyCode());   
}


public static void main(String[] args) {
    new Game();

}

}

当我输出 System.out.println(frame.getInsets());我明白了

java.awt.Insets[top=22,left=0,bottom=0,right=0]

我显然做错了什么,但无法弄清楚为什么添加 BufferStrategy 会创建 JPanel 偏移 22px

任何帮助将不胜感激:)

【问题讨论】:

    标签: java swing jframe jpanel awt


    【解决方案1】:

    框架有边框和装饰,它们包含在框架的边界内(它们不会被添加到外部),从您使用 MacOS 的外观来看,顶部的 22 像素是窗口标题.

    最好的解决方案是,不要使用框架作为渲染表面,而是使用Game 类。这意味着它需要从java.awt.Canvas 扩展而不是javax.swing.JPanel,并且您需要从中创建BufferStrategy

    如果你重写CanvasgetPreferredSize方法,你可以在框架上使用pack,它会围绕这个打包窗口,所以物理框架会比内容大,但内容会你喜欢的尺寸

    您还需要将主/游戏循环移动到单独的线程,因为这是当前存在阻塞事件调度线程的风险,这可能会导致您无法解决问题(例如永远不会收到关键事件)

    【讨论】:

    • 太好了,谢谢 :) 线程是我列表中的下一件事。使用线程进行游戏循环的最佳方法是什么?我会实现 Runnable 吗??
    • 通常,是的,通常建议使用Runnable 并将其传递给Thread 的实例(通过它的构造函数)。请记住,Swing 不是线程安全的,但由于您使用的是 BufferStrategy,这应该不是问题,因为 BufferStrategy 和 Swing 组件不能很好地协同工作
    • 再次感谢 :) 那么,对于一个游戏,您一般会使用 Canvas 来渲染游戏图形吗?像 libgdx 这样的游戏库会拥有自己的创建窗口和绘制到屏幕的方法,还是会使用 Swing 和 AWT??
    • 游戏套件可能会依赖 CanvasBufferStrategy 或提供自己的本地对等体,根据那里的实现将其附加到 Canvas
    猜你喜欢
    • 2014-10-03
    • 1970-01-01
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    相关资源
    最近更新 更多