2010-04-01 17 views
9

Tôi có một lớp con của JLabel tạo thành một thành phần của GUI của tôi. Tôi đã triển khai khả năng kéo và thả thành phần từ vùng chứa này sang vùng chứa khác, nhưng không có bất kỳ hiệu ứng hình ảnh nào. Tôi muốn có JLabel này theo con trỏ trong khi kéo mục từ thùng này sang vùng chứa khác. Tôi nghĩ rằng tôi chỉ có thể tạo một khung kính và vẽ nó lên đó. Tuy nhiên, ngay cả sau khi tôi thêm thành phần vào ngăn kính, hãy đặt thành phần hiển thị và đặt ngăn kính hiển thị và đặt ngăn kính thành mờ, tôi vẫn không nhìn thấy thành phần đó. Tôi biết thành phần hoạt động vì tôi có thể thêm nó vào khung nội dung và hiển thị nó.Đặt thành phần trên ngăn kính

Làm cách nào để thêm thành phần vào ngăn kính?


Cuối cùng, hãy tìm cách làm ví dụ đơn giản. Cảm ơn, @akf. Tôi đã có thể điều chỉnh giải pháp này cho vấn đề ban đầu của mình, cho phép tôi xóa ~ 60 dòng mã Java2D được hiển thị bằng tay một biểu diễn của JLabel.

package test; 

import java.awt.Color; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.border.LineBorder; 

public class MainFrame extends JFrame { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     MainFrame mf = new MainFrame(); 
     mf.setSize(400, 400); 
     mf.setLocationRelativeTo(null); 
     mf.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
     mf.setGlassPane(new JPanel()); 

     JLabel l = new JLabel(); 
     l.setText("Hello"); 
     l.setBorder(new LineBorder(Color.BLACK, 1)); 
     l.setBounds(10, 10, 50, 20); 
     l.setBackground(Color.RED); 
     l.setOpaque(true); 
     l.setPreferredSize(l.getSize()); 

     //mf.add(l); 
     ((JPanel)mf.getGlassPane()).add(l); 
     mf.getGlassPane().setVisible(true); 

     mf.setVisible(true); 
    } 
} 
+0

Các bạn đã cố gắng thiết lập thành phần của bạn AS các glasspane thay vì thêm nó vào glasspane? – willcodejavaforfood

+0

Thành phần này đại diện cho một ô trong trò chơi chữ, vì vậy nó chỉ là 37 * 37 và sử dụng đường viền để có hiệu lực. Tôi không thấy làm thế nào tôi có thể biến đổi điều này thành một ngăn kính vì nó sẽ gây rối với kích thước của gạch. –

+0

Chúng ta có thể thấy một số mã không? Cụ thể là cách bạn thêm thành phần vào ngăn kính và đặt nó hiển thị. –

Trả lời

3

Ngoài con trỏ đến các ví dụ về LayerPane đã được cung cấp, vấn đề với mã ban đầu xoay quanh cài đặt kích thước ưa thích của nhãn của bạn. Bạn đặt nó trước khi JLabel đã được định kích thước, do đó, bạn:

l.setPreferredSize(l.getSize()); 

là không hiệu quả. Mặt khác, nếu bạn thực hiện cuộc gọi đó sau khi thực hiện cuộc gọi đến setBounds, bạn sẽ thấy kết quả mong muốn của mình. Với ý nghĩ đó, sắp xếp lại này:

l.setPreferredSize(l.getSize()); 
l.setBounds(10, 10, 50, 20); 

trông như thế này:

l.setBounds(10, 10, 50, 20); 
l.setPreferredSize(l.getSize()); 
13

Mã ví dụ bên dưới minh họa cách kéo một quân cờ chung quanh bàn cờ. Nó sử dụng JLayeredPane thay vì một khung kính, nhưng tôi chắc chắn rằng các khái niệm sẽ giống nhau. Đó là:

a) thêm khung kính để cửa sổ gốc
b) làm cho các cửa sổ kính có thể nhìn thấy
c) thêm các thành phần để cửa sổ kính đảm bảo các giới hạn có giá trị
d) sử dụng setLocation () để animate kéo của các thành phần

Edit: thêm mã để sửa chữa SSCCE

JLabel l = new JLabel(); 
l.setText("Hello"); 
l.setBorder(new LineBorder(Color.BLACK, 1)); 
// l.setPreferredSize(l.getSize()); 
// l.setBounds(10, 10, 50, 20); 
((JPanel)mf.getGlassPane()).add(l); 

mf.setVisible(true); 
mf.getGlassPane().setVisible(true); 

Khi sử dụng quản lý bố trí bạn không bao giờ sử dụng setSize() hoặc setBounds() phương pháp. Trong trường hợp của bạn, bạn chỉ cần đặt kích thước ưa thích thành (0, 0) vì đây là kích thước mặc định của tất cả các thành phần.

Nó hoạt động khi bạn thêm nhãn vào khung vì trình quản lý bố cục mặc định cho khung nội dung của khung là bố cục đường viền, do đó kích thước của nhãn được bỏ qua và nhãn được tạo thành kích thước của khung .

Tuy nhiên, theo mặc định, JPanel sử dụng FlowLayout không tôn trọng kích thước ưa thích của thành phần. Vì kích thước ưa thích là 0, nên không có gì để vẽ.

Ngoài ra, ngăn kính phải được hiển thị để nó được sơn.

Tôi khuyên bạn nên đọc Swing tutorial. Có phần về cách các nhà quản lý bố cục hoạt động và cách các ô kính hoạt động và mỗi phần có các ví dụ làm việc.

Chỉnh sửa: Mã Ví dụ thêm dưới đây:

import java.awt.*; 
import java.awt.event.*; 
import java.util.*; 
import javax.swing.*; 

public class ChessBoard extends JFrame implements MouseListener, MouseMotionListener 
{ 
    JLayeredPane layeredPane; 
    JPanel chessBoard; 
    JLabel chessPiece; 
    int xAdjustment; 
    int yAdjustment; 

    public ChessBoard() 
    { 
     Dimension boardSize = new Dimension(600, 600); 

     // Use a Layered Pane for this this application 

     layeredPane = new JLayeredPane(); 
     layeredPane.setPreferredSize(boardSize); 
     layeredPane.addMouseListener(this); 
     layeredPane.addMouseMotionListener(this); 
     getContentPane().add(layeredPane); 

     // Add a chess board to the Layered Pane 

     chessBoard = new JPanel(); 
     chessBoard.setLayout(new GridLayout(8, 8)); 
     chessBoard.setPreferredSize(boardSize); 
     chessBoard.setBounds(0, 0, boardSize.width, boardSize.height); 
     layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER); 

     // Build the Chess Board squares 

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

     // Add a few pieces to the board 

     ImageIcon duke = new ImageIcon("dukewavered.gif"); // add an image here 

     JLabel piece = new JLabel(duke); 
     JPanel panel = (JPanel)chessBoard.getComponent(0); 
     panel.add(piece); 
     piece = new JLabel(duke); 
     panel = (JPanel)chessBoard.getComponent(15); 
     panel.add(piece); 
    } 

    /* 
    ** Add the selected chess piece to the dragging layer so it can be moved 
    */ 
    public void mousePressed(MouseEvent e) 
    { 
     chessPiece = null; 
     Component c = chessBoard.findComponentAt(e.getX(), e.getY()); 

     if (c instanceof JPanel) return; 

     Point parentLocation = c.getParent().getLocation(); 
     xAdjustment = parentLocation.x - e.getX(); 
     yAdjustment = parentLocation.y - e.getY(); 
     chessPiece = (JLabel)c; 
     chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment); 

     layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER); 
     layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
    } 

    /* 
    ** Move the chess piece around 
    */ 
    public void mouseDragged(MouseEvent me) 
    { 
     if (chessPiece == null) return; 

     // The drag location should be within the bounds of the chess board 

     int x = me.getX() + xAdjustment; 
     int xMax = layeredPane.getWidth() - chessPiece.getWidth(); 
     x = Math.min(x, xMax); 
     x = Math.max(x, 0); 

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

     chessPiece.setLocation(x, y); 
    } 

    /* 
    ** Drop the chess piece back onto the chess board 
    */ 
    public void mouseReleased(MouseEvent e) 
    { 
     layeredPane.setCursor(null); 

     if (chessPiece == null) return; 

     // Make sure the chess piece is no longer painted on the layered pane 

     chessPiece.setVisible(false); 
     layeredPane.remove(chessPiece); 
     chessPiece.setVisible(true); 

     // The drop location should be within the bounds of the chess board 

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

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

     Component c = chessBoard.findComponentAt(x, y); 

     if (c instanceof JLabel) 
     { 
      Container parent = c.getParent(); 
      parent.remove(0); 
      parent.add(chessPiece); 
      parent.validate(); 
     } 
     else 
     { 
      Container parent = (Container)c; 
      parent.add(chessPiece); 
      parent.validate(); 
     } 
    } 

    public void mouseClicked(MouseEvent e) {} 
    public void mouseMoved(MouseEvent e) {} 
    public void mouseEntered(MouseEvent e) {} 
    public void mouseExited(MouseEvent e) {} 

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

Tôi gặp sự cố khi chuyển đổi JLayeredPane vì tôi sử dụng GridBagLayout cho bố cục của biểu mẫu chính. Điều này gây rối với DRAG_LAYER vì nó được yêu cầu phải có cùng một trình quản lý bố cục như phần còn lại của ngăn nội dung, nhưng tôi không muốn một trình quản lý bố cục vì điều này chỉ được sử dụng để kéo. –

+0

Ví dụ của tôi sử dụng GridLayout và DRAG_LAYER không cần sử dụng cùng một trình quản lý bố cục. Trong thực tế, nó không sử dụng trình quản lý bố cục vì bạn đang định vị các thành phần theo cách thủ công. Tôi không đề nghị bạn cần phải swith và sử dụng một lớp lớp chỉ là các khái niệm nên giống nhau. Đó là vì một ngăn kính cũng không sử dụng trình quản lý bố cục, bạn chịu trách nhiệm thiết lập các giới hạn của thành phần một cách chính xác. Dù sao thì tôi cũng không thể giúp gì được nữa. Tôi đã cung cấp cho bạn mã làm việc, tôi không biết mã của bạn khác nhau như thế nào. – camickr

+3

Bắt đầu bằng cách tạo một SSCCE đơn giản (http://sscce.org) hiển thị ngăn kính với một JLabel ở một vị trí cụ thể. Sau khi bạn nắm vững điều đó, sau đó bạn chuyển sang làm động vị trí của nhãn khi bạn kéo nó bằng chuột. Nếu bạn không thể làm cho SSCCE hoạt động thì bạn có mã đơn giản để đăng và chúng tôi có thể cung cấp các đề xuất cụ thể hơn. – camickr

3

Kể từ khi tôi đã đi theo blog Romain Guy về Swing trong một thời gian dài. Tôi có một liên kết mà bạn có thể quan tâm. Ông đã phát hành nguồn - sử dụng GlassPane cho các hiệu ứng DnD.

http://jroller.com/gfx/entry/drag_and_drop_effects_the

Bản thân tôi chưa bao giờ sử dụng một ga hoạt hình/ảnh hưởng đến Chia sẽ, vì vậy không thể bình luận thêm nữa: - |

+0

Thật không may, sử dụng hình ảnh được vẽ trực tiếp lên ngăn kính chứ không phải các thành phần được hiển thị bởi Swing. –

+0

Nó không quan trọng là ví dụ vẽ hình ảnh. Để sử dụng các thành phần, bạn chỉ cần thêm thành phần vào ngăn kính và đảm bảo bạn đã đặt các giới hạn đúng cách. – camickr

+0

Vấn đề là tôi _was_ thêm thành phần vào ngăn kính và đặt giới hạn của nó, nhưng nó vẫn không hiển thị. Điều duy nhất tôi có thể hình dung là tôi không có ý tưởng làm thế nào để thiết lập các giới hạn một cách chính xác trên một thành phần. –

11

Mặc dù tiếp tuyến cho câu hỏi, JLayeredPaneexample được trích dẫn bởi @camickr thừa nhận sự thích ứng sau, làm nổi bật tác động của mouseReleased() so với thành phần hiện có.

public ChessBoard() { 
    ... 
    // Add a few pieces to the board 
    addPiece(3, 0, "♛"); 
    addPiece(4, 0, "♚"); 
    addPiece(3, 7, "♕"); 
    addPiece(4, 7, "♔"); 
} 

static Font font = new Font("Sans", Font.PLAIN, 72); 

private void addPiece(int col, int row, String glyph) { 
    JLabel piece = new JLabel(glyph, JLabel.CENTER); 
    piece.setFont(font); 
    JPanel panel = (JPanel) chessBoard.getComponent(col + row * 8); 
    panel.add(piece); 
} 
+0

@DavidKroukamp: Thông tin thêm về tùy biến hình tượng [tại đây] (http://stackoverflow.com/q/18686199/230513). – trashgod

Các vấn đề liên quan