Сохраните один нарисованный объект в JPanel при рисовании другого объекта (Java) - PullRequest
0 голосов
/ 16 июня 2020

У меня есть сетка 9x9, которая может раскрашивать сама себя, прямоугольник, который может раскрашивать себя, и конструктор, который позволяет перемещать прямоугольник с помощью клавиш со стрелками. Однако я не могу понять, как сохранить сетку на экране в то время, когда прямоугольник перемещается. В конечном счете, я хочу, чтобы прямоугольник мог действовать как навигация по сетке, перемещаясь на один квадрат вправо, когда пользователь нажимает вправо, et c.

Насколько я могу судить, вся панель JPanel переделывать всякий раз, когда вызывается paint (), что означает, что один из способов сделать это - перерисовывать каждую строку при каждом нажатии клавиши, но это кажется чрезмерным. Любым другим путем? Как бы то ни было, закрашивание прямоугольника приводит к тому, что сетка закрашивается.

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


public class TestDoubleObject extends JFrame
{

    private Color ourRectColor = new Color(28,222,144);
    private int ourRectWidth = 50;
    private int ourRectHeight = 50;

    private Point ourRecLocation = new Point(150,150);


    public class Rectangle
    {
        protected void paint(Graphics2D g2d)
        {
                g2d.setColor(ourRectColor);
                g2d.fillRect(ourRecLocation.x, ourRecLocation.y, ourRectWidth, ourRectHeight);
        }

    } // Rectangle class


    public class OurRectangle extends JPanel
    {

        private Rectangle capableRectangle;

        public OurRectangle()
        {
            capableRectangle = new Rectangle();
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D)g.create();

            capableRectangle.paint(g2d);

            g2d.dispose();
        }

    } // OurRectangle class


    public class CoreGrid
    {
        protected void paint(Graphics2D g2d)
        {

            g2d.setColor(new Color(0,0,0));

            // Draw Horizontal Lines

            for(int i=100;i<=640;i+=60)
                g2d.drawLine(100,i,640,i);


            // Draw Vertical Lines

            for(int i=100;i<=640;i+=60)
                g2d.drawLine(i,100,i,640);

        }

    } // CoreGrid class


    public class OurCoreGrid extends JPanel
    {
        private CoreGrid capableCoreGrid;

        public OurCoreGrid()
        {
            capableCoreGrid = new CoreGrid();
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D)g.create();

            capableCoreGrid.paint(g2d);

            g2d.dispose();
        }

    } // OurCoreGrid class


    KeyStroke pressRight = KeyStroke.getKeyStroke("RIGHT");
    KeyStroke pressLeft = KeyStroke.getKeyStroke("LEFT");
    KeyStroke pressUp = KeyStroke.getKeyStroke("UP");
    KeyStroke pressDown = KeyStroke.getKeyStroke("DOWN");

    OurRectangle recToWorkWith = new OurRectangle();
    OurCoreGrid gridToWorkWith = new OurCoreGrid();


    public TestDoubleObject()
    {

        InputMap inputMap = recToWorkWith.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = recToWorkWith.getActionMap();


        Action rightAction = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                ourRecLocation.x += 20;
                recToWorkWith.repaint();
            }
        };

        inputMap.put(pressRight, "rightAction");
        actionMap.put("rightAction",rightAction);


        Action leftAction = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                ourRecLocation.x -= 20;
                recToWorkWith.repaint();
            }
        };

        inputMap.put(pressLeft, "leftAction");
        actionMap.put("leftAction",leftAction);


        Action downAction = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                ourRecLocation.y += 20;
                recToWorkWith.repaint();
            }
        };

        inputMap.put(pressDown, "downAction");
        actionMap.put("downAction",downAction);


        Action upAction = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                ourRecLocation.y -= 20;
                recToWorkWith.repaint();
            }
        };

        inputMap.put(pressUp, "upAction");
        actionMap.put("upAction",upAction);



        add(gridToWorkWith);

        add(recToWorkWith);



        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800,800);
        setVisible(true);
    }

    public static void main(String[] argv)
    {
        EventQueue.invokeLater(

        new Runnable()
        {
            @Override
            public void run()
            {
                new TestDoubleObject();
            }
        });
    }
}

1 Ответ

1 голос
/ 17 июня 2020

один из способов сделать это - перерисовывать каждую строку при каждом нажатии клавиши, но это кажется чрезмерным.

Именно так и работает живопись. Swing имеет двойную буферизацию, поэтому вы не заметите проблем с покраской.

Однако это не ваша текущая проблема.

Я не могу понять, как сохранить сетку на экране, в то время как прямоугольник перемещается

Диспетчером компоновки по умолчанию для панели содержимого JFrame является BorderLayout. Когда вы добавляете компонент в BorderLayout и не указываете ограничение, предполагается BorderLayout.CENTER.

add(gridToWorkWith);
add(recToWorkWith);

Итак, с помощью приведенного выше кода вы пытаетесь добавить два компонента в BorderLayout.CENTER . Однако BorderLayout управляет только последним добавленным компонентом, то есть первый компонент будет иметь размер (0, 0), поэтому он никогда не окрашивается. 1017 1019 *

Таким образом, код может быть примерно таким:

gridToWorkWith.setLayout( new BorderLayout() );
gridToWorkWith.add( recToWorkWith );
add(gridToWorkWith);
//add(recToWorkWith);

Однако это все равно не сработает, потому что по умолчанию JPanel непрозрачен, поэтому вы не увидите сетку, потому что прямоугольник рисует поверх из этого. Итак, вам нужно сделать прямоугольник непрозрачным:

recToWorkWith.setOpaque( false );

Приятно видеть, что вы используете привязки клавиш. Одно из предложений - создать действие с параметром для управления движением прямоугольника. Таким образом, двумя параметрами будет изменение местоположения по оси x / y.

В качестве примера такого подхода посмотрите MotionAction, найденный в примере MotionWithKeyBindings, найденном в Motion Using the Keyboard . Ваши четыре действия можно легко заменить на 4 экземпляра одного и того же действия, используя разные параметры. Вы даже можете создать движение по диагонали.

...