Java 如何通过从主类获取变量并将其用作标题来影响另一个类中的JFrame?

Java 如何通过从主类获取变量并将其用作标题来影响另一个类中的JFrame?,java,swing,Java,Swing,标题很可能让人困惑,但让我详细说明一下 我正在制作一个电子游戏。我已经到处寻找这个问题的答案,但似乎我找不到任何与我的代码相关的东西。我有两个类:一个用于main方法,另一个用于JFrame: RunGame.java: package net.naprav.wardungeon; import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import

标题很可能让人困惑,但让我详细说明一下

我正在制作一个电子游戏。我已经到处寻找这个问题的答案,但似乎我找不到任何与我的代码相关的东西。我有两个类:一个用于main方法,另一个用于JFrame:

RunGame.java:

package net.naprav.wardungeon;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

public class RunGame extends Canvas implements Runnable {
private static final long serialVersionUID = 1203994186653691379L;

private static final int WIDTH = WindowFrame.WIDTH;
private static final int HEIGHT = WindowFrame.HEIGHT;
private static final Dimension size = WindowFrame.size;

private Thread thread;
public boolean isRunning = false;

public static int FPS = 0; //Frames per second.
public static int TPS = 0; //Ticks per second. (Updates per second)

public static String frames;
public static String updates;

private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] allPixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

//static Key key;
RenderSystem system;

/**
 * Added the main constructor.
 */ 
public RunGame() {
    this.setVisible(true);
    this.setSize(size);
    this.setPreferredSize(size);
    this.setMinimumSize(size);
    this.setMinimumSize(size);

    system = new RenderSystem(WIDTH, HEIGHT);
}

/**
 * Responsible for the logic behind the game.
 */
public void tick() {

}

/*
 * Responsible for the actual rendering behind the game.
 */
public void render() {
    BufferStrategy buffer = this.getBufferStrategy();

    //Clearing the screen to make room for the pixels! :D
    system.clearScreen();
    //Rendering the pixels in the RenderMechanism class.
    system.changePixels();
    for (int counter = 0; counter < allPixels.length; counter++) {
        //Setting the pixels in this class to the ones in RenderMechanism.java.
        allPixels[counter] = system.allPixels[counter];
    }

    //Buffer is automatically null, so we can create one to render a number of buffers. (3)
    if (buffer == null) {
        this.createBufferStrategy(3);
        return;
    }

    //Graphics setup.
    Graphics gfx = buffer.getDrawGraphics();
    gfx.setColor(new Color(146, 17, 189));
    gfx.fillRect(0, 0, this.getWidth(), this.getHeight());
    //Draw stuffs between here...
    gfx.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), null);
    //and here.
    gfx.dispose();
    buffer.show();
}

/**
 * Used to start the thread and make it go! :D
 */
public synchronized void begin() {
    thread = new Thread(this);
    thread.start();
    isRunning = true;
}

/**
 * Used to end the thread and make it stop! :/
 */
public synchronized void finish() {
    if (isRunning == true) {
        isRunning = false;
        try {
            thread.join();
        } catch (InterruptedException exc) {
            System.out.println("Couldn't join thread! :(");
            exc.printStackTrace();
        }
    }
}   


/**
 * The run method is used to run the game itself in the thread.
 */
public void run() {
    long previousTime = System.nanoTime();
    long secondTimer = System.currentTimeMillis();

    final double nanoSeconds = 1000000000.0 / 60.0;
    double omega = 0;

    while (isRunning == true) {
        long currentTime = System.nanoTime();
        omega += (currentTime - previousTime) / nanoSeconds;
        previousTime = currentTime;

        while (omega >= 1) {
            this.tick();
            TPS++;
            omega--;
        }

        this.render();
        FPS++;

        if ((System.currentTimeMillis() - secondTimer) > 1000) {
            secondTimer += 1000;
            //Un-comment out below code for console output of frames and updates.
            frames = String.valueOf(FPS);
            updates = String.valueOf(TPS);
            System.out.println(frames + ", " + updates);
            FPS = 0;
            TPS = 0;
        }
    }
    this.finish();
}

/**
 * The Main method.
 * @param args
 */
public static void main(String[] args) {
    WindowFrame window = new WindowFrame("WarDungeon", FPS, TPS);
    //Get rid of '//' below to test the login screen!
    //LoginScreen login = new LoginScreen("WarDungeon Login");
}
}
我知道这是很多代码,我道歉。我仍然是Java编码的新手,但如果你能帮我,那就太好了。我的主要问题是我不能让FPS和TPS显示在标题栏上。我不知道如何在不影响帧和更新的“每秒”的情况下更改该变量


提前感谢。

简短回答:您需要定期从
run()
方法调用JFrame上的
.setTitle(…)
(可能是代替您的
System.out.println
)。这是保持标题栏最新的唯一方法


仅从代码的粗略概述来看,您似乎需要进行一些重构,因为RunGame类中没有对JFrame的引用。与其让JFrame成为包含RunGame实例的“主机”,不如将其反转,让RunGame控制JFrame。

可能有几种方法可以做到这一点

基本过程是

  • 查找父窗口/框架
  • 解析当前标题
  • 创建新标题
  • 更新窗口标题
例如

while (isRunning == true) {
    /*...*/

    if ((System.currentTimeMillis() - secondTimer) > 1000) {
        frames = String.valueOf(FPS);
        updates = String.valueOf(TPS);
        /*...*/
        Window parent = SwingUtilities.windowForComponent(this);
        if (parent instanceof Frame) {
            Frame frame = (Frame)parent;
            String title = frame.getTitle();
            String title = value.substring(0, value.indexOf("|")).trim();
            title = title + " | " + "FPS: " + frame + ", UPS: " + update;
            frame.setTitle(title);
        }
    }
}
public interface GameContainer {
    public String getTitle();
    public void setTitle();
}
这种方法的问题是,它突然将
RunGame
Frame
紧密结合起来

虽然这看起来并不是什么大问题,但如果您想重用组件或以其他方式部署它,它可能会破坏应用程序

更好的解决方案是定义一个
接口
,该接口具有某种
RunGame
可以调用的方法(例如
get/setTitle

例如

while (isRunning == true) {
    /*...*/

    if ((System.currentTimeMillis() - secondTimer) > 1000) {
        frames = String.valueOf(FPS);
        updates = String.valueOf(TPS);
        /*...*/
        Window parent = SwingUtilities.windowForComponent(this);
        if (parent instanceof Frame) {
            Frame frame = (Frame)parent;
            String title = frame.getTitle();
            String title = value.substring(0, value.indexOf("|")).trim();
            title = title + " | " + "FPS: " + frame + ", UPS: " + update;
            frame.setTitle(title);
        }
    }
}
public interface GameContainer {
    public String getTitle();
    public void setTitle();
}
然后,
WindowFrame
就可以实现这个接口了

public class WindowFrame extends JFrame implements GameContainer {...}
RunGame
则需要一个实例

public class RunGame extends Canvas implements Runnable {
    /*...*/
    private GameContainer gameContainer;
    public RunGame(GameContainer gameContainer) {
        this.gameContainer = gameContainer;
然后您将使用此实例进行更改

    if ((System.currentTimeMillis() - secondTimer) > 1000) {
        frames = String.valueOf(FPS);
        updates = String.valueOf(TPS);
        /*...*/
        if (gameContainer != null) {
            String title = gameContainer.getTitle();
            String title = value.substring(0, value.indexOf("|")).trim();
            title = title + " | " + "FPS: " + frame + ", UPS: " + update;
            frame.setTitle(title);
        }
    }
最后,当您创建游戏时,您只需将
GameContainer
的引用传递给它

game = new RunGame(this);

现在,您可以自由地定义
GameContainer
,这是您认为合适的…

IHMO-
RunGame
应该尽可能少地了解它的运行环境,因为它使它更加灵活,并为部署选择提供了更多机会…这是一个很好的观点@MadProgrammer。然而,我认为某个地方的人需要(a)访问RunGame中包含的FPS信息,(b)访问它正在运行的JFrame,以及(c)连接到RunGame中的run循环。此外,RunGame(我想?)将成为一个单身汉,其生活的全部目的就是管理JFrame。对于这样的小型应用程序,在RunGame中使用优雅并具有该功能似乎是合理的,而不是在代码中添加额外的接口和委托类。不过,这只是一个意见!我并不反对你的观点,但我可能会说,这是一个很好的学习机会,可以在任何可能的地方尝试使用好的实践。这是第二十二条军规,我花了更多的时间在我自己的个人代码中翻阅它…;)-依我拙见