gpt4 book ai didi

java - 如何将对象添加到JFrames

转载 作者:行者123 更新时间:2023-11-29 07:14:36 25 4
gpt4 key购买 nike

我正在尝试在JFrame中制作游戏,但遇到了问题。我创建了一个对象,该对象由四张图像组成,并被串成一张。我的问题是,如何在JFrame中绘制此对象?

这是代码:

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.*;

public class t4
{
static boolean running;

public static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static double width = screenSize.getWidth();
public static double height = screenSize.getHeight();

public static int x = ( 250 );
public static int y = ( 150 );

public static final int sx = (int)width;
public static final int sy = (int)height;

public static void main( String[] args ) throws IOException, InterruptedException
{
Image ur = new ImageIcon("redBlock.gif").getImage();
Image ll = new ImageIcon("redBlock.gif").getImage();
Image ul = new ImageIcon("blueBlock.gif").getImage();
Image lr = new ImageIcon("blueBlock.gif").getImage();

// Create game window...
JFrame app = new JFrame();
app.setIgnoreRepaint( true );
app.setUndecorated( true );

// Add ESC listener to quit...
app.addKeyListener( new KeyAdapter()
{
public void keyPressed( KeyEvent e )
{
if( e.getKeyCode() == KeyEvent.VK_ESCAPE )
running = false;
if((e.getKeyCode()==KeyEvent.VK_LEFT)||(e.getKeyCode()==KeyEvent.VK_KP_LEFT))
x-=10;
if((e.getKeyCode()==KeyEvent.VK_RIGHT)||(e.getKeyCode()==KeyEvent.VK_KP_RIGHT))
x+=10;
if((e.getKeyCode()==KeyEvent.VK_UP)||(e.getKeyCode()==KeyEvent.VK_KP_UP))
y-=10;
if((e.getKeyCode()==KeyEvent.VK_DOWN)||(e.getKeyCode()==KeyEvent.VK_KP_DOWN))
y+=10;
}
});

// Get graphics configuration...
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();

// Change to full screen
gd.setFullScreenWindow( app );
if( gd.isDisplayChangeSupported() )
{
gd.setDisplayMode(new DisplayMode( sx, sy, 32, DisplayMode.REFRESH_RATE_UNKNOWN ));
}

// Create BackBuffer...
app.createBufferStrategy( 2 );
BufferStrategy buffer = app.getBufferStrategy();

// Create off-screen drawing surface
BufferedImage bi = gc.createCompatibleImage( sx, sy );

// Objects needed for rendering...
Graphics graphics = null;
Graphics2D g2d = null;
Color background = Color.BLACK;
Random rand = new Random();

// Variables for counting frames per seconds
int fps = 0;
int frames = 0;
long totalTime = 0;
long curTime = System.currentTimeMillis();
long lastTime = curTime;

running = true;
while( running )
{
try
{
// wait(500);

// count Frames per second...
lastTime = curTime;
curTime = System.currentTimeMillis();
totalTime += curTime - lastTime;
if( totalTime > 1000 )
{
totalTime -= 1000;
fps = frames;
frames = 0;
}
++frames;

// clear back buffer...
g2d = bi.createGraphics();
g2d.setColor( background );
g2d.fillRect( 0, 0, sx, sy );

// draw some rectangles...
/* int r = 45;
int g = 232;
int b = 163;
g2d.setColor( new Color(r,g,b) );
int w = ( 250 );
int h = ( 150 );
g2d.fillRect( x+25, y+25, w, h );*/

if(y<775)
{
y++;
}
else
{
y=0;
}

// display frames per second...
g2d.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
g2d.setColor( Color.GREEN );
g2d.drawString( String.format( "FPS: %s", fps ), 20, 20 );

// Blit image and flip...
graphics = buffer.getDrawGraphics();
graphics.drawImage( bi, 0, 0, null );

graphics.drawImage(ur,x,y,null);
graphics.drawImage(ll,x+50,y+50,null);
graphics.drawImage(ul,x,y+50,null);
graphics.drawImage(lr,x+50,y,null);

if( !buffer.contentsLost() )
buffer.show();

}
finally
{
// release resources
if( graphics != null )
graphics.dispose();
if( g2d != null )
g2d.dispose();
}
}

gd.setFullScreenWindow( null );
System.exit(0);
}

public static void wait(int x) throws InterruptedException
{
Thread.currentThread().sleep(x);
}
}


我想创建一个包含图像ur,ll,ul和lr的对象,并能够在屏幕上绘制它。

最佳答案

这是您应该做的:


修改类以使其扩展javax.swing.JComponent
覆盖paintComponent(Graphics)
创建一个javax.swing.Timer来管理帧速率。
覆盖getPreferredSize()


首先(按照DavidB的要求),我将向您解释为什么您应该执行这些操作,然后再向您展示如何进行。

说明


由于您尝试将组件添加到JFrame,因此需要组件的类与JFrame的add方法兼容(实际上,它属于Container,但这无关紧要)。如果您查看the JavaDoc documentation for add,您会发现它不会仅接受任何Object;相反,它需要Component(或其子类)的实例。您可以将Component而不是JComponent子类化,但是AWT应用程序中的Component比Swing应用程序更多。
简而言之:子类JComponent,以便JFrame.add将其接受为参数。
子类化JComponent后,您实际上需要告诉窗口管理器要绘制什么。您可以将绘图代码放在任何地方,但是请记住,除非有人实际调用该方法,否则不会调用(使用)该代码。图形环境调用以开始绘制过程的方法称为paintComponent *。如果重写此方法,则图形环境将调用您的自定义绘画代码。
简而言之:覆盖paintComponent,因为这是图形环境所关心的。
由于您最有可能在游戏中制作动画,因此您希望保持恒定的每秒帧数,对不对?如果不这样做,则有很多因素(计算机功率,其他应用程序正在运行,绘制复杂性等)可能会使帧速率陷入困境。为此,您需要每秒以指定次数(每帧一次)调用repaint方法。这是Swing计时器的重点。您给它一个代码块和一个毫秒数,并且每次经过指定的时间间隔后它将运行该代码。
简而言之:使用Swing计时器,以便可以保持帧速率恒定并受到控制。
假设您有一个文字处理应用程序。它的顶部是菜单栏,中间是文档窗口,底部是工具栏。显然,您希望菜单栏和工具栏较小,并且文档要占用尽可能多的空间,对吗?这就是为什么您需要让每个组件告诉您其大小应为多少(称为首选大小)的原因。覆盖getPreferredSize允许您返回所需的任意大小,从而控制组件的大小。**
简而言之:覆盖getPreferredSize,以便窗口管理器和图形环境正确设置所有大小。


*实际上不是paintComponent被调用;是paint。但是,paint方法调用paintComponentpaintBorderpaintChildren


  此方法实际上将绘画工作委托给三个受保护的对象
  方法:paintComponent,paintBorder和paintChildren。他们是
  以列出的顺序调用,以确保孩子出现在
  组件本身。一般而言,组件及其子组件
  不应在分配给边框的插图区域上绘画。
  子类可以像往常一样仅重写此方法。一个子类
  只是想要专门化UI(外观)代表的绘画
  方法应该只覆盖paintComponent。


(来源:the JavaDoc

**覆盖getPreferredSize并不能真正保证该尺寸是显示组件的尺寸。它仅指定显示它的大小。一些布局管理器将选择忽略此设置(例如BorderLayout)。但是,当您调用pack正确调整窗口大小时,它应根据该大小计算首选大小。

程序

扩展JComponent

要使类扩展JComponent,只需将类签名更改为此:

import javax.swing.JComponent;

public class MyGameDisplay extends JComponent {
...
}


覆盖 paintComponent

您需要导入 java.awt.Graphics类。请参阅以下示例代码以了解如何使用 paintComponent

import javax.swing.JComponent;
import java.awt.Graphics;

public class MyGameDisplay extends JComponent {
// Some code here

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // this line is crucial; see below
g.drawString(100,100,"Hello world");
}
}


注意:上面,我提到了从 super.paintComponent方法中调用 paintComponent的必要性。这样做的原因是,它将(除其他事项外)清除您先前显示的所有图形。因此,例如,如果您的程序绘制了一个在屏幕上移动的圆,则除非您调用 super.paintComponent,否则图形的每次迭代还将包含来自先前图形的圆轨迹。

使用 Timer

要获得所需的FPS速率,请修改该类以包含Swing计时器,如下所示:

// Include these imports:
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MyGameDisplay extends JComponent {
private Timer t;
public MyGameDisplay() {
ActionListener al = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
t = new Timer(1000 / 30 /* frame rate */, al);
t.start();
}
}


覆盖 getPreferredSize

覆盖 getPreferredSize的原因是,布局管理器将知道如何正确调整容器的大小。

虽然编写实际的逻辑来计算大小可能很困难,但实际上并不覆盖 getPreferredSize。这样做:

@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400); // for example
}




完成后,您可以运行以下代码:

import javax.swing.JFrame;

public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
MyGameDisplay mgd = new MyGameDisplay();
frame.add(mgd);
frame.pack();
frame.setVisible(true);
}
}

关于java - 如何将对象添加到JFrames,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10693520/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com