Нарисуйте поверх апплета внутри рамки

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

Мое первоначальное понимание заключалось в том, что Applet, расширяя Component, точно так же, как и любой обычный java.awt.Component, который можно добавить внутри контейнера, который просто переопределяет метод рисования, но кажется, что он не работает.

В моем коде инициализации я создаю java.awt.Frame, на котором я добавляю свою пользовательскую реализацию java.awt.Container, которая переопределила все методы рисования, чтобы они заполнили прямоугольник в x: 5, y: 5 с размером w: 10, h: 10 после вызова родительского метода

Однако, когда апплет добавляется, он всегда, независимо от того, что нарисовано поверх всего

public class AppletTest {

    public static void main(String[] args) {
        Frame frame = new Frame("Applet Test!");

        Container container = new Container() {

            @Override
            public void paint(Graphics g) {
                super.paint(g);
                g.fillRect(5, 5, 10, 10);
            }

            @Override
            public void paintAll(Graphics g) {
                super.paintAll(g);
                g.fillRect(5, 5, 10, 10);
            }

            @Override
            public void paintComponents(Graphics g) {
                super.paintComponents(g);
                g.fillRect(5, 5, 10, 10);
            }

            @Override
            public void print(Graphics g) {
                super.print(g);
                g.fillRect(5, 5, 10, 10);
            }

            @Override
            public void printComponents(Graphics g) {
                super.printComponents(g);
                g.fillRect(5, 5, 10, 10);
            }

            @Override
            public void update(Graphics g) {
                super.update(g);
                g.fillRect(5, 5, 10, 10);
            }

        };

        Dimension dimension = new Dimension(50, 50);
        container.setPreferredSize(dimension);

        Applet applet = new Applet() {
            @Override
            public void paint(Graphics g) {
                super.paint(g);
                g.fillRect(0, 0, 10, 10);
            }
        };

        container.add(applet);

        applet.setBounds(0, 0, 50, 50);


        frame.add(container);
        frame.pack();
        frame.setVisible(true);

        applet.init();
        applet.start();


    }

}

Каковы шаги, которые необходимо предпринять, чтобы иметь возможность рисовать поверх Applet от его родительского Container?

Вот также скриншот результата выполнения приведенного выше кода

! [введите описание изображения здесь

Если я, однако, изменяю тип Applet на Component, например

Component applet = new Component() {
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 10, 10);
    }
};

правильный результат

введите описание изображения здесь

Ограничения требуемого решения заключаются в том, что я не могу изменить сам Applet, как его устаревший компонент, который предоставляется только как двоичный. Я знаю, что есть решение, сделав модификацию байт-кода, но из-за многих вкусов апплетов это не может быть и речи.

Ответ 1

Почему контейнерный квадрат не отображается

Это происходит из-за области скрепления аппликатора с контейнером. Вы можете увидеть это, если настроить цвет фона апплета и изменить размер:

applet.setBackground(Color.RED);
applet.setBounds(0, 0, 12, 12);

В результате мы можем видеть красную границу (фон апплета) под черным квадратом, нарисованную на апплете:

Частичное перекрытие

С вашим размером апплета и с красным фоном апплета полностью перекрывайте контейнерную область:

Полное перекрытие

Если вы меняете Applet на Component, вы можете видеть черный квадрат из контейнера, потому что класс Component не имеет фона. То есть изменить тип переменной апплета:

Component applet = new Component() {
//...
};
applet.setBackground(Color.RED);

Вы можете видеть изображение как в своем эксперименте:

Component no background

Рисунок сверху апплета

Каковы шаги, которые необходимо предпринять, чтобы иметь возможность рисовать поверх апплета из его родительского контейнера?

Нельзя рисовать поверх апплета, за исключением рисования непосредственно на апплете.

Использование GlassPane не решает эту проблему для апплетов. Я пробовал example из документации

Пример документации

и замените код:

contentPane.add(new JButton("Button 1"));
contentPane.add(new JButton("Button 2"));

в

Applet applet = new Applet() {
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 10, 10);
    }
};
applet.setPreferredSize(new Dimension(100, 25));
applet.setBackground(Color.GREEN);
contentPane.add(applet);

В результате мы можем увидеть апплет, в котором owerlap darawed circle:

Glasspane overlaped

Круг полностью вычерчен, если мы изменим тип переменной апплета на JLanel.

Glasspane draw full circle

Ответ 2

Как Sergey, ваш Applet перекрывает ваш Container, и поскольку у него есть фон, вы не можете увидеть окрашенный прямоугольник на Container, Однако, насколько я знаю, невозможно установить этот фон в прозрачный цвет. Вы можете видеть эти сообщения, здесь и здесь, которые обсуждают тему и возможное решение.

Лучший способ для ситуации, когда вы можете изменить код Applet, но не можете изменить тип Applet

import java.applet.Applet;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

@SuppressWarnings("serial")
public class AppletTest {
    public static void main(String[] args) {
        Frame frame = new Frame("Applet Test");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                frame.dispose();
             }
         });

        int apHeight = 50;
        int apWidth = 50;

        Container container = new Container() {
            @Override
            public void paint(Graphics g) {
                super.paint(g);
                Graphics2D graphs = (Graphics2D) g;
                graphs.setBackground(Color.WHITE);
                graphs.clearRect(0, 0, apWidth, apHeight);
                g.setColor(Color.RED);
                g.fillRect(5, 5, 10, 10);
            }
        };

        Dimension dimension = new Dimension(50, 50);
        container.setPreferredSize(dimension);

        frame.add(container);
        frame.pack();
        frame.setVisible(true);

        BufferedImage bufImage = new BufferedImage(dimension.width, dimension.height, BufferedImage.TYPE_INT_RGB);
        container.paint(bufImage.createGraphics());

        Applet applet = new Applet() {
            @Override
            public void paint(Graphics g) {
                super.paint(g);
                g.drawImage(bufImage, 0, 0, this); 
                g.fillRect(0, 0, 10, 10);
            }
        };

        container.add(applet);
        applet.setBounds(0, 0, apWidth, apHeight);
        applet.init();
    }
}

Результат этого выглядит следующим образом.

Красный и черный квадрат

Изменить для уточненного вопроса
Если вы читаете из файла, лучшим способом было бы объявить ваш апплет, создать образ, а затем нарисовать изображение на апплете. Я сделал пример, который делает двоичный файл, а затем читает объект из него. После этого он рисует фон на нем.

import java.applet.Applet;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

@SuppressWarnings("serial")
public class AppletTest {
    private static void createBinaryApplet() throws IOException {
        Applet applet = new Applet() {
            @Override
            public void paint(Graphics g) {
                super.paint(g);
                g.fillRect(0, 0, 10, 10);
            }
        };

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("applet.dat"));
        oos.writeObject(applet);
        oos.close();
    }

    public static void main(String[] args) {
        Frame frame = new Frame("Applet Test");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                frame.dispose();
             }
         });

        final int prefHeight = 50;
        final int prefWidth = 50;

        Container container = new Container() {
            @Override
            public void paint(Graphics g) {
                super.paint(g);
                Graphics2D graphs = (Graphics2D) g;
                graphs.setBackground(Color.WHITE);
                graphs.clearRect(0, 0, prefWidth, prefHeight);
                g.setColor(Color.RED);
                g.fillRect(5, 5, 10, 10);
            }
        };

        container.setPreferredSize(new Dimension(prefWidth, prefHeight));

        frame.add(container);
        frame.pack();
        frame.setVisible(true);

        BufferedImage bufImage = new BufferedImage(prefWidth, prefHeight, BufferedImage.TYPE_INT_RGB);
        container.paint(bufImage.createGraphics());

        try {
            createBinaryApplet();

            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("applet.dat"));
            Applet applet = (Applet) ois.readObject();
            ois.close();

            container.add(applet);
            applet.setBounds(0, 0, prefWidth, prefHeight);
            applet.init();

            Graphics g = applet.getGraphics();
            g.drawImage(bufImage, 0, 0, applet);
            applet.paint(g);
        } catch(ClassNotFoundException | IOException e) {
            System.out.println("Whoops");
        }
    }
}

Это дает тот же результат, что и раньше.