簡體   English   中英

Java Swing:如何獲取 JFrame 像素的顏色

[英]Java Swing: how to get the color of a pixel of a JFrame

我正在嘗試為組件的選定(x,y)像素獲取 Swing JFrame 的顏色。

例如,我想知道給定JFrame(0,0)點的顏色。

原因是我的組件是一個部分透明的覆蓋層,下面有一個JPanel 對於不透明的像素,鼠標事件應由覆蓋層處理。 對於透明的像素,鼠標事件應該轉發到下面的JPanel

這是一種方法嗎?

是的,這是可能的。 使用以下示例中的函數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);
    }
}

我想說(希望這會帶來更好的性能),如果您願意為此使用Image方法,那么創建一個尺寸為 1x1 像素的圖像然后轉換其創建的圖形以匹配要求的點。 並且還將此圖像重用於同一Component (甚至GraphicsConfiguration )的后續采樣。

我通過創建以下方法進行了一些性能測試:

  1. 一種名為getColorAtClipped的方法,它設置創建的Image Graphics的剪輯,因此不必繪制所有操作。
  2. 一個名為getColorAtRelocation的方法將組件的位置臨時設置在需要采樣的位置,然后(實際上使它更快)創建一個尺寸為 1x1 的圖像並在其上繪制父級。 盡管這個方法對於 Swing 來說並不是真正的線程安全,因為它需要來回設置Component的位置。 它還為父Container調用printAll ,這意味着要繪制更多Component
  3. 然后一個名為getColorAtTranslation的方法創建一個 1x1 圖像並轉換其Graphics實例,以便實際繪制所需的位置(0,0),這是圖像中真正的唯一像素。 事實證明,對於前 3 種方法來說,這種方法是最快的。
  4. 那么為什么不為后續樣本重用相同的資源?...所以這導致我采用最后一種方法:包含參與采樣的所有必需資源的類:在以下代碼中稱為ComponentColorSampler的類

測試代碼:

本節后面是測試上述方法性能的代碼。 如果不正確,請在評論中告訴我,但請注意,我對每種方法運行了大約 300 萬次采樣,希望可以減少附帶延遲。 測試方法的每百萬個樣本,我打印一些時間,然后重新啟動該過程以測試另外一百萬個,最多 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/線程安全的,但會表明如果您正確使用它們會帶來什么性能(例如在事件調度線程上執行采樣)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM