Упаковка полигонов и Jbutton в плитку - PullRequest
2 голосов
/ 17 февраля 2020

Я делаю игру в маджонг на качелях для курсового проекта и пытаюсь создать плитку, которая на самом деле представляет собой простой JButton с подключенными к нему несколькими полигонами. Это выглядит так (https://imgur.com/af7zzTn).

Я создал метод, который создает структуру, как указано выше, но у меня есть 2 проблемы:

  1. Я не знаю, как "упаковать" структуру выше в "плитку". Допустим, «плитка» будет объектом класса «Плитка», который расширяет JButton или JComponent, я не уверен, какой из них подходит лучше.

  2. Я хочу добавить плитки как и выше для JLayeredPane, что позволит мне использовать 3-ю координату, например «z», или, другими словами, положить плитки друг на друга, не вызывая их, но я также не знаю, как это сделать.

Не могли бы вы мне помочь? Я так растерялся, что потратил около 10 часов на решение такой проблемы, но не смог найти лучшего решения на inte rnet. Также я был бы рад, если вы сделаете ответ максимально просто.

Заранее спасибо, и вот мой код:

public class TestWindow extends JFrame {
static JLayeredPane levels;

public TestWindow() {
    super("Test");
    PanelTest panel = new PanelTest();
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(1000, 700);
    setVisible(true);
    add(panel);
    levels = getLayeredPane();
    System.out.println(levels.getSize());
}


//Method for creating Tile, like one on the image
public static void createTestTile(int x, int y, int z, Graphics g) {
    Graphics2D g2d = (Graphics2D) g;

    //Left
    Polygon ml = new Polygon();
    ml.addPoint(x, y);
    ml.addPoint(x - 5, y + 10);
    ml.addPoint(x - 5, y + 70);
    ml.addPoint(x, y + 60);
    g2d.setPaint(Color.LIGHT_GRAY);
    g2d.fillPolygon(ml);
    g2d.setPaint(Color.GRAY);
    g2d.drawLine(x, y + 60, x - 5, y + 69);

    //Middle-bottom
    Polygon mb = new Polygon();
    mb.addPoint(x, y + 60);
    mb.addPoint(x - 5, y + 70);
    mb.addPoint(x + 41, y + 70);
    mb.addPoint(x + 46, y + 60);
    g2d.setPaint(Color.LIGHT_GRAY);
    g2d.fillPolygon(mb);

    //JButton on top
    JButton top = new JButton();
    top.setBounds(x, y, 46, 60);
    TestWindow.levels.add(top, new Integer(z));
}

class PanelTest extends JPanel {


    int x;
    int y;

    public PanelTest() {
        setLayout(null);


    }

    public void paintComponent(Graphics g) {

        Graphics2D g2d = (Graphics2D) g;

        createTestTile(200, 100, 1, g);
        createTestTile(200, 160, 1, g);
        createTestTile(246, 160, 1, g);
        createTestTile(223, 130, 2, g);
        createTestTile(246, 100, 1, g);
        createTestTile(400, 100, 1, g);
    }

}

public static void main(String[] args) {
    TestWindow window = new TestWindow();
}

}

1 Ответ

1 голос
/ 17 февраля 2020

Код для рисования только для рисования. Он НИКОГДА не должен создавать компонент.

Для игры у вас есть два подхода к проектированию:

  1. Используйте реальные компоненты и настраивайте компоненты, используя такие функции, как Borders.
  2. делать заказные картины для всего.

Ваш код пытается смешать оба подхода, что неверно.

Я пытаюсь создать плитку, которая на самом деле является простым JButton с несколькими полигонами, подключенными к it.

Если вы хотите реализовать игру с использованием реальных компонентов, вам следует реализовать желаемый вид, используя пользовательский Border, чтобы придать кнопке эффект 3D.

Прочтите раздел из учебника Swing по Как использовать границы

Ниже приведен пример, который я изменил на основе «поднятого» * ​​1024 *, чтобы рисовать только блики с двух сторон:

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 * A class which implements a simple tile border.
 */
public class TileBorder extends AbstractBorder
{
    protected int thickness;
    protected Color shadowInner;
    protected Color shadowOuter;

    /**
     * Creates a tile border with the specified type and whose
     * colors will be derived from the background color of the
     * component passed into the paintBorder method.
     * @param thickness the type of tile for the border
     */
    public TileBorder(int thickness) {
        this.thickness = thickness;
    }

    /**
     * Creates a tile border with the specified type, highlight and
     * shadow colors.
     * @param thickness the type of tile for the border
     * @param shadow the color to use for the tile shadow
     */
    public TileBorder(int thickness, Color shadow)
    {
        this(thickness, shadow, shadow.brighter());
    }

    /**
     * Creates a tile border with the specified type, highlight and
     * shadow colors.
     *
     * @param thickness the type of tile for the border
     * @param shadowOuterColor the color to use for the tile outer shadow
     * @param shadowInnerColor the color to use for the tile inner shadow
     */
    public TileBorder(int thickness, Color shadowOuterColor, Color shadowInnerColor)
    {
        this(thickness);
        this.shadowOuter = shadowOuterColor;
        this.shadowInner = shadowInnerColor;
    }

    /**
     * Paints the border for the specified component with the specified
     * position and size.
     * @param c the component for which this border is being painted
     * @param g the paint graphics
     * @param x the x position of the painted border
     * @param y the y position of the painted border
     * @param width the width of the painted border
     * @param height the height of the painted border
     */
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
    {
        int h = height;
        int w = width;
        int t = thickness;
        int m = thickness / 2;

        Graphics2D g2d = (Graphics2D)g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.translate(x, y);

        //  Paint border on right/bottom of component

        Shape outer = new Rectangle(0, 0, w - 1, h - 1);
        Shape inner = new Rectangle(0, 0, w - t, h - t);

        Area border = new Area( outer );
        border.subtract( new Area(inner) );

        g2d.setColor(getShadowInnerColor(c));
        g2d.fill( border );

        // Highlight border edge

        g2d.setColor(getShadowOuterColor(c));

        g2d.draw( border );
        g2d.drawLine(0, 0, w - t, 0);
        g2d.drawLine(0, 0, 0, h - t);
        g2d.drawLine(w - t, h - t, w, h);

        //  Fill border edge with background color of parent component

        g2d.setColor( c.getParent().getBackground() );

        Polygon topRight = new Polygon();
        topRight.addPoint(w - t, 0);
        topRight.addPoint(w, 0);
        topRight.addPoint(w, m);
        g2d.fillPolygon(topRight);

        Polygon bottomLeft = new Polygon();
        bottomLeft.addPoint(0, h - t);
        bottomLeft.addPoint(0, h);
        bottomLeft.addPoint(m, h);
        g2d.fillPolygon(bottomLeft);

        //  Cleanup

        g2d.dispose();
    }

    /**
     * Reinitialize the insets parameter with this Border's current Insets.
     * @param c the component for which this border insets value applies
     * @param insets the object to be reinitialized
     */
    public Insets getBorderInsets(Component c, Insets insets)
    {
        insets.set(0, 0, thickness, thickness);
        return insets;
    }

    /**
     * Returns the inner shadow color of the tile border
     * when rendered on the specified component.  If no shadow
     * color was specified at instantiation, the shadow color
     * is derived from the specified component's background color.
     * @param c the component for which the shadow may be derived
     */
    public Color getShadowInnerColor(Component c)
    {
        Color shadow = getShadowInnerColor();
        return shadow != null ? shadow : c.getBackground().darker();
    }

    /**
     * Returns the outer shadow color of the tile border
     * when rendered on the specified component.  If no shadow
     * color was specified at instantiation, the shadow color
     * is derived from the specified component's background color.
     * @param c the component for which the shadow may be derived
     */
    public Color getShadowOuterColor(Component c)
    {
        Color shadow = getShadowOuterColor();
        return shadow != null ? shadow : c.getBackground().darker().darker();
    }

    /**
     * Returns the inner shadow color of the tile border.
     * Will return null if no shadow color was specified
     * at instantiation.
     */
    public Color getShadowInnerColor()
    {
        return shadowInner;
    }

    /**
     * Returns the outer shadow color of the tile border.
     * Will return null if no shadow color was specified
     * at instantiation.
     */
    public Color getShadowOuterColor()
    {
        return shadowOuter;
    }

    /**
     * Returns whether or not the border is opaque.
     */
    public boolean isBorderOpaque()
    {
        return true;
    }

    private static void createAndShowGUI()
    {
        Border tile = new TileBorder(6);
        JPanel panel = new JPanel( new FlowLayout(FlowLayout.LEFT, 0, 0) );

        for (int i = 0; i < 5; i++)
        {
            JButton button = new JButton();
            button.setPreferredSize( new Dimension(50, 100) );
            button.setBorder( tile );
            panel.add( button );
        }

        JLayeredPane layeredPane = new JLayeredPane();
        int locationX = 20;
        int locationY = 50;

        for (int i = 0; i < 5; i++)
        {
            JButton button = new JButton();
            button.setSize( new Dimension(50, 100) );
            button.setLocation(locationX, locationY);
            button.setBorder( tile );
            panel.add( button );
            layeredPane.add(button, new Integer(i));
            locationX += 6;
            locationY -= 6;
        }

        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel, BorderLayout.PAGE_START);
        frame.add(layeredPane, BorderLayout.CENTER);
        frame.setSize(300, 300);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args) throws Exception
    {
        java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}

Позволяет настроить толщину границы, а также указать цвета границы.

Вы также можете проверить Как использовать многоуровневые панели для рабочих примеров.

...