Размещение компонента на Стеклянной Области

У меня есть подкласс JLabel, который формирует компонент моего GUI. Я реализовал способность перетащить компонент от одного контейнера до другого, но без любых визуальных эффектов. Я хочу иметь этот JLabel, следуют за курсором во время перетаскивания объекта от одного контейнера до другого. Я полагал, что мог просто создать стеклянную область и натянуть ее там. Однако даже после того, как я добавляю компонент к стеклянной области, устанавливаю видимый компонент, и устанавливаю стеклянную видимую область, и устанавливаю стеклянную область как непрозрачную, я все еще так не вижу компонент. Я знаю работы компонента, потому что я могу добавить его к довольному область и иметь его, обнаруживаются.

Как я добавляю компонент к стеклянной области?


Наконец изображенный, как получить простую работу в качестве примера. Спасибо, @akf. Я смог адаптировать это решение своей исходной проблемы, позволив мне удалить ~60 строк кода Java2D, который вручную представил представление 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);
    }
}
10
задан Chris Lieb 3 April 2010 в 03:49
поделиться

4 ответа

Помимо указателей на уже предоставленные примеры 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());
3
ответ дан 3 December 2019 в 14:52
поделиться

Поскольку я уже давно слежу за блогами Ромена Ги о свинге. У меня есть ссылка, которая может вас заинтересовать. Он выложил исходник - в котором используется GlassPane для эффектов DnD.

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

Я сам никогда не использовал анимацию/эффект fizzy в DnD, поэтому не могу комментировать дальше :-|

3
ответ дан 3 December 2019 в 14:52
поделиться

Несмотря на несоответствие вопроса, пример JLayeredPane , процитированный @camickr, допускает следующую адаптацию, которая подчеркивает эффект 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);
}
12
ответ дан 3 December 2019 в 14:52
поделиться

В примере кода ниже показано, как перетащить шахматную фигуру по шахматной доске. Он использует JLayeredPane вместо стеклянной панели, но я уверен, что концепции будут такими же. То есть:

а) добавьте стеклянную панель к корневой панели
б) сделайте стеклянную панель видимой
в) добавьте компонент в стеклянную панель, убедившись, что границы допустимы
г) используйте 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);
     }
}
13
ответ дан 3 December 2019 в 14:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: