我最近开始使用 Java GUI - 最恰当的是 Swing。
现在我遇到了这个问题,我无法解决。
我想配置一个扩展 JPanel
并实现 ActionListener
(类似的东西)的游戏板:
+----------------+
| Panel1 | Board |
|________| |
| Panel2 | |
| | |
+----------------+
但是我得到了这个:
+----------------+
| Panel1 | Board |
|________|_______|
| Panel2 | EMPTY |
| | |
+----------------+
我开始尝试使用 GridLayout
主 Pane 来实现这一点,其中包含 BoxLayout
ed 面板,但没有奏效。然后我找到了 GroupLayout
,这让我想到了上面的案例,并让我失去了对 board 类中听众的控制/关注。
[编辑] 我还尝试更改板的最小尺寸和首选尺寸,也没有用。
谁能告诉我为什么会这样?
恢复:
- 为什么组布局要对 Board 面板执行此操作?无论如何,我可以修复它吗?
- 因为在 Board 类中,我执行 setFocusable(true);为什么进入组布局后无法获取操作/事件?(没有它也能正常工作)
代码如下:
游戏类
...
public ConstructorOfTheClassThatExtendsJFrame() {
statusbar = new JLabel(" 0");
panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.black));
this.getContentPane().add(panel);
Board board = new Board(this);
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
//Specify automatic gap insertion:
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
//PANEL 1
col1 = new JPanel();
col1.setBorder(BorderFactory.createLineBorder(Color.black));
//PANEL 3
col3 = new JPanel();
col3.add(statusbar);
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(col1)
.addComponent(col3))
.addComponent(board)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(col1)
.addComponent(board))
.addComponent(col3)
);
setSize(400, 400);
setResizable(false);
setTitle("GameOn");
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
和我的 Board 类(来自 ZetCode)
public Board(Game parent) {
setFocusable(true);
curPiece = new Shape();
timer = new Timer(400, this);
timer.start();
statusbar = parent.getStatusBar();
board = new Tetrominoes[BoardWidth * BoardHeight];
addKeyListener(new TAdapter());
clearBoard();
}
...
class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (!isStarted || curPiece.getShape() == Tetrominoes.NoShape) {
return;
}
int keycode = e.getKeyCode();
if (keycode == 'p' || keycode == 'P') {
pause();
return;
}
if (isPaused)
return;
switch (keycode) {
case KeyEvent.VK_LEFT:
tryMove(curPiece, curX - 1, curY);
break;
case KeyEvent.VK_RIGHT:
tryMove(curPiece, curX + 1, curY);
break;
case KeyEvent.VK_DOWN:
//tryMove(curPiece, curX, curY - 1);
oneLineDown();
break;
case KeyEvent.VK_UP:
tryMove(curPiece.rotateRight(), curX, curY);
break;
case KeyEvent.VK_SPACE:
dropDown();
break;
case 'd':
oneLineDown();
break;
case 'D':
oneLineDown();
break;
case KeyEvent.VK_SHIFT:
newPiece();
break;
}
}
[编辑] 经过一些建议,这里是代码的 sscce 版本,其中键事件有效但对齐仍然错误:
游戏类(本例是hello world但还是)
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
public class HelloWorldSwing{
private static void createAndShowGUI(){
//Create frame
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.black));
frame.getContentPane().add(panel);
//Create the new group layout
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
//We specify automatic gap insertion:
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
//PANEL 1
JPanel col1 = new JPanel();
col1.setBorder(BorderFactory.createLineBorder(Color.black));
//PANEL 2
JLabel label2 = new JLabel("Col2");
Board board = new Board(label2, new BorderLayout());
//PANEL 3
JPanel col3 = new JPanel();
JLabel label = new JLabel("Col1");
JLabel label3 = new JLabel("Col3");
col1.add(label);
board.add(label2,BorderLayout.PAGE_END);
col3.add(label3);
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(col1)
.addComponent(col3))
.addComponent(board)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(col1)
.addComponent(board))
.addComponent(col3)
);
frame.setSize(300, 400);
frame.setVisible(true);
}
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
和板类:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.BorderLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Board extends JPanel implements ActionListener {
JLabel blabel;
public Board(JLabel label, BorderLayout b) {
super(b);
setFocusable(true);
blabel = label;
addKeyListener(new TAdapter());
}
public void actionPerformed(ActionEvent e) {
}
class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
switch (keycode) {
case KeyEvent.VK_LEFT:
blabel.setText("Left");
break;
case KeyEvent.VK_RIGHT:
blabel.setText("Right");
break;
case KeyEvent.VK_DOWN:
blabel.setText("Down");
break;
}
}
}
}
感谢您的宝贵时间!
最佳答案
我在您的代码中看到一件事可能是个问题并且可以很容易地解决:您正在使用 KeyListeners。这通常应该在 Swing GUI 中避免,您应该尝试使用 Key Bindings。哪些更灵活,哪些不需要绑定(bind)组件具有焦点。
关于您的 GroupLayout 大小问题,我不得不承认我对 GroupLayout 的使用非常薄弱,事实上我努力避免使用它。其他需要考虑的布局包括 GridBagLayout 或 MigLayout。
编辑:
但是,我现在已经阅读了 GroupLayout 教程,包括 section标记为“强制调整组件大小(允许缩小和增大):”。似乎在将组件添加到布局时必须添加一些参数,在我的代码示例中如下所示:
.addComponent(board2, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
例如,这是我的代码,显示了按需要布置的组件,还显示了 KeyBindings 和 PropertyChangeListener 的使用。请注意,通过使用键绑定(bind),焦点不再是一个大问题,因为我不必将 JPanel 设置为可聚焦,也不必为其提供焦点:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
/**
* uses GroupLayout and Key Bindings
* @link http://stackoverflow.com/questions/14784773/grouplayout-makes-action-listener-loses-focus
* @author Pete
*
*/
@SuppressWarnings("serial")
public class HelloWorldSwing2GroupLayout extends JPanel {
private JLabel[] labels = {new JLabel("A"), new JLabel("B")};
private Board2 board2 = new Board2();
private JLabel directionLabel = new JLabel();
public HelloWorldSwing2GroupLayout() {
directionLabel.setHorizontalAlignment(SwingConstants.CENTER);
board2.add(directionLabel);
board2.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (Board2.DIRECTION.equals(pcEvt.getPropertyName())) {
Direction dir = (Direction)pcEvt.getNewValue();
if (dir != null) {
directionLabel.setText(dir.getText());
} else {
directionLabel.setText("");
}
}
}
});
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
int lWidth = board2.getPreferredSize().width;
int lHeight = board2.getPreferredSize().height / 2;
Dimension preferredSize = new Dimension(lWidth, lHeight);
for (JLabel label : labels) {
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setVerticalAlignment(SwingConstants.CENTER);
label.setBorder(BorderFactory.createLineBorder(Color.black));
// please, please forgive me Jeanette! This is for demo purposes only.
label.setPreferredSize(preferredSize);
}
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
layout.setHorizontalGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(labels[0], 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(labels[1], 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(board2, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(layout.createParallelGroup()
.addGroup(layout.createSequentialGroup()
.addComponent(labels[0], 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(labels[1], 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(board2, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}
private static void createAndShowGui() {
HelloWorldSwing2GroupLayout mainPanel = new HelloWorldSwing2GroupLayout();
JFrame frame = new JFrame("HelloWorldSwing2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class Board2 extends JPanel {
private static final int PREF_W = 200;
private static final int PREF_H = 400;
public static final String DIRECTION = "direction";
private Direction direction = null;
public Board2() {
setBorder(BorderFactory.createTitledBorder("Board2"));
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
for (Direction dir : Direction.values()) {
inputMap.put(dir.getKeyStroke(), dir.getText());
actionMap.put(dir.getText(), new MyArrowBinding(dir));
}
}
private class MyArrowBinding extends AbstractAction {
private Direction dir;
public MyArrowBinding(Direction dir) {
super(dir.getText());
this.dir = dir;
putValue(ACTION_COMMAND_KEY, dir);
}
@Override
public void actionPerformed(ActionEvent e) {
setDirection(dir);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void setDirection(Direction direction) {
Direction oldValue = this.direction;
Direction newValue = direction;
this.direction = newValue;
firePropertyChange(DIRECTION, oldValue, newValue);
}
public Direction getDirection() {
return direction;
}
}
enum Direction {
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
Direction(String text, KeyStroke keyStroke) {
this.text = text;
this.keyStroke = keyStroke;
}
private String text;
private KeyStroke keyStroke;
public String getText() {
return text;
}
public KeyStroke getKeyStroke() {
return keyStroke;
}
@Override
public String toString() {
return text;
}
}
看起来像这样:
我非常喜欢使用 PropertyChangeListeners 来处理这类事情,因为它可以让您的代码轻松解耦。现在 Board2 类不必担心其他类对其方向的任何变化有何 react 。它所要做的就是将此更改广播给碰巧正在收听它的任何类,并且它们各自根据自己认为合适的方式做出响应。
关于java - GroupLayout 使 Action 监听器失去焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14784773/