【问题标题】:Why is JFrame not adding a component properly为什么 JFrame 没有正确添加组件
【发布时间】:2015-07-05 21:50:51
【问题描述】:

尝试将组件添加到 JFrame 时出现错误。

这是第一堂课:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class FrameG extends JFrame
{

private static final String MOVE_UP = "move up";
public static int frameID = 1;
private static JFrame window = new JFrame();
private static openWin frame = new frame01();
public static void main(String[] args) {
    window.setSize(1500,900);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setVisible(true);
    window.setResizable(true);
    frame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), MOVE_UP);
    frame.getActionMap().put(MOVE_UP, new movement());
    mainloop();
}
private static void mainloop()
{
    window.removeAll();
    switch(frameID)
    {
        case 1:
            frame = new frame01();
            frame.setLayout(new FlowLayout());
            System.out.println(frame);
            window.add(frame);
            break;
        default:
            break;
    }
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ex) {
        Logger.getLogger(FrameG.class.getName()).log(Level.SEVERE, null, ex);
    }
    mainloop();
}
}
class movement extends AbstractAction
{
@Override
public void actionPerformed(ActionEvent e) {
    System.out.println("hi");
}
}

和第二个类(它扩展了一个具有扩展 JComponent 的抽象绘制方法的类):

import java.awt.Graphics;
import java.awt.*;
import javax.swing.JComponent;
import java.awt.geom.*;
public class frame01 extends openWin{
@Override
public void paint(Graphics g) {
    Graphics2D pic = (Graphics2D) g;
    pic.setBackground(Color.BLACK);
}
}

错误可能是无效部分,但我不确定它是什么:

frameg.frame01[,0,0,0x0,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=0,maximumSize=,minimumSize=,preferredSize=]

【问题讨论】:

  • private static openWin frame = new frame01(); 看起来很可疑。请在该行上展开。
  • 你的 mainLoop 方法会导致 StackOverflowException;您不应该从 EDT 外部更新 ui;在进行任何自定义绘画之前,您应该覆盖 paintComponent 而不是绘画并调用 super.paintComponent;根据您的代码,我不确定您如何知道 mainLoop 的一个周期与另一个周期之间的任何区别;而且你的 frame01 实际上并没有画任何东西,所以无论如何它可能看起来与框架的默认内容相同

标签: java swing jframe jcomponent


【解决方案1】:

您的代码明显缺乏对 Swing 工作原理的理解

这...

private static void mainloop()
{
    window.removeAll();
    switch(frameID)
    {
        case 1:
            frame = new frame01();
            frame.setLayout(new FlowLayout());
            System.out.println(frame);
            window.add(frame);
            break;
        default:
            break;
    }
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ex) {
        Logger.getLogger(FrameG.class.getName()).log(Level.SEVERE, null, ex);
    }
    mainloop();
}

这是一个坏主意,有两个原因,第一个是它最终会生成一个StackOverflowException,第二个是它违反了Swing的单线程规则。

通常,while-loop 通常会更好,但是当您处理基于 Swing 的组件时,您应该考虑使用 Swing TimerSwingWorker,具体取决于您希望实现的目标。

不断添加和删除组件似乎也是一个奇怪的想法,但这个问题没有上下文来知道您希望实现什么。话虽如此,作为一般规则,如果您想在视图之间切换,CardLayout 通常被认为是首选解决方案

这...

public class frame01 extends openWin{
    @Override
    public void paint(Graphics g) {
        Graphics2D pic = (Graphics2D) g;
        pic.setBackground(Color.BLACK);
    }
}

只是什么都不做,除了破坏油漆链,这可能会导致产生无穷无尽的奇怪油漆制品。如果临时更改 Graphics 上下文的背景颜色,您的所有代码都会执行此操作,但由于您不使用它绘制任何内容,因此它实际上毫无意义

作为一般规则,建议覆盖 Swing 组件的 paintComponent 方法(并在进行任何自定义绘制之前调用 super.paintComponent)。

我强烈建议您看看:

【讨论】:

    【解决方案2】:

    您的代码有很多问题。正如我在评论中所说,private static openWin frame = new frame01(); 行似乎很可疑。但这还不是最糟糕的部分:

    这个:

    private static void mainloop()
    {
        window.removeAll();
        switch(frameID)
        {
            case 1:
                frame = new frame01();
                frame.setLayout(new FlowLayout());
                System.out.println(frame);
                window.add(frame);
                break;
            default:
                break;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(FrameG.class.getName()).log(Level.SEVERE, null, ex);
        }
        mainloop();
    }
    

    不好!它可能会中断,因为您不断创建 new frame01() 并将其添加到您的 window

    不要覆盖paint,但paintComponent。我不明白的另一件事是为什么要在单独的 class 而不是 openWin 本身中覆盖它。

    另一件事,不要让主线程休眠,如果你真的必须运行自己的线程并让它进入休眠状态。

    这段代码的目的是什么?我正在尝试理解它,以便我可以帮助您重新设计它。

    PS:不是真正的答案,只是比评论长一点。

    【讨论】:

    • 私有静态openWin frame = new frame01();之所以使用它,是因为 frame01 可以容纳多个类,但不能同时容纳。我尝试了paintcomponent,但效果相同。此外,openWin 是抽象的。我对此并不担心,但是当我尝试添加它时,它什么也没做,我认为原因是无效的东西是什么
    • @pi_squared 正如我所说的那样,这行并不是最糟糕的部分。看起来你(大概)游戏的整体设计很弱。为什么要递归循环 mainLoop()
    • 稍后我将添加一种与组件交互的方法。只是我无法获取 window.add(frame); 的问题工作
    • @pi_squared 我向你保证window.add(frame); 可以正确执行。你的问题不是你怎么做,而是你做了多少次。你必须重新设计循环(甚至更好的整个程序)。首先摆脱那个讨厌的递归调用,其次不要每次都创建新框架,但只创建一次,不要在每个循环中添加它,而是一次。在旁注中,您覆盖的 paint 方法什么都不做。
    • @pi_squared 也许this 会帮助您重新设计循环。这是我前段时间问的一个问题,它有一个类似的循环,请注意它使用Canvas 并且run() 方法在单独的Thread 上运行。
    【解决方案3】:

    永远不要使用线程,它会作为计时器启动和停止。请改用javax.swing.Timer。此外,您还创建了一个递归函数来实现一个无限循环,该循环非常连线且容易失败。 Swing 有自己的线程,当您将其与其他线程混为一谈时,它会将您的代码转化为我们都害怕的怪物。

    【讨论】:

      猜你喜欢
      • 2011-09-29
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-14
      相关资源
      最近更新 更多