Java Swing: как получить цвет пикселя JFrame - PullRequest
0 голосов
/ 28 марта 2020

Я пытаюсь получить цвет Swing JFrame для выбранного (x,y) пикселя компонента.

Например, я хочу узнать цвет данного JFrame в их (0,0) точка.

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

Это способ сделать это?

Ответы [ 2 ]

2 голосов
/ 29 марта 2020

Да, это возможно. Используйте функцию getColorAt из приведенного ниже примера:

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class GUI {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(GUI::startUp); 

    }

    private static void startUp() {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1020,760);
        frame.setResizable(false);
        frame.setLayout(new FlowLayout());
        frame.getContentPane().setBackground(Color.BLUE);
        JTextArea jta = new JTextArea(40,40);
        jta.setEditable(false);
        jta.setBackground(Color.WHITE);
        frame.add(new JScrollPane(jta));
        frame.setVisible(true);
        SwingUtilities.invokeLater(() -> printColors(frame));
    }

    private static void printColors(JFrame frm) {
        System.out.println("Color at (1, 1): " + getColorAt(frm, new Point(1, 1)));
        System.out.println("Color at (300, 100): " + getColorAt(frm, new Point(300, 100)));
    }

    public static Color getColorAt(JFrame frm, Point p) {
        Rectangle rect = frm.getContentPane().getBounds();
        BufferedImage img = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_ARGB);
        frm.getContentPane().paintAll(img.createGraphics());
        return new Color(img.getRGB(p.x, p.y), true);
    }
}
1 голос
/ 03 апреля 2020

Я хотел бы сказать (надеясь, что это приведет к повышению производительности), что, возможно, если вы захотите go с подходом Image для этого, было бы хорошо создать изображение размером 1x1 пикселей, а затем переведите созданную графику, чтобы она соответствовала запрошенной точке. А также повторно использовать это изображение для последующих выборок того же Component (или даже GraphicsConfiguration).

Я провел несколько тестов производительности с созданием следующих подходов:

  1. Метод с именем getColorAtClipped, который устанавливает клип созданного Graphics из Image, поэтому не все операции должны быть нарисованы.
  2. Метод с именем getColorAtRelocation, который временно устанавливает местоположение компонента на необходимо определить местоположение, а затем (что на самом деле делает его быстрее) создать изображение размером 1x1 и нарисовать на нем родительский объект. Хотя этот метод на самом деле не является поточно-ориентированным для Swing, так как он требует установки местоположения Component вперед и назад. Он также вызывает printAll для родительского Container, что означает, что нужно нарисовать больше Component s.
  3. Затем метод с именем getColorAtTranslation, который создает изображение 1x1 и переводит его экземпляр Graphics так, чтобы требуемое местоположение будет нарисовано в точке (0,0), которая является единственным пикселем на изображении. Этот метод оказался самым быстрым для всех трех первых методов.
  4. Тогда почему бы не использовать те же ресурсы для последующих выборок? ... Так что это приводит меня к окончательному подходу: классу, содержащему все необходимые Ресурсы, которые участвуют в выборке: тот, который называется ComponentColorSampler в следующем коде

Код тестирования:

В этом разделе приведен код для проверки производительности вышеуказанных подходов. Если это не правильно, дайте мне знать в комментариях, но имейте в виду, что я использовал каждый метод для примерно 3 миллионов выборок в надежде, что задержки с обеспечением будут уменьшены. На каждый миллион образцов тестового метода я печатал несколько таймингов, а затем перезапускал процесс для тестирования еще одного миллиона, вплоть до 3.

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import java.util.function.IntBinaryOperator;
import java.util.function.Supplier;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Main {

    public static Color getColorAtClipped(final Component comp, final Point p) {
        final BufferedImage bimg = comp.getGraphicsConfiguration().createCompatibleImage(comp.getWidth(), comp.getHeight());
        final Graphics2D g2d = (Graphics2D) bimg.createGraphics();
        g2d.setClip(p.x, p.y, 1, 1);
        comp.printAll(g2d);
        g2d.dispose();
        final Color c = new Color(bimg.getRGB(p.x, p.y), true);
        bimg.flush();
        return c;
    }

    public static Color getColorAtRelocation(final Component comp, final Point p) {
        final Point loc = comp.getLocation();
        final BufferedImage bimg = comp.getGraphicsConfiguration().createCompatibleImage(1, 1);
        comp.setLocation(loc.x - p.x, loc.y - p.y);
        final Graphics2D g2d = (Graphics2D) bimg.createGraphics();
        //g2d.setClip(0, 0, 1, 1);
        comp.getParent().printAll(g2d);
        comp.setLocation(loc);
        g2d.dispose();
        final Color c = new Color(bimg.getRGB(0, 0), true);
        bimg.flush();
        return c;
    }

    public static Color getColorAtTranslation(final Component comp, final Point p) {
        final BufferedImage bimg = comp.getGraphicsConfiguration().createCompatibleImage(1, 1);
        final Graphics2D g2d = (Graphics2D) bimg.createGraphics();
        g2d.translate(-p.x, -p.y);
        //g2d.setClip(0, 0, 1, 1);
        comp.printAll(g2d);
        g2d.dispose();
        final Color c = new Color(bimg.getRGB(0, 0), true);
        bimg.flush();
        return c;
    }

    public static class ComponentColorSampler<C extends Component> implements AutoCloseable, IntBinaryOperator, Supplier<C> {
        private final C comp;
        private final BufferedImage bimg;
        private final Graphics2D g2d;
        private int x, y;

        public ComponentColorSampler(final C comp) {
            this.comp = Objects.requireNonNull(comp);
            bimg = comp.getGraphicsConfiguration().createCompatibleImage(1, 1);
            g2d = bimg.createGraphics();
            //g2d.setClip(0, 0, 1, 1);
            x = y = 0;
        }

        @Override
        public C get() {
            return comp;
        }

        @Override
        public int applyAsInt(final int x, final int y) {
            g2d.clearRect(0, 0, 1, 1);
            g2d.translate(this.x - x, this.y - y);
            this.x = x;
            this.y = y;
            comp.printAll(g2d);
            return bimg.getRGB(0, 0);
        }

        public Color sample(final int x, final int y) {
            return new Color(applyAsInt(x, y), true);
        }

        @Override
        public void close() {
            g2d.dispose();
            bimg.flush();
        }
    }

    public static class DrawPanel extends JPanel {
        private final int x, y;
        private Color c;

        public DrawPanel(final int x, final int y) {
            this.x = x;
            this.y = y;
            c = Color.BLUE;
        }

        @Override
        protected void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.setColor(c);
            g.fillRect(x, y, 1, 1);
        }

        public void setColor(final Color c) {
            this.c = Objects.requireNonNull(c);
            paintImmediately(0, 0, getWidth(), getHeight()); //Not sure yet.
            repaint(); //Just to be sure now.
        }
    }

    //@SuppressWarnings("SleepWhileInLoop")
    public static boolean checkValid(final DrawPanel dp, final Supplier<Color> sampler) throws InterruptedException, InvocationTargetException {
        for (final Color c: new Color[]{Color.BLUE, Color.RED, Color.BLACK, Color.WHITE, Color.BLACK, Color.CYAN}) {
            SwingUtilities.invokeAndWait(() -> dp.setColor(c));
            Thread.sleep(250); //Let it some time to change (not sure if needed).
            if (!Objects.equals(c, sampler.get()))
                return false;
        }
        return true;
    }

    public static long checkTime(final Supplier<Color> sampler) {
        final long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000; ++i)
            sampler.get();
        return System.currentTimeMillis() - start;
    }

    public static void main(final String[] args) throws InterruptedException, InvocationTargetException {

        final Point p = new Point(100, 100);

        final DrawPanel contents = new DrawPanel(p.x, p.y);

        contents.setPreferredSize(new Dimension(200, 200));

        final JFrame frame = new JFrame("Printed!");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(contents);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);

        final ComponentColorSampler<Component> sampler = new ComponentColorSampler<>(contents);

        final Supplier<Color> clipped = () -> getColorAtClipped(contents, p),
                              relocation = () -> getColorAtRelocation(contents, p),
                              translation = () -> getColorAtTranslation(contents, p),
                              samplerSampler = () -> sampler.sample(p.x, p.y);

        System.out.println("#### Validity checks...");
        for (int i = 0; i < 3; ++i) {
            System.out.println("Batch " + (i + 1) + ':');
            System.out.println("> Clipped: " + checkValid(contents, clipped) + '.');
            System.out.println("> Relocation: " + checkValid(contents, relocation) + '.');
            System.out.println("> Translation: " + checkValid(contents, translation) + '.');
            System.out.println("> Sampler: " + checkValid(contents, samplerSampler) + '.');
        }

        System.out.println("#### Timings...");
        for (int i = 0; i < 3; ++i) {
            System.out.println("Batch " + (i + 1) + ':');
            System.out.println("> Clipped: " + checkTime(clipped) + "ms.");
            System.out.println("> Relocation: " + checkTime(relocation) + "ms.");
            System.out.println("> Translation: " + checkTime(translation) + "ms.");
            System.out.println("> Sampler: " + checkTime(samplerSampler) + "ms.");
        }

        System.out.println("#### Done.");
    }
}

Результаты:

Вывод программы:

#### Validity checks...
Batch 1:
> Clipped: true.
> Relocation: true.
> Translation: true.
> Sampler: true.
Batch 2:
> Clipped: true.
> Relocation: true.
> Translation: true.
> Sampler: true.
Batch 3:
> Clipped: true.
> Relocation: true.
> Translation: true.
> Sampler: true.
#### Timings...
Batch 1:
> Clipped: 34668ms.
> Relocation: 22737ms.
> Translation: 5416ms.
> Sampler: 1152ms.
Batch 2:
> Clipped: 38521ms.
> Relocation: 22805ms.
> Translation: 5451ms.
> Sampler: 1156ms.
Batch 3:
> Clipped: 38275ms.
> Relocation: 22864ms.
> Translation: 5415ms.
> Sampler: 1163ms.
#### Done.

Таким образом, первый подход составляет около 37 секунд для миллиона выборок, второй подход - около 22, третий 5 и, наконец, последний подход составляет чуть более 1 секунды (для миллиона выборок). Так что ComponentColorSampler является самой быстрой реализацией в этих тестах (около 865 выборок в миллисекунду) и работает на любом Component. Проверка достоверности означает лишь некоторую проверку того, что выбранный цвет имеет правильное значение.

Примечание : тесты не являются Swing / Thread-безопасными, но показывают, какова будет производительность, если вы их правильно используете (например, выполнение выборок в потоке диспетчеризации событий).

...