10

GUIのコンポーネントを形成するJLabelのサブクラスがあります。コンポーネントをあるコンテナから別のコンテナにドラッグアンドドロップする機能を実装しましたが、視覚効果はありません。あるコンテナから別のコンテナにアイテムをドラッグするときに、このJLabelをカーソルに追従させたいと思います。ガラス板を作ってそこに描くだけでいいと思いました。ただし、コンポーネントをガラスペインに追加し、コンポーネントを表示に設定し、ガラスペインを表示に設定し、ガラスペインを不透明に設定した後でも、コンポーネントが表示されません。コンポーネントをコンテンツペインに追加して表示できるので、コンポーネントが機能することはわかっています。

ガラス板にコンポーネントを追加するにはどうすればよいですか?


最後に、簡単な例を機能させる方法を考え出しました。ありがとう、@akf。このソリューションを元の問題に適合させることができ、JLabelの表現を手動でレンダリングした最大60行のJava2Dコードを削除することができました。

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

4 に答える 4

13

以下のコード例は、チェス盤の周りでチェスの駒をドラッグする方法を示しています。ガラス板の代わりに JLayeredPane を使用していますが、概念は同じであると確信しています。あれは:

a) ガラス ペインをルート ペインに追加する
b) ガラス ペインを表示する
c) 境界が有効であることを確認しながらコンポーネントをガラス ペインに追加する
d) setLocation() を使用してコンポーネントのドラッグをアニメーション化する

編集: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);

レイアウト マネージャーを使用する場合は、setSize() または setBounds() メソッドを使用しないでください。あなたの場合、これはすべてのコンポーネントのデフォルトのサイズであるため、優先サイズを (0, 0) に設定するだけです。

フレームのコンテンツ ペインのデフォルトのレイアウト マネージャーはボーダー レイアウトであるため、フレームにラベルを追加すると機能します。したがって、ラベルの優先サイズは無視され、ラベルはフレームのサイズになります。

ただし、デフォルトでは、JPanel はコンポーネントの推奨サイズを尊重する FlowLayout を使用します。優先サイズは 0 であるため、ペイントするものはありません。

また、ガラス板を塗装するには、ガラス板を見えるようにする必要があります。

Swing チュートリアルを読むことをお勧めします。レイアウト マネージャーがどのように機能するか、およびガラス ペインがどのように機能するかについてのセクションがあり、各セクションには実用的な例があります。

編集:以下に追加されたサンプルコード:

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);
     }
}
于 2010-04-01T18:29:46.637 に答える
12

質問には接していますが、@camickr によって引用されたJLayeredPane mouseReleased()は、既存のコンポーネントに対する効果を強調する次の適応を認めています。

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);
}
于 2010-04-01T20:12:44.520 に答える
3

既に提供されている LayerPane の例へのポインタに加えて、元のコードの問題は、ラベルの優先サイズの設定に集中しています。JLabel のサイズが変更される前に設定すると、次のようになります。

l.setPreferredSize(l.getSize());

効果がありません。一方、 への呼び出しを行った後にその呼び出しを行うとsetBounds、目的の結果が表示されます。それを念頭に置いて、これを並べ替えます。

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

次のようになります。

l.setBounds(10, 10, 50, 20);
l.setPreferredSize(l.getSize());
于 2010-04-03T03:06:01.163 に答える
3

Romain Guy の Swing に関するブログを長い間フォローしていたので。あなたが興味を持っているかもしれないリンクがあります。彼はソースをリリースしました - これは DnD 効果のために GlassPane を使用しました。

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

私自身、DnD で発泡性アニメーション/エフェクトを使用したことがないので、これ以上コメントすることはできません :-|

于 2010-04-01T18:55:41.823 に答える