1

简而言之,我想将 a 的文本设置为( )JLabel中的 a的文本,然后将屏幕从另一个( )中的另一个拖动到另一个上。JTextFieldJPanelpnlUserJLabelJPanelJTextFieldJPanelpnlGrid

这是详细信息。

我写了一个“Solitaire Scrabble”程序。用户可以将文本光标定位在网格单元格中(a JTextFieldin pnlGrid)并键入“用户字母”列表中的字母(a JTextFieldin pnlUser),或者用户可以模拟从“用户字母”中拖动一个字母并将其放下中的目标网格单元格pnlGrid

我说“模拟”是因为所选字母实际上并未在屏幕上拖动。我使用鼠标指针HAND_CURSOR使拖放尽可能真实,但我还没有弄清楚如何HAND_CURSOR“抓住”字母并将字母物理拖过板子到目的地。

HAND_CURSOR实际上,在拖动操作期间沿网格移动时,字母被突出显示但留在“用户字母”区域中。当它到达目标单元格pnlGrid并释放鼠标按钮时,该字母会从“用户字母”中删除,并突然出现在网格单元格中。

所以这封信或多或少地从“用户信件”“传送”(让我向上,斯科蒂)到一个网格单元。这太抽象了。我希望用户字母位于 HAND_CURSOR 手指的尖端,并沿着网格拖动到将被放置的网格单元格中,如下面的 3 张图片所示。

在此处输入图像描述在此处输入图像描述在此处输入图像描述

我已经使用 JLayeredPane 在一个小型测试程序(以下来源)中成功实现了它,但我无法在游戏中实现它。但是直到两天前我才对 JLayeredPane 一无所知,所以我真的不知道我在做什么。(我改编了一个演示 JLayeredPane 的 Oracle 教程程序。)

我刚刚阅读了“玻璃窗格”,并认为它可能更容易实现,直到我下载了该演示的源代码,这很长,所以因为它是全新的,而且更难适应。

所以我想在我花更多时间沮丧之前,我应该问:

一种JLayeredPane或一种setGlassPane方法是否合适?有没有更简单或更好的方法将一个JLabel从一个JPanel拖到另一个JPanel

(程序中的方法是确定指向哪个“用户字母”,将该字母存储在 aJLabel中,然后确保指尖正好位于字母的底部中心。mouseDraggedHAND_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]);
    }
  }
}
4

1 回答 1

1

感谢@trashgod,我通过他指向这个例子变体的链接找到了答案;我调整了在那里找到的棋盘的拖放,以适应我自己对“拼字游戏”的特殊需求。

下面的代码不是我的 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);
          }
        }
于 2015-03-17T08:50:58.690 回答