【问题标题】:JFrame not adding graphics from separate classJFrame没有从单独的类中添加图形
【发布时间】:2015-06-17 21:48:12
【问题描述】:

我对 Swing 很陌生,我遇到了一个问题,即我的 JFrame 中没有显示图形。我应该看到的是一个蓝色的矩形在框架中缓慢向下移动,后面是一个纯白色的背景。然而,当我运行我的主类时,我看到的只是一个普通的 JFrame。这是我的代码:

Execute

public class Execute {

public static void main (String[ ] args) {
    GUI gui = new GUI();
    gui.createFrame(800,600);

    ElevatorOne e1 = new ElevatorOne();
    e1.addElevatorOne();
}
}

ElevatorOne 类(应该在哪里初始化和添加图形)

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;

public class ElevatorOne extends GUI{

int y = 100;

public void addElevatorOne() {

    drawElevatorOne drawE1 = new drawElevatorOne();
    frame.getContentPane().add(drawE1);

    for(int i = 0; i < 130; i++) {
        y++;

        drawE1.repaint();

        try {
            Thread.sleep(50);
        } catch (Exception ex) { }
    }
}

@SuppressWarnings("serial")
class drawElevatorOne extends JPanel{
    public void paintComponent(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());

        g.setColor(Color.BLUE);
        g.drawRect(200,y,40,60);
    }
}

}

最后,我的GUI 类(创建frame 的地方) 导入 javax.swing.JFrame;

public class GUI {

JFrame frame = new JFrame();

public void createFrame(int x, int y) {
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    frame.setResizable(false);
    frame.setSize(x, y);
}

}

【问题讨论】:

  • 您的 addElevatorOne 可能会阻塞 EDT,这意味着我只会在短暂延迟后绘制最后一个位置。考虑使用 Swing Timer 来代替动画。您还违反了绘画链,这可能会导致绘画伪影和其他怪异现象,请确保在进行任何自定义绘画之前调用 super.paintComponent
  • 1) 添加组件(并调用pack)之前框架可见。 2) 使用基于 Swing 的 Timer 在 GUI 中制作动画。不要阻塞 EDT(事件调度线程)。发生这种情况时,GUI 将“冻结”。有关详细信息和修复,请参阅 Concurrency in Swing
  • 挥杆计时器中的@MadProgrammer,我会在每次重复时调用repaint() 方法吗?

标签: java swing


【解决方案1】:

虽然您得到了一个公认的答案,但我确实对该答案有异议,并且觉得有必要加两分钱:

  • 我认为你有一个 GUI 类然后让 Elevator1 扩展它是没有意义的。如果您希望 Elevator1 使用 JFrame,则让它创建一个 JFrame,因为您的继承确实不需要或受益。
  • 我自己,我会让 Elevator1 扩展 JPanel,然后让它在自己的 paintComponent 方法中绘制,这样就不需要 drawElevatorOne 内部类(应该命名为 DrawElevatorOne 以遵守 Java 命名约定)。
  • 您在 Swing GUI 中使用 Thread.sleep,这样做非常危险。这有效的唯一原因是因为它在主线程中被调用。如果您的代码已正确创建并设置为在 Swing 事件线程中启动和创建 GUI 组件,那么这将失败并且应该失败,因为它会使 Swing 事件线程进入睡眠状态。不要这样做,不要在有可能在 Swing 事件线程中被调用的方法中调用 Thread.sleep。
  • 改为使用 Swing Timer 来管理您的延迟。
  • 不要忘记(几乎)总是在您的 oeverride 中调用 super.paintComponent(g) 方法。不这样做会破坏 Swing 绘制链,并有很大的难以调试副作用的风险。

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class ElevatorTest {
   private static final int PREF_W = 800;
   private static final int PREF_H = 600;

   private static void createAndShowGui() {
      MyElevator mainPanel = new MyElevator(PREF_W, PREF_H);

      JFrame frame = new JFrame("Elevator Test");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      // start everything on the Swing event thread
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class MyElevator extends JPanel {
   private static final Color BACKGROUND = Color.white;
   private static final int ELEVATOR_X = 200;
   private static final int ELEVATOR_W = 40;
   private static final int ELEVATOR_H = 60;
   private static final int TIMER_DELAY = 50;
   public static final int MAX_ELEVATOR_Y = 130;
   private static final Color ELEVATOR_COLOR = Color.blue;
   private int prefW;
   private int prefH;
   private int elevatorY = 0;

   public MyElevator(int prefW, int prefH) {
      this.prefW = prefW;
      this.prefH = prefH;
      setBackground(BACKGROUND);

      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   @Override
   protected void paintComponent(Graphics g) {
      // Don't forget to call the super method
      super.paintComponent(g);

      g.setColor(ELEVATOR_COLOR);
      g.fillRect(ELEVATOR_X, elevatorY, ELEVATOR_W, ELEVATOR_H);
   }

   // to help size our GUI properly
   @Override
   public Dimension getPreferredSize() {
      Dimension superSz = super.getPreferredSize();
      if (isPreferredSizeSet()) {
         return superSz;
      }
      int w = Math.max(superSz.width, prefW);
      int h = Math.max(superSz.height, prefH);
      return new Dimension(w, h);
   }

   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         if (elevatorY >= MAX_ELEVATOR_Y) {
            // if elevator at max, stop thimer
            ((Timer) e.getSource()).stop();
         } else {
            // advance elevator and draw it
            elevatorY++;
            repaint();
         }
      }
   }
}

【讨论】:

    【解决方案2】:

    您的 ElevatorOne 类扩展了 GUI。因此,它继承了 GUI 的所有功能,但您可以同时创建它们。这可能是你打算做的:

    编辑:我运行了这段代码,确实有一个框在你指定的移动。

    public class Execute {
    
    public static void main (String[ ] args) {
        //    GUI gui = new GUI();
        //    gui.createFrame(800,600);
    
        ElevatorOne e1 = new ElevatorOne();
        e1.createFrame(800, 600);
        e1.addElevatorOne();
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-27
      • 2014-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多