2015-03-14 1 views
1

En bref, je veux mettre le texte d'une JLabel être celle d'un JTextField dans un JPanel (pnlUser), puis faites glisser le JLabel sur l'écran de JPanel sur un autre JTextField dans un autre JPanel (pnlGrid).Comment faire glisser un JLabel d'un JPanel dans un JFrame sur un JTextField dans un autre JPanel dans le même JFrame?

Voici les détails.

J'ai écrit un programme "Solitaire Scrabble". L'utilisateur peut placer le curseur de texte dans une cellule (JTextField dans pnlGrid) et taper une lettre qui est dans la liste des "User letters" (un JTextField dans pnlUser) OU l'utilisateur peut simuler en faisant glisser une lettre de " Lettres d'utilisateur "et le déposer dans la cellule de la grille de destination au pnlGrid.

Je dis "simuler" parce que la lettre sélectionnée n'est pas réellement déplacée sur l'écran. J'utilise le pointeur de la souris HAND_CURSOR pour rendre le glisser/déposer aussi réel que possible, mais je n'ai pas compris comment faire le HAND_CURSOR "saisir" la lettre et faire glisser physiquement la lettre à travers le tableau à sa destination. En l'état, la lettre est mise en surbrillance mais laissée dans la zone "Lettres utilisateur" tandis que HAND_CURSOR se déplace le long de la grille pendant l'opération de glissement. Quand il arrive à la cellule de destination dans pnlGrid et que le bouton de la souris est relâché, la lettre est effacée de "User letters" et apparaît soudainement dans la cellule de la grille. Ainsi, la lettre est plus ou moins "téléportée" ("beam-up", Scotty) de "User letters" à une cellule de la grille. C'est trop abstrait. Je veux que la lettre de l'utilisateur soit à l'extrémité du doigt pointé de HAND_CURSOR et soit traînée le long de la grille dans la cellule de la grille où elle sera déposée, comme montré dans les 3 images ci-dessous.

enter image description hereenter image description hereenter image description here

Je l'ai fait avec succès arriver dans un petit programme de test (source ci-dessous) à l'aide JLayeredPane, mais je ne peux pas y arriver dans le jeu. Mais je ne savais rien de JLayeredPane jusqu'à il y a deux jours, donc je ne sais pas vraiment ce que je fais. (J'ai adapté un programme de tutoriel Oracle qui démultiplie JLayeredPane.)

Je viens de lire à propos du "volet de verre" et j'ai pensé qu'il serait peut-être plus facile à implémenter jusqu'à ce que je télécharge la source de cette démo, qui est assez longue, donc depuis c'est totalement nouveau et sera encore plus difficile à adapter.

Je pensais avant que je passe plus d'heures dans la frustration que je devrais demander:

Est-ce un JLayeredPane ou une approche setGlassPane appropriée? Y at-il un moyen plus facile ou mieux de faire glisser un JLabel d'un JPanel sur un autre JPanel?

(L'approche du programme est de déterminer quel « lettre utilisateur » est pointé du, stocker cette lettre dans un JLabel, et assurez-vous que pendant mouseDragged le bout du doigt HAND_CURSOR est juste au centre bas de la lettre.)

package mousemoveletter; 
import javax.swing.*; 
import javax.swing.border.*; 
import java.awt.*; 
import static java.awt.Color.*; 
import java.awt.event.*; 
import static javax.swing.SwingUtilities.invokeLater; 

public class LayeredPaneDemo extends JPanel 
{ 
    private static final int USER7 = 7; 
    static Cursor HAND = new Cursor(Cursor.HAND_CURSOR); 
    static Cursor ARROW = new Cursor(Cursor.DEFAULT_CURSOR); 

    private static JLayeredPane layeredPane; 
    private static JLabel  lblToMove; 
    private static JPanel  pnlUser; 
    private static JPanel  pnlGrid; 
    private static final JTextField[] txtUser = new JTextField[USER7]; 

    public LayeredPaneDemo() // constructor 
    { 
    pnlGrid = new JPanel(); 
    setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 
    layeredPane = new JLayeredPane(); 
    layeredPane.setPreferredSize(new Dimension(240, 240)); 
    pnlGrid.setSize(140, 140); 
    pnlGrid.setBorder(new EtchedBorder(RED, GREEN)); 
    pnlGrid.setBackground(YELLOW); 

    lblToMove = new JLabel("XXX"); 
    lblToMove.setSize(new Dimension(40,40)); 

    layeredPane.add(pnlGrid, 0,0); 
    layeredPane.add(lblToMove, new Integer(0), -1); 

    add(layeredPane); 
    } 

    private static void createAndShowGUI() { 
    JFrame frame = new JFrame("LayeredPaneDemo"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    JComponent newContentPane = new LayeredPaneDemo(); 
    newContentPane.setOpaque(true); //content panes must be opaque 
    frame.setContentPane(newContentPane); 
    makeUser(); 

    frame.add(pnlUser); 

    frame.pack(); 
    frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
    invokeLater(new Runnable() 
    { 
     public void run() { 
     createAndShowGUI(); 
     } 
    }); 
    } 

    private static void makeUser(){ 
    pnlUser = new JPanel(new GridLayout(1,USER7)); 
    pnlUser.setPreferredSize(new Dimension(225, 50)); 
    pnlUser.setBackground(Color.green); 
    pnlUser.setBorder(BorderFactory.createLineBorder(Color.BLUE)); 
    for(int k = 0; k < USER7; k++) 
    { 
     txtUser[k] = new JTextField("" + (char)(Math.random()*26+65)); 
     txtUser[k].setName("" + k); 
     txtUser[k].setEditable(false); 
     txtUser[k].addMouseMotionListener(new MouseMotionAdapter() 
     { 
     public void mouseDragged(MouseEvent e) 
     { 
      lblToMove.setCursor(HAND); 
      int w = Integer.parseInt(e.getComponent().getName()); 
      lblToMove.setText(txtUser[w].getText()); 
      layeredPane.setLayer(lblToMove, 0, 0); 
      lblToMove.setLocation(e.getX() + (e.getComponent().getWidth())*w, 
           e.getY() + layeredPane.getHeight() - e.getComponent().getHeight()/2); 
     }; 
     }); 

     txtUser[k].addMouseListener(new MouseAdapter() 
     { 
     public void mouseReleased(MouseEvent e) 
     { 
      lblToMove.setCursor(ARROW); 
     }   
     }); 
     pnlUser.add(txtUser[k]); 
    } 
    } 
} 
+1

Try this [exemple] (http://stackoverflow.com/a/2562685/230513) et [variation] (http://stackoverflow.com/a/2563350/230513) – trashgod

+0

@ trashgod-- MERCI pour l'exemple et la variation. Après BEAUCOUP d'heures de quasi-échecs à essayer d'adapter votre idée à ma situation, j'ai ENFIN ce que je pense qui va fonctionner pour moi. Comme il est 5 heures mardi, je pense que j'attendrai jeudi pour essayer de l'implémenter dans le jeu actuel! – DSlomer64

Répondre

1

Merci à @trashgod, je me suis dit qu'il en suivant ses liens vers ce example et variation; J'ai adapté le drag/drop de l'échiquier trouvé là à mes propres besoins particuliers pour "Scrabble".

Le code ci-dessous est et non code final pour mon programme Solitaire Scrabble, mais preuve de concept, éventuellement utilisable par d'autres personnes souhaitant faire glisser une cellule d'une grille 1xN sur une grille MxM.

 package components; 
     import java.awt.*; 
     import static java.awt.BorderLayout.NORTH; 
     import static java.awt.BorderLayout.SOUTH; 
     import java.awt.event.*; 
     import static java.lang.Integer.parseInt; 
     import javax.swing.*; 
     import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE; 
     import javax.swing.event.MouseInputAdapter; 

     public class ChessBoard //implements MouseListener, MouseMotionListener 
     { 
      static Point parentLocation; 
      int homeRow, homeCol; // where to restore moved user letter if dropped on occupied cell 

      static int N  = 11; // NxN 'chessboard' squares 
      static int S  = 44; // square dimensions: SxS 
      static int W   ; // chessboard dimensions: WxW 
      static int USER7 = 7; 
      static Font dragFont; 
      static JFrame frame; 
      JLayeredPane layeredPane; 
      static JPanel gamePanel, // encompasses both pnlGrid and pnlUser 
         pnlGrid, 
         pnlUser; 
      JLabel  userDragLetter = new JLabel(); // main item to drag around or restore if needed 
      int   xAdjustment, yAdjustment; // how to locate drops accurately 

      String userLetters[] ; 

      public ChessBoard() // constructor 
      { 
      W = S*N; 
      dragFont = new Font("Courier", Font.PLAIN, S); 

      userLetters = new String[USER7]; 
      for (int i = 0; i < USER7; i++) 
       userLetters[i] = "" + (char)(65 + Math.random()*26); 

      Dimension gridSize = new Dimension(W, W); 
      Dimension userSize = new Dimension(W,  S); 
      Dimension gameSize = new Dimension(W, (W + S)); 

      frame    = new JFrame(); 
      frame.setSize(new Dimension(gameSize)); // DO NOT USE PREFERRED 

      layeredPane = new JLayeredPane(); 
      layeredPane.setPreferredSize(gameSize); // NO PREFERRED => NO GRID! 

      gamePanel = new JPanel(); 

// **EDIT** LOSE THIS LINE   gamePanel.setLayout(new BorderLayout()); 

      gamePanel.setPreferredSize(gameSize); 

      pnlGrid  = new JPanel(); 
      pnlGrid.setLayout(new GridLayout(N, N)); 
      pnlGrid.setPreferredSize(gridSize); 
      pnlGrid.setBounds(0, 0, gridSize.width, gridSize.height); 

      pnlUser  = new JPanel(); 
      pnlUser.setLayout(new GridLayout(1, N)); 
      pnlUser.setPreferredSize(userSize); 
      pnlUser.setBounds(0, gridSize.height, userSize.width, userSize.height); 

      layeredPane.add(pnlGrid, JLayeredPane.DEFAULT_LAYER); // panels to drag over 
      layeredPane.add(pnlUser, JLayeredPane.DEFAULT_LAYER); // "   " 

      for (int i = 0; i < N; i++){ 
       for (int j = 0; j < N; j++){ 
       JPanel square = new JPanel(); 
       square.setBackground((i + j) % 2 == 0 ? Color.red : Color.white); 
       pnlGrid.add(square); 
       } 
      } 

      for (int i = 0; i < N; i++) { 
       JPanel square = new JPanel(new BorderLayout()); 
       square.setBackground(Color.YELLOW); 
       pnlUser.add(square); 
      } 

      for (int i = 0; i < USER7; i++) 
       addPiece(i, 0, userLetters[i]); 

      gamePanel.addMouseListener(new MouseInputAdapter() 
      { 
       public void mousePressed (MouseEvent e){mousePressedActionPerformed (e);} 
       public void mouseReleased(MouseEvent e){mouseReleasedActionPerformed(e);} 
      }); 

      gamePanel.addMouseMotionListener(new MouseMotionAdapter() 
      { 
       public void mouseDragged(MouseEvent me){mouseDraggedActionPerformed(me);} 
      }); 

    // **EDIT: LOSE THE NEXT TWO LINES AND REPLACE BY THE LINE AFTER THEM** 


     //  gamePanel.add(layeredPane, NORTH); 
     //  gamePanel.add(pnlUser,  SOUTH); 
       gamePanel.add(layeredPane); 
       } 

      private void addPiece(int col, int row, String glyph) { 
      JLabel piece = new JLabel(glyph, JLabel.CENTER); 
      piece.setFont(dragFont); 
      JPanel panel = (JPanel) pnlUser.getComponent(col + row * N); 
      piece.setName("piece " + glyph + " @ " + row + " " + col); 
      panel.add(piece); 
      } 

      void mousePressedActionPerformed(MouseEvent e) 
      { 
      userDragLetter = null; // signal that we're not dragging if no piece is in the square 

      gamePanel.setCursor(new Cursor(Cursor.HAND_CURSOR)); 

      Component c = pnlGrid.findComponentAt(e.getX(), e.getY()); 
      if(c != null) 
       return; // Illegal to click pnlGrid 

      c = pnlUser.findComponentAt(e.getX(), e.getY() - pnlGrid.getHeight()); 

      if(c == null | c instanceof JPanel) 
       return; // letter already played; can't drag empty cell 

      parentLocation = c.getParent().getLocation(); 
      xAdjustment = parentLocation.x - e.getX(); 
      yAdjustment = parentLocation.y - e.getY() + gamePanel.getHeight() - pnlUser.getHeight(); 

      userDragLetter = (JLabel)c; 
      userDragLetter.setPreferredSize(new Dimension(S, S)); // prevent 2 letters in a square 
      userDragLetter.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment); 

      layeredPane.add(userDragLetter, JLayeredPane.DRAG_LAYER); 

      homeRow = parseInt(userDragLetter.getName().substring(10,11)); // save restore location 
      homeCol = parseInt(userDragLetter.getName().substring(12,13)); 
      } 

      void mouseDraggedActionPerformed(MouseEvent me) 
      { 
      if (userDragLetter == null) 
       return; // nothing to drag 

      int x = me.getX() + xAdjustment; // make sure grid cell will be chosen in-bounds 
      int xMax = layeredPane.getWidth() - userDragLetter.getWidth(); 
      x = Math.min(x, xMax); 
      x = Math.max(x, 0); 

      int y = me.getY() + yAdjustment; 
      int yMax = layeredPane.getHeight() - userDragLetter.getHeight(); 
      y = Math.min(y, yMax); 
      y = Math.max(y, 0); 

      if(y >= pnlGrid.getHeight()) 
       return; // can't drag to location off grid 

      userDragLetter.setLocation(x, y); 
      } 

      void mouseReleasedActionPerformed(MouseEvent e) 
      { 

    //**EDIT: CHANGED NEXT LINE** 

      gamePanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 

      if (userDragLetter == null) 
       return; // nothing to drag; nothing to release 

      // Make sure the chess piece is no longer painted on the layered pane 
      userDragLetter.setVisible(false); 
      layeredPane.remove(userDragLetter); 
      userDragLetter.setVisible(true); 

      int xMax = layeredPane.getWidth() - userDragLetter.getWidth(); 
      int x = Math.min(e.getX(), xMax); 
      x = Math.max(x, 0); 

      int yMax = layeredPane.getHeight()- userDragLetter.getHeight(); 
      int y = Math.min(e.getY(), yMax); 
      y = Math.max(y, 0); 

      Component c = pnlGrid.findComponentAt(x, y); // find deepest nested child component 

      if(c == null) // then grid cell is unoccupied so ... 
       c = pnlUser.findComponentAt(x, y); // see if there's a letter there ... 

      if(c == null | (c instanceof JLabel)){ // and if illegal or there is one, put it back... 
       userDragLetter.setLocation(parentLocation.x + xAdjustment, 
             parentLocation.y + yAdjustment + gamePanel.getHeight()); 
       userDragLetter.setVisible(true); 
       addPiece(homeCol, homeRow,userDragLetter.getName().substring(6,7)); 
       layeredPane.remove(userDragLetter); 
       return; 
      } 
      else // but if NO letter ... 
      { 
       Container parent = (Container)c; 
       parent.add(userDragLetter); // put one in the grid cell 
       parent.validate(); 
      } 
      userDragLetter.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
      } 

      public static void main(String[] args) 
      { 
      new ChessBoard(); 
      frame.add(gamePanel); 
      frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
     // frame.setResizable(false); 
      frame.pack(); 
      frame.setLocationRelativeTo(null); 
      frame.setVisible(true); 
      } 
     } 
+0

@ trashgod - Je vous vois édité mon post. Était-ce juste pour ajouter les hyperliens ou avez-vous changé le code? Je demande parce que j'ai trouvé un problème avec le code aujourd'hui et je ne veux pas écraser toutes les modifications que vous pourriez avoir apportées au code. Rends-moi au plus vite, s'il te plaît. [Le changement que je vais faire (même si le code fonctionne d'une manière ou d'une autre) est d'ajouter "layeredPane" à "gamePanel". De cette façon, ces deux conteneurs se chevauchent exactement, et n'est-ce pas le pont de la couche multicouche? Comme c'est le cas, j'ajoute aussi 'pnlUser' à' gamePanel' et ce n'est pas correct, n'est-ce pas?] – DSlomer64