2013-02-09 1 views
1

최근에 Java GUI로 작업하기 시작했습니다.GroupLayout은 포커스 리스너가 포커스를 잃게합니다.

이제 나는이 문제를 해결할 수 없습니다.

+----------------+ 
| Panel1 | Board | 
|________|_______| 
| Panel2 | EMPTY | 
|  |  | 
+----------------+ 

내가이 사용을하려고에 의해 시작 :

+----------------+ 
| Panel1 | Board | 
|________|  | 
| Panel2 |  | 
|  |  | 
+----------------+ 

하지만이납니다 : 나는 JPanel를 확장하고이 같은 ActionListener (뭔가를) 구현하는 게임 보드를 폐기 할 메인 패널의 GridLayout 내부에 BoxLayout ed 패널이 있지만 작동하지 않습니다. 그런 다음 GroupLayout을 찾았습니다. 위의 사례로 안내해 주었고 이사회 수업 시간에 청취자의 초점을 잃어 버렸습니다.

[편집] 보드의 최소 및 권장 크기를 변경하려고 시도했으나 작동하지도 않았습니다.

왜 이런 일이 일어 났는지 말해 줄 수 있습니까?

다시 시작 :

  1. 왜 그룹 레이아웃이 보드 패널에이 일을합니까? 어쨌든 고칠 수 있니?
  2. 보드 클래스 내에서 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); 
    } 

내 보드 클래스 (

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; 
      } 

     } 

[EDIT])에서 솜 ZetCode 후 전자 조언, 여기에 키 이벤트가 작동 코드의 sscce 버전입니다하지만 정렬이 여전히 잘못 : (여전히이 경우 안녕하세요 세계지만)

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; 
      } 
     } 
    } 
} 

감사합니다!

+1

[sscce] (http://sscce.org) 작성 및 게시를 고려하십시오. 포커스가 필요한 JPanels를 볼 때 의심 스럽습니다. 왜 이것이 필요한가? 그리고 GUI 클래스가 리스너 인터페이스를 구현하는 이유는 무엇입니까? 일반적으로 코드를 별도로 유지하면 코드를 유지 관리하기가 더 쉽습니다. –

+0

그리고 레이아웃이 ActionListener 이벤트에 영향을 주어서는 안되기 때문에 뭔가 다른지 또는 틀린 지 궁금합니다. 지금까지 제시 한 정보를 기반으로 말할 수 없으므로 [sscce] (http://sscce.org)가 도움이 될 것입니다 *. –

+0

sscce에 대해서, 나는 내가했던 것보다 더 많이 최소화 할 수 있다고 생각지 않습니다. 텍스트가 퍼지지만 내 영어 때문에, 나는 내 자신을 더 짧게 표현할 수 없다 (나는 생각한다). 어쨌든, 당신이 여전히 너무 크고 간결하지 않다고 생각하면 저에게 말해주세요. 최선을 다할 것입니다. 리스너를 구현하는 GUI에 대해, 이것은 프로그래밍중인 빠른 테트리스입니다. MVC 또는 Command-Kernel 패턴이 없으며 '하드 코드'입니다. –

답변

3

코드에 문제가있을 수 있으며 너무 어려움없이 해결 될 수 있습니다. KeyListeners를 사용하고 있습니다. 이것은 일반적으로 스윙 GUI에서는 피해야하며,보다 유연하고 바인딩 된 구성 요소에 포커스가 필요하지 않은 Key Bindings을 사용해야합니다.

GroupLayout 크기 조정 문제에 관해서는 GroupLayout의 사용에 대해 매우 약하다는 것을 인정해야하며 실제로 그 사용을 철저히 피하려고합니다. 고려해야 할 다른 레이아웃에는 GridBagLayout 또는 MigLayout이 포함됩니다.

편집 :
는 그러나, 나는 레이블 section을 포함하여 GroupLayout 튜토리얼, 책 읽기있다 "(축소 및 성장 수) 크기 조정이 될 수있는 구성 요소를 강제로를". 그것은 당신이 내 코드 예제처럼 보이는 레이아웃에 구성 요소를 추가 할 때 당신은 몇 가지 매개 변수를 추가해야 나타납니다 예를 들어

.addComponent(board2, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 

, 여기에 원하는대로 배치 구성 요소를 보여주는, 또한 키 바인딩의 사용을 보여주는 내 코드입니다 PropertyChangeListener를 돌려줍니다.

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; 
    } 
} 

과 같이 보일 것이다 : 키 바인딩을 사용하여 초점을 더 이상 내가 포커스 수 없으며에게 초점을 제공하기 위해 JPanel을 설정하지 않아도 같은 문제로 큰 없다는 것을 주목
enter image description here

저는 여러분의 코드를 쉽게 분리 할 수 ​​있으므로 PropertyChangeListeners를 사용하는 것을 좋아합니다. 이제 Board2 클래스는 다른 클래스가 방향 변경에 대해 어떻게 반응하는지 걱정할 필요가 없습니다. 그것이해야 할 일은이 변화를 듣고있는 모든 수업에 방송하는 것이며, 그들은 그들이 맞는 것처럼 반응합니다.

+0

고마워요! 그걸 몰랐고, 나는 그들을 연구/구현할 것이다. 위치에 대해서는 어떤 생각이 있습니까? 해당 부분이 포커스/이벤트와 아무 관련이 없으므로 레이아웃이 적용됩니다. –

+0

@AfonsoTsukamoto : GroupLayout의 사용에 대해 매우 약하다는 것을 인정해야하며 실제로 그 사용을 철저히 피하려고합니다. 고려해야 할 다른 레이아웃에는 GridBagLayout 또는 MigLayout이 포함됩니다. –

+0

, 괜찮습니다. 결국 찾겠습니다. 아니면 누군가가이 문제를 도와 줄 것입니다. 내 sscce 코드가 거의 준비가되어있다. (나는 실제로 당신의 대답 중 하나를 사용하여 그것을 더 간단하게 만든다.) 희망을주고 나면 더 쉽게 만들 수있다. –