简体   繁体   English

如何将JLabel从JFrame中的一个JPanel拖动到同一JFrame中另一个JPanel的JTextField中?

[英]How should I drag a JLabel from one JPanel in a JFrame onto a JTextField in another JPanel in the same JFrame?

In short, I want to set the text of a JLabel to be that of a JTextField in a JPanel ( pnlUser ) and then drag the JLabel across the screen from JPanel onto another JTextField in another JPanel ( pnlGrid ). 简而言之,我想将JLabel的文本设置为JPanelpnlUser )中的JTextField的文本,然后将JLabelJPanel拖到整个屏幕上,拖到另一个JPanelpnlGrid )中的另一个JTextField上。

Here are the details. 这是详细信息。

I have written a "Solitaire Scrabble" program. 我写了一个“纸牌拼字游戏”程序。 The user can either position the text cursor in a grid cell (a JTextField in pnlGrid ) and type a letter that is in the list of "User letters" (a JTextField in pnlUser ) OR the user can simulate dragging a letter from "User letters" and dropping it into the destination grid cell in pnlGrid . 用户可以将文本光标放置在网格单元中(在pnlGridJTextField ),然后键入“用户字母”列表中的字母(在pnlUserJTextField ),或者用户可以模拟从“用户字母”中拖动字母“并将其放入pnlGrid的目标网格单元中。

I say "simulate" because the selected letter is not actually dragged across the screen. 我之所以说“模拟”,是因为所选字母实际上并没有在屏幕上拖动。 I use the mouse pointer HAND_CURSOR to make the drag/drop as real as possible, but I haven't figured out how to make the HAND_CURSOR "grab" the letter and physically drag the letter across the board to its destination. 我使用鼠标指针HAND_CURSOR使拖放尽可能真实,但我还没有弄清楚如何使HAND_CURSOR “抓住”字母并将其实际拖动到目标位置。

As it is, the letter is highlighted but left in the "User letters" area while the HAND_CURSOR moves along the grid during the drag operation. HAND_CURSOR ,该字母被突出显示,但是在“ HAND_CURSOR ”在拖动操作过程中沿网格移动时留在“用户字母”区域中。 When it gets to the destination cell in pnlGrid and the mouse button is released, the letter is erased from "User letters" and suddenly appears in the grid cell. 当到达pnlGrid的目标单元格并释放鼠标按钮时,该字母便从“用户字母”中删除,并突然出现在网格单元格中。

So the letter is more or less "teleported" (beam me up, Scotty) from "User letters" to a grid cell. 因此,该字母或多或少地从“用户字母”“传送”到了网格单元中(请问我,斯科蒂)。 This is too abstract. 这太抽象了。 I want the user letter to be at the tip of the HAND_CURSOR's pointing finger and be dragged along the grid into the grid cell where it will be dropped, as shown in the 3 pictures below. 我希望用户字母位于HAND_CURSOR的指尖处,并沿着网格拖到将其拖放到的网格单元中,如下面的3张图片所示。

在此处输入图片说明在此处输入图片说明在此处输入图片说明

I've successfully made it happen in a small test program (source below) using JLayeredPane, but I can't make it happen in the game. 我已经使用JLayeredPane在一个小型测试程序(下面的资源)中成功实现了它,但是我无法在游戏中实现它。 But I knew nothing about JLayeredPane until two days ago so I don't really know what I'm doing. 但是直到两天前我对JLayeredPane还是一无所知,所以我真的不知道自己在做什么。 (I adapted an Oracle tutorial program that demos JLayeredPane.) (我改编了一个演示JLayeredPane的Oracle教程程序。)

I just read about the "glass pane" and thought it would maybe be easier to implement until I downloaded the source for that demo, which is quite long, so since it's totally new and will be even harder to adapt. 我刚刚阅读了有关“玻璃窗格”的内容,并认为在下载该演示的源代码之前,实现起来可能会更容易,因为它很长,因此,它是全新的,适应起来会更加困难。

So I thought before I spend more hours in frustration I should ask: 所以我想在花更多的时间沮丧之前,我应该问:

Is a JLayeredPane or a setGlassPane approach appropriate? JLayeredPanesetGlassPane方法是否合适? Is there an easier or better way to drag a JLabel from one JPanel onto another another JPanel ? 有没有更简便或更好的方法将JLabel从一个JPanel拖动到另一个JPanel

(The approach in the program is to determine which "User letter" is being pointed at, store that letter in a JLabel , and then make sure that during mouseDragged the HAND_CURSOR fingertip is right at the bottom center of the letter.) (该程序中的方法是确定所指向的“用户字母”,将该字母存储在JLabel ,然后确保在mouseDragged期间, HAND_CURSOR指尖位于该字母的底部中心。)

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

Thanks to @trashgod, I figured it out by following his links to this example and variation ; 感谢@trashgod,我通过关注他到本示例变体的链接来弄清楚了它; I adapted the drag/drop of the chessboard found there to my own particular needs for "Scrabble". 我将在那里找到的棋盘的拖放调整适应了我自己对“拼字游戏”的特殊需要。

The code below is not final code for my Solitaire Scrabble program, but proof-of-concept, possibly usable by others wishing to drag a cell from a 1xN grid onto a MxM grid. 下面的代码不是我的Solitaire Scrabble程序的最终代码,而是概念验证,可能被希望将单元从1xN网格拖到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);
          }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM