我现在遇到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);
也无效。
这是我的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
和paintCompenent()
都没有决定加载?
答案 0 :(得分:1)
基本上,在核心,你有一个违反Swing API的线程,似乎对Swing的基本工作缺乏了解......欢迎来到危险区......
Swing是单线程的,不是线程安全的。这意味着您应该阻止EDT,但您也不应该与EDT外部的任何UI组件进行交互或修改
您需要改变方法。
Swing已经有一个Event Queue,一个处理这些事件的线程,Event Dispatching Thread,并使用被动绘制算法来更新UI(和布局管理器)。
你需要在这些限制范围内工作才能使一切工作。
不应尝试在BLANKScreen
课程中切换状态,而应该从"菜单面板"开始。和#34;游戏小组"。
"菜单面板"将向用户显示菜单选项,"游戏面板"将显示游戏,它将具有游戏循环和实际游戏的绘画逻辑。
现在,你可以"让他们一起工作,但我认为你需要将它们分开以开始...它只会使问题复杂化......
然后,您可以使用CardLayout
在它们之间切换。这样可以更容易地改变状态的可见状态。
另请看一下:
<强>更新... 强>
第一条规则面向对象编程 - 责任分离。一个对象负责它的工作,只有它的工作。如果你发现你的对象正在尝试做更多的事情(比如更新游戏框架并显示一个菜单),那么你就会想错误(特别是在这种情况下)。
您需要将菜单与游戏分开。游戏有一个更新机制,菜单不关心,它不需要它,它由核心框架更新。
游戏具有用户自己的交互功能,菜单也是如此,但它们之间的含义不同(鼠标点击菜单会有所作为,但在游戏中它会做其他事情),所以他们应该分开......
菜单和游戏可能甚至不关心对方,所以你可以使用某种控制器,控制两者之间的状态并促进沟通
这是一个粗略的例子,我通常会花更多的时间来构建更好的控制器和模型,但这是为了展示概念的重点,而不是提供一个完整的,开箱即用的运行解决方案...
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();
}
}
}
答案 1 :(得分:0)
@MadProgrammer的评论有答案。但除了严重的线程问题之外,您似乎多次向容器添加按钮。据我所知,addMainMenuButtonsOptions
每2 ms被调用一次,直到按下一个键。 (虽然您不会显示使用类KeyTyped
的代码,但我假设您已将其绑定到关键侦听器?)。
较小一点:您是否考虑过在构造函数中使用setBackground
和setOpaque
,而不是手动调用clearRect
?
同样@Tom指出,看起来你使用的是默认布局,所以(多个?)按钮可能会浮动到顶部 - 这就是你想要的吗?