所以我有2个类。一个创建 JPanel 和一个 JFrame,另一个创建按钮。现在我想将这些按钮添加到我的 JPanel 中。
我的 JPanel 和 JFrame 创建的地方:
public class Surface extends JPanel implements KeyListener, ActionListener
{
private static final long serialVersionUID = 1L;
static JFrame jframe = new JFrame("TitleComingSoon");
Snake mySnake = new Snake(true);
int width;
int height;
@SuppressWarnings("deprecation")
public Surface(int width, int height)
{
this.width = width;
this.height = height;
// Create the JPanel
setLayout(null);
setBounds(0, 0, 400, 400);
setBackground(Color.DARK_GRAY);
// Create the JFrame
jframe.setSize(width, height);
jframe.setResizable(false);
jframe.setLayout(null);
jframe.add(this); // Add the JPanel to the JFrame
jframe.setVisible(true);
// Add the KeyListener
addKeyListener(this);
setFocusTraversalKeysEnabled(true);
setFocusable(true);
requestFocusInWindow();
show();
}
@Override
public void paintComponent(Graphics diamond)
{
super.paintComponent(diamond);
diamond.drawRect(60, 60, 100, 50);
diamond.setColor(Color.RED);
repaint();
}
}
在我的另一堂课上,我正在这样做:
Surface.jframe.add(myButton);
我的问题是,按钮在 JPanel 下方。因此,如果我删除JPanel,我可以看到按钮。
有几件事跳出来了...
- 使用
null
布局。虽然看起来您获得了控制权,但会增加工作量并失去平台之间的灵活性。 - 从另一个组件创建框架,但更重要的是,从其构造函数中创建框架。面板不应关注其显示方式,而应专注于完成其设计目的的工作。
- 使用
KeyListener
.KeyListener
挑剔又麻烦,最好使用键绑定 API - 使用
static
进行跨对象通信。静态不是您提供跨类字段访问的方式,还有很多其他技术可以提供更好的支持。主要问题是,如果您创建窗格的另一个实例,您将创建一个新框架并更改对static
字段的引用......现在你实际上是在处理哪个框架?
那么,解决方案是什么?
- 从"主"入口类中,创建一个
JFrame
、Surface
面板和按钮的实例。将Surface
面板设置为框架的内容面板,然后将按钮添加到框架中。 - 使用适当的布局管理器
- 使用键绑定 API 而不是
KeyListener
您可以在Surface
中创建ButtonHolderClass
的实例,并通过公共getter
方法检索按钮:
public Surface(int width, int height)
{
...
ButtonHolderClass buttonHolder = new ButtonHolderClass();
JButton myButton = buttonHolder.getMyButton();
add(myButton); // Add myButton
jframe.add(this); // Add the JPanel to the JFrame
}
Surface.jframe.add(myButton);
您正在将按钮添加到 JFrame。你说你想把它添加到JPanel中。
简单制作
Surface.add(myButton);
Surface.jframe.add(Surface);
这会将 JButton 添加到 JPanel,然后将 JPanel 添加到 JFrame。
在这里订购东西有一个小问题。在 Surface 构造函数完成构造之前,将 Surface 实例添加到帧中。
package test;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Surface extends JPanel {
static JFrame jframe;
static Surface surfaceInstance = new Surface();
public static Surface getInstance() {
return surfaceInstance;
}
public static void main(String argv[]) {
/* You need this to be a good friend of the Swing */
Runnable initiator = new Runnable() {
public void run() {
jframe = new JFrame("Whatever title you want");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // this will kill the application when you close the frame
jframe.setContentPane(Surface.getInstance());
jframe.pack();
jframe.setVisible(true);
}
};
/** You let the Swing run your initiator when Swing wishes to do so */
SwingUtilities.invokeLater(initiator);
Surface.getInstance().setPreferredSize(new Dimension(400,400));
/** then you can add other stuff to it **/
for (String buttonTitle: new String[] {"button1", "button2", "button3"}) {
Surface.getInstance().add(new JButton(buttonTitle));
}
}
}