Java 将JButton添加到窗口时出现问题

Java 将JButton添加到窗口时出现问题,java,swing,jpanel,jbutton,paintcomponent,Java,Swing,Jpanel,Jbutton,Paintcomponent,我现在在使用JButton时遇到问题。 我的JButton将不会添加到JFrame或JPanel中,并且它似乎正在禁用paintComponent()运行 这是我的JPanel课程: public class BLANKScreen extends JPanel implements Runnable { Thread thread = new Thread(this); public boolean running = false; public static Imag

我现在在使用
JButton
时遇到问题。 我的
JButton
将不会添加到
JFrame
JPanel
中,并且它似乎正在禁用
paintComponent()
运行

这是我的JPanel课程:

public class BLANKScreen extends JPanel implements Runnable {
    Thread thread = new Thread(this);
    public boolean running = false;
    public static ImageIcon greenButton = new ImageIcon("resources/menubuttons/GreenButton.png");
    public static JButton mainMenuPlayButton = new JButton("Play!", greenButton);
    private int fps;
    static BLANKWindow w;
    public int scene = 0;

    public void run() {
        long lastFrame = System.currentTimeMillis();
        int frames = 0;

        running = true;
        scene = 0;

        while (running) {
            if (scene == 0) {
                addMainMenuButtonsOptions();
            } else if (scene == 1) {

            }

            repaint();

            frames++;

            if (System.currentTimeMillis() - 1000  >= lastFrame) {
                fps = frames;
                frames = 0;
                lastFrame = System.currentTimeMillis();
            }

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

        System.exit(0);
    }

    public BLANKScreen (BLANKWindow w) {
        this.w = w;
        this.w.addKeyListener(new KeyHandler(this));
        this.w.addMouseListener(new MouseHandler(this));
        thread.start();
    }

    public class KeyTyped {
        public void keyESC() {
            running = false;
        }

        public void keySpace() {
            if (scene == 0) {
                scene = 1;
            } else if (scene == 1) {
                scene = 0;
            }
        }
    }

    public class MouseClicked { }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.clearRect(0, 0, this.w.getWidth(), this.w.getHeight());

        if (scene == 0) {
            int nameLength = g.getFontMetrics().stringWidth("BLANK!");
            g.drawString("BLANK!", w.getWidth() / 2 - nameLength / 2, w.getHeight() / 4);
        }
    }

    public void addMainMenuButtonsOptions() {
        mainMenuPlayButton.setActionCommand("/mainMenuPlayButton");
        mainMenuPlayButton.addActionListener(new ActionHandler());

        this.add(mainMenuPlayButton);
        System.out.println("ThingHappend");
    }
}
this.add(mainMenuPlayButton)w.add(mainMenuPlayButton)时,code>也不起作用

以下是我的JFrame类:

public class BLANKWindow extends JFrame {
    public static void main(String[] args) {
        new BLANKWindow();
    }

    public BLANKWindow() {
        new JFrame();

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int screenHeight = screenSize.height;
        int screenWidth = screenSize.width;

        this.setSize(screenWidth, screenHeight);
        this.setTitle("BLANK");
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setResizable(true);
        this.setExtendedState(MAXIMIZED_BOTH);
        this.setVisible(true);

        BLANKScreen dbs = new BLANKScreen(this);
        this.add(dbs);
    }
}

出于某种原因,
JButton
paintcompent()
都没有决定加载?

@MadProgrammer的评论给出了答案。但是除了严重的线程问题外,您似乎多次向容器添加按钮。据我所知,
addMainMenuButtonsOptions
每隔2毫秒调用一次,直到按下一个键。(虽然您没有显示使用类
KeyTyped
)的代码,但我假设您已将其绑定到键侦听器?)

一个较小的问题:您是否考虑过在构造函数中使用
setBackground
setOpaque
,而不是手动调用
clearRect


正如@Tom所指出的,看起来您使用的是默认布局,因此(多个?)按钮可能会浮到顶部-这就是您想要的吗?

基本上,在核心部分,您违反了Swing API的线程,并且似乎对Swing的基本工作方式缺乏了解……欢迎来到危险地带

Swing是单线程的,并且不是线程安全的。这意味着您应该阻止EDT,但也不应该与EDT外部的任何UI组件进行交互或修改

你需要改变你的方法

Swing已经有了一个事件队列、一个处理这些事件的线程、一个事件调度线程,并使用被动绘制算法来更新UI(和布局管理器)

您需要在这些约束条件下工作,以使所有这些都能工作

不要试图在
BLANKScreen
类中切换状态,而应该从“菜单面板”和“游戏面板”之类的东西开始

“菜单面板”将向用户显示菜单选项,“游戏面板”将显示游戏,它将具有实际游戏的游戏循环和绘制逻辑

现在,你“可以”让他们一起工作,但我认为你需要先把他们分开…这只会使问题复杂化

然后,您可以使用在它们之间切换。这将使更改可见状态更容易

另请看:

已更新…

面向对象编程的第一条规则——职责分离。一个对象负责它的工作,并且只负责它的工作。如果你发现你的对象正在尝试做更多的事情(比如更新游戏的框架和显示菜单),那么你的想法是错误的(尤其是在这种情况下)

你需要把菜单和游戏分开。游戏有一个更新机制,菜单不在乎,它不需要,它是由核心框架更新的

游戏有自己的用户交互,菜单也有,但它们彼此有不同的含义(鼠标点击菜单会做一些事情,但在游戏中它会做其他事情),所以它们应该分开

菜单和游戏可能彼此都不关心,所以你可以使用某种控制器,它可以控制两者之间的状态并促进通信

这是一个粗略的例子,我通常会花更多的时间构建更好的控制器和模型,但这是为了演示概念的要点,而不是提供一个完全现成的运行解决方案

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestGameMenu {

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

    public TestGameMenu() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new MainView());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MainView extends JPanel {

        private MenuPane menuPane;
        private GamePane gamePane;

        public MainView() {
            setLayout(new CardLayout());
            menuPane = new MenuPane();
            gamePane = new GamePane();

            add(menuPane, "menu");
            add(gamePane, "game");

            menuPane.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if ("play".equalsIgnoreCase(e.getActionCommand()))  {
                        ((CardLayout) getLayout()).show(MainView.this, "game");
                        gamePane.resume();
                    }
                }
            });
        }

    }

    public class MenuPane extends JPanel {

        private JButton playGame;

        public MenuPane() {
            setLayout(new GridBagLayout());
            playGame = new JButton("Play My Awesome Game!");
            playGame.setActionCommand("play");
            add(playGame);
        }

        public void addActionListener(ActionListener listener) {
            playGame.addActionListener(listener);
        }

        public void removeActionListener(ActionListener listener) {
            playGame.removeActionListener(listener);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class GamePane extends JPanel {

        private Point p;
        private int xDelta;
        private int yDelta;

        private volatile boolean running = true;
        private volatile boolean paused = true;

        private ReentrantLock lckPause;
        private Condition conPause;

        public GamePane() {

            p = new Point(100, 100);
            do {
                xDelta = (int)((Math.random() * 10) - 5);
            } while (xDelta == 0);
            do {
                yDelta = (int)((Math.random() * 10) - 5);
            } while (yDelta == 0);

            lckPause = new ReentrantLock();
            conPause = lckPause.newCondition();
            Thread t = new Thread(new Runnable() {

                @Override
                public void run() {
                    while (running) {
                        while (paused) {
                            lckPause.lock();
                            try {
                                conPause.await();
                            } catch (InterruptedException ex) {
                            } finally {
                                lckPause.unlock();
                            }
                        }

                        p.x += xDelta;
                        p.y += yDelta;

                        if (p.x < 0) {
                            p.x = 0;
                            xDelta *= -1;
                        } else if (p.x > getWidth()) {
                            p.x = getWidth();
                            xDelta *= -1;
                        }
                        if (p.y < 0) {
                            p.y = 0;
                            yDelta *= -1;
                        } else if (p.y > getHeight()) {
                            p.y = getHeight();
                            yDelta *= -1;
                        }

                        repaint();

                        if (running && !paused) {
                            try {
                                Thread.sleep(40);
                            } catch (InterruptedException ex) {
                            }
                        }
                    }
                }
            });

            t.start();

        }

        public void pause() {

            if (!paused && running) {

                lckPause.lock();
                try {
                    paused = true;
                } finally {
                    lckPause.unlock();
                }

            }

        }

        public void resume() {

            if (paused && running) {

                lckPause.lock();
                try {
                    paused = false;
                    conPause.signalAll();
                } finally {
                    lckPause.unlock();
                }

            }

        }

        public void stop() {

            if (running) {

                lckPause.lock();
                try {
                    paused = false;
                    running = false;
                    conPause.signalAll();
                } finally {
                    lckPause.unlock();
                }

            }

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            g2d.fillOval(p.x - 5, p.y - 5, 10, 10);
            g2d.dispose();
        }

    }

}

导入java.awt.CardLayout;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.EventQueue;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.GridBagLayout;
导入java.awt.Point;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.util.concurrent.locks.Condition;
导入java.util.concurrent.locks.ReentrantLock;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.UIManager;
导入javax.swing.UnsupportedLookAndFeelException;
公共类TestGameMenu{
公共静态void main(字符串[]args){
新的TestGameMenu();
}
公共测试游戏菜单(){
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException |实例化Exception | IllegalacessException |不支持ookandfeelException ex){
例如printStackTrace();
}
JFrame=新JFrame(“测试”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(newmainview());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
});
}
公共类MainView扩展了JPanel{
私人MenuPane MenuPane;
私人游戏窗格游戏窗格;
公共主视图(){
setLayout(新的CardLayout());
menuPane=新menuPane();
gamePane=新建gamePane();
添加(菜单栏,“菜单”);
添加(游戏窗格,“游戏”);
menuPane.addActionListener(新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
if(“play”.equalsIgnoreCase(例如getActionCommand())){
((CardLayout)getLayout()).show(MainView.this,“游戏”);
gamePane.resume();
}
}
});
}
}
公共类MenuPane扩展了JPanel{
私人按钮