【问题标题】:Ramshackle GUI, using Absolute Positioning Randomly Turns Images UpsidedownRamshackle GUI,使用绝对定位随机翻转图像
【发布时间】:2016-06-01 18:05:21
【问题描述】:

所以,首先我知道绝对定位对于 GUI 来说并不理想……但是,我必须构建 4 种不同类型的窗口和 1 个整体游戏窗口,所有这些都带有一个内置的运行器。我有一天半的时间来做这件事,而且在学生的日程安排上(尤其是一个没有编写 GUI 经验并且禁止使用 JOptionPane 的学生),我做得又快又乱。有了这个,问题就来了。

运行 GUI 时,一切都按计划进行。然而,在游戏运行大约 1/4 次时,随机图像会被颠倒过来。它并不总是相同的图像,也不会每次都出现。我让图像出现,但直接在 JFrame 上绘画(没有面板,是的,我知道它的编程很糟糕)。感谢您提供的任何输入,在网上真的找不到这样的东西。我发现的最佳建议是当同一张图像总是上下颠倒时,但事实并非如此。 代码:

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


public class game extends JFrame implements Runnable {

  private boolean running = false;
  private Image dbImage = null;
  private Dimension screenSize;
  private int width;
  private int height;
  private int screenIndex = 0;
  private BufferedImage img = null;
  private dialog d = new dialog();
  private boolean a = false;
  private Room1 room1 = new Room1();
  private Room2 room2 = new Room2();
  private Room3 room3 = new Room3();
  private Room4 room4 = new Room4();
  private Room5 room5 = new Room5();
  private Room6 room6 = new Room6();
  private Toilet toilet = new Toilet();
  private final boolean UNLOCK = true;

  public game()
  {
    super("Game");
    setExtendedState(JFrame.MAXIMIZED_BOTH);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();
    setVisible(true);
    setIconImage(new ImageIcon("pencil-icon.png").getImage());
    screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    width = (int)screenSize.getWidth();
    height = (int)screenSize.getHeight();

    (new Thread(this)).start();
  }

  public void update(Graphics g) {
    paint(g);
  }

  public void paint(Graphics g) {
    switch (screenIndex) {

      case 0:
        img = null;
        try {
          img = ImageIO.read(new File("map.png"));
        } catch (IOException e) {
        }
        break;
      case 1:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_6009.JPG"));
        } catch (IOException e) {
        }
        break;
      case 2:
        img = null;
        try{
          img = ImageIO.read(new File("IMG_6010.JPG"));
        }
        catch (IOException e) {}
        break;

      case 3:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_6011.jpg"));
        } catch (IOException e) {
        }
        break;
      case 4:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_6013.jpg"));
        } catch (IOException e) {
        }
        break;
      case 5:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_5994.jpg"));
        } catch (IOException e) {
        }
        break;

      case 6:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_5992.jpg"));
        } catch (IOException e) {
        }
        break;
      case 7:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_5991.jpg"));
        } catch (IOException e) {
        }
        break;
    }

    g.drawImage(img, 0, 0, width, height, null);
  }

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

  public void run() {
    running = true;

    while(running) {
      repaint();
      process();

      try {
        Thread.sleep(20);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public int isScreenIndex() {
    return screenIndex;
  }
//SI 1 and 2 are working
  public void setScreenIndex(int s) {
    this.screenIndex = s;
  }
  public void process() {
    if (screenIndex==0)
    {
      try{
        Thread.sleep(2000);
      }
      catch (Exception e){}
      int a = -1;
      a = d.map();
      while (a==-1){
        try {
        Thread.sleep(200);
        }
        catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      if (a==1 && ((room5.isDone() && !room1.isDone()) || UNLOCK)){
        setScreenIndex(1);
        return;
      }
      if (a==2 && (!room2.isDone() || UNLOCK)){
        setScreenIndex(2);
        return;
      }
      if (a==3 && (!room3.isDone() || UNLOCK)){
        setScreenIndex(3);
        return;
      }
      if (a == 4 && ((!room4.isDone() && room3.isDone())||UNLOCK)){
        setScreenIndex(4);
        return;
      }
      if (a == 5 && ((room4.isDone() && room6.isDone() && !room5.isDone())||UNLOCK)){
        setScreenIndex(5);
        return;
      }
      if (a == 6 && ((room2.isDone() && !room6.isDone())||UNLOCK)){
        setScreenIndex(6);
        return;
      }
      if (a == 7){
        d.showString("Progress",room1.getRoomName()  + "\t\t" + room1.getScore() + "\n" +
                     room2.getRoomName()  + "\t\t" + room2.getScore() + "\n" +
                     room3.getRoomName()  + "\t\t" + room3.getScore() + "\n" +
                     room4.getRoomName()  + "\t\t" + room4.getScore() + "\n" +
                     room5.getRoomName()  + "\t\t" + room5.getScore() + "\n" +
                     room6.getRoomName()  + "\t\t" + room6.getScore());
      }
      if (a == 8 && (!toilet.isDone() || UNLOCK)){
        setScreenIndex(7);
        return;
      }
    }
    if (screenIndex == 1){
      room1.play();
      setScreenIndex(0);
      return;
    }
    if (screenIndex == 2){
      room2.play();
      setScreenIndex(0);
      return;
    }
    if (screenIndex==3){
      //boolean a = false;
      room3.play();
      //while(!a){
      //  try {
      //    Thread.sleep(200);
      //  } catch(InterruptedException e) {
      //  }
      //}
      setScreenIndex(0);
      return;
    }
    if (screenIndex==4){
      room4.play();
      setScreenIndex(0);
      return;
    }
    if (screenIndex == 5){
      room5.play();
      setScreenIndex(0);
      return;
    }
    if (screenIndex == 6){
      room6.play();
      setScreenIndex(0);
      return;
    }
    if (screenIndex == 7){
      toilet.play();
      setScreenIndex(0);
      return;
    }
  }
}

【问题讨论】:

  • "I don't think it will be useful to post my code..." -- 认真的吗?我们应该猜猜为什么你的程序会出现奇怪的行为不端?请查收minimal reproducible example
  • 而且你有很多公认的糟糕编程正在进行。为什么不修复它,因为你知道它很糟糕?是的,您不应该直接在 JFrame 上绘图,所以不要这样做。
  • 好吧,我找到了一个失去声誉的好方法......我之所以这么说的主要原因是因为我正在调用几个文件,大约 9 个其他类,以及它的 200 行。我会立即发布。我知道我的编程很糟糕,但是除了这个错误之外,该项目正在运行,并且班上还有 14 名其他学生正在处理此代码。在这一点上,它的任何更改都只能是很小的,例如错误修复。
  • 发帖前,请再次阅读minimal reproducible example链接。您已经过早地发布了您的问题 - 在尝试隔离问题之前,而且在尝试重新编写代码之前,它也不会使用不良做法。如果您只使用良好的做法,那么这个错误很有可能会消失。
  • 添加了代码。抱歉,我知道这些要求,但由于上述原因,我真的认为这不会有帮助。

标签: java image swing user-interface position


【解决方案1】:

您在这里覆盖了 JFrame 的绘制方法:

  public void paint(Graphics g) {
    switch (screenIndex) {

      case 0:
        img = null;
        try {
          img = ImageIO.read(new File("map.png"));
        } catch (IOException e) {
        }
        break;
      case 1:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_6009.JPG"));
        } catch (IOException e) {
        }
        break;
      case 2:
        img = null;
        try{
          img = ImageIO.read(new File("IMG_6010.JPG"));
        }
        catch (IOException e) {}
        break;

      case 3:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_6011.jpg"));
        } catch (IOException e) {
        }
        break;
      case 4:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_6013.jpg"));
        } catch (IOException e) {
        }
        break;
      case 5:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_5994.jpg"));
        } catch (IOException e) {
        }
        break;

      case 6:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_5992.jpg"));
        } catch (IOException e) {
        }
        break;
      case 7:
        img = null;
        try {
          img = ImageIO.read(new File("IMG_5991.jpg"));
        } catch (IOException e) {
        }
        break;
    }

    g.drawImage(img, 0, 0, width, height, null);
  }

在里面做了几件坏事:

  • 您不应该在 JFrame 中绘画,因为您可能会弄乱整个应用程序的绘画,包括子组件、边框、玻璃窗格、内容窗格等...
  • 你永远不会调用 super paint 方法——这可能是你最大的错误
  • 您实际上是在此方法中读取文件,使其缓慢爬行。永远不要从绘画中进行文件 I/O。
  • catch (IOException e) {} 忽略了例外情况,这是一种非常危险的做法,代码相当于闭着眼睛开车。

建议:

  • 首先,最重要的是按照教程告诉您的操作,我们已经告诉无数来到这里的人:不要在顶级窗口内绘图。在 JPanel 的 paintComponent 方法中绘图。
  • 请调用超级绘画方法。
  • 一次读取图像,例如在构造函数中,将图像存储到变量中,并且永远不要读取它们或在绘画方法中执行文件 i/o。
  • 至少在您的 catch 块中打印异常的堆栈跟踪。

其他问题:

  • 您的代码在 while 循环中进行了大量轮询,这表明您希望将程序更改为更加“事件驱动”。
  • 您的代码看起来除了轮询其他类的状态之外什么都不做,并根据这些结果更改显示的图像。如果是这样,那么更好的是:
    • 摆脱轮询,改为使用观察者模式来通知图像显示类更改其图像。这可以使用 PropertyChangeListener 或简单的 ChangeListener 来完成。
    • 在程序启动时再次读取所有图像,并将它们存储到变量中。 Image 的 ArrayList 或者更好的 ArrayList<Icon> 可以很好地解决这个问题。
    • 在 JLabel 中将图像显示为 ImageIcon
    • 当状态发生变化时,只需使用 JLabel 的 setIcon(...) 方法交换图像即可。这将使您的程序更加简单和防弹。

类似于...的东西

import java.awt.BorderLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

// this is a JPanel and can be displayed in a JFrame
// a JDialog, or in another JPanel
public class GamePanel extends JPanel {
    public static final String[] IMG_PATHS = {
            "map.png",
            "IMG_6009.JPG",
            "IMG_6010.JPG",
            "IMG_6011.JPG",
            "IMG_6013.JPG",
            "IMG_5994.JPG",
            "IMG_5992.JPG",
            "IMG_5991.JPG"
    };
    private JLabel imageLabel = new JLabel();
    private List<Icon> icons = new ArrayList<>();
    private int iconIndex = 0;

    public GamePanel() {
        try {
            // read in the images once and only
            // once
            for (String imagePath : IMG_PATHS) {                
                // actually better to use resources
                // instead of Files here
                File file = new File(imagePath);
                BufferedImage img = ImageIO.read(file);
                Icon icon = new ImageIcon(img);
                icons.add(icon);
            }
        } catch (IOException e) {
            // never ignore the exceptions
            e.printStackTrace();
        }
        imageLabel.setIcon(icons.get(iconIndex));

        setLayout(new BorderLayout());
        add(imageLabel, BorderLayout.CENTER);
    }

    // let outside classes easily change what image is displayed
    public void viewImage(int iconIndex) {
        if (iconIndex < 0 || iconIndex >= icons.size()) {
            throw new IllegalArgumentException("iconIndex: " + iconIndex);
        } else {
            this.iconIndex = iconIndex;
            imageLabel.setIcon(icons.get(iconIndex));
        }
    }
}

【讨论】:

  • 但是,这些是否会导致上述错误?我知道这是不好的做法,但正如我之前所说,除了那个问题之外它都有效。我不担心在 Paint 方法中读取文件,因为它实际上很少运行。仅在搬到新房间时。超级 Paint 方法是一个我没有注意到的错误......并且在 JFrame 中绘画很好,因为我从未向 JFrame 添加任何组件,一切都是通过弹出窗口通过一个单独的类对话框完成的,我稍后编写了该对话框并且正在工作很好。
  • @R.Thom:如果没有您发布我们可以运行的minimal reproducible example,我们无法知道,而不是在链接中。
  • 我不知道是什么导致了这个问题,但这是当前的问题。如果我能确定是什么原因造成的,我会修复它。我能想到的创建一个最小的、完整的和可验证的示例的唯一方法是,如果我要给你我正在使用的所有图像的副本,并从游戏中删除每一行代码,然后为你写一个方法从图像到图像的过渡。如果这就是您回答问题所需要的一切,那么这本身就是一个小时的工作,甚至可能不会重现问题,我不知道原因。
  • @R.Thom:这就是为什么创建 MCVE 可以帮助您发现问题。你删掉代码直到你找出问题,完成。
  • @R.Thom 正如 Hovercraft 指出的那样,您可能会因不当使用油漆系统而获得油漆工件
猜你喜欢
  • 1970-01-01
  • 2021-01-18
  • 2014-06-19
  • 2012-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多