3

I would like to achieve the following for my swing project,enter image description here

I was able to get this by extending a JPanel and and using JLayer. enter image description here

I event tried using AlphaComposite but it didn't work.

Edit1: I think JTable or JViewport might help me to get what I want but I don't know how to use them.

Edit2: Updated the SSCCE, thank you trashgod for the suggestion. I have made use of the Scalr library because after using getScaledInstance method of Image class, if i tried to use the getSubImage method of BufferedImage,the following exception is thrown:

java.lang.ClassCastException: sun.awt.image.ToolkitImage cannot be cast to java.awt.image.BufferedImage

since the Image generated by getScaledInstance method is a instance of ToolkitImage so, it cannot be cast into a BufferedImage.

If you don't want to use the Scalr library,you can use the code suggested in this post to scale the BufferedImage and than use getSubImage method.

enter image description here

SCSE.java

import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.util.Random;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import org.imgscalr.Scalr;

public class SCSE {

    private JFrame mainFrame;
    private JPanel mainPanel;
    private GridView gridView;
    private JButton imgBtn, shuffleBtn;
    private int gridX = -1, gridY = -1, gridWidth = -1, gridHeight = -1;
    private boolean isGridEmpty = false;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            SCSE sc = new SCSE();

            sc.createGUI();

        });
    }

    private void createGUI() {

        mainFrame = new JFrame();
        mainFrame.setSize(500, 500);
        mainFrame.setResizable(false);
        mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        mainPanel = new JPanel(new BorderLayout());

        gridView = new GridView();

        imgBtn = new JButton("Get-Image");
        shuffleBtn = new JButton("Shuffle-ViewPort");
        imgBtn.addActionListener((ActionEvent evt) -> {
            try {
                gridView.setImage(ImageIO.read(new URL("http://www.keenthemes.com/preview/metronic/theme/assets/global/plugins/jcrop/demos/demo_files/image1.jpg")));
            } catch (IOException ex) {
                System.out.println(ex);
            }
        });

        shuffleBtn.addActionListener((ActionEvent evt) -> {
            gridView.startShuffle();
        });

        mainPanel.add(gridView.getComponent(), BorderLayout.CENTER);
        mainPanel.add(imgBtn, BorderLayout.NORTH);
        mainPanel.add(shuffleBtn, BorderLayout.SOUTH);
        mainFrame.add(mainPanel);
        mainFrame.setLocationRelativeTo(null);
        mainFrame.setVisible(true);
    }

    class GridView {

        private Random shuffleRandom;
        private RegisterUI layerUi = null;
        private JLayer<JPanel> gridLayer = null;
        private ImagePanel mainPanel = null;
        private int gridNos = 21;   //number of grids
        int digit[];
        private int viewportDimensions = 4; //no of rows and columns in viewport
        private JLabel gridLabel[][] = new JLabel[gridNos][gridNos];
        private int gridX = -1, gridY = -1, gridWidth = -1, gridHeight = -1;
        private boolean isGridInitialized = false;

        public GridView() {
            initPersuasive();
            initPanel();
            initGrids();
        }

        private void initPanel() {
            mainPanel = new ImagePanel();
            mainPanel.setLayout(new GridLayout(gridNos, gridNos, 0, 0));                 //creates layout to place labels in grid form
            layerUi = new RegisterUI();
            gridLayer = new JLayer<>(mainPanel, layerUi);
        }

        private void initGrids() {
            for (int i = 0; i < gridNos; i++) {
                for (int j = 0; j < gridNos; j++) {
                    gridLabel[i][j] = new JLabel();
                    gridLabel[i][j].setOpaque(false);
                    gridLabel[i][j].setName("" + (i + 1));         // Since for loop index is 0 to 80, we add 1 to the name to make it 1 to 81
                    mainPanel.add(gridLabel[i][j]);              //add it to mainPanel
                }
            }
        }

        private void initPersuasive() {
            shuffleRandom = new Random();
            digit = new int[2];

        }

        private void random() {

            digit[0] = shuffleRandom.nextInt(gridNos - viewportDimensions);
            digit[1] = shuffleRandom.nextInt(gridNos - viewportDimensions);
        }

        public void startShuffle() {
            random();
            int x = gridLabel[digit[0]][digit[1]].getX();
            int y = gridLabel[digit[0]][digit[1]].getY();
            layerUi.placeViewport(x, y);
        }

        public void stopShuffle() {
            layerUi.removeViewPort();
        }

        public void setupGridView() {

            gridX = gridLabel[0][0].getX();
            gridY = gridLabel[0][0].getY();
            gridWidth = gridLabel[0][0].getWidth();
            gridHeight = gridLabel[0][0].getHeight();
            mainPanel.setValues(gridX, gridY);
            layerUi.setViewSize(gridWidth * viewportDimensions, gridHeight * viewportDimensions);

        }

        public void setImage(BufferedImage img) {
            if (!isGridInitialized) {
                setupGridView();
                isGridInitialized = true;
            }
            BufferedImage sendImg = Scalr.resize(img, Scalr.Mode.FIT_EXACT, gridWidth * gridNos, gridHeight * gridNos, Scalr.OP_ANTIALIAS);
            layerUi.setupViewport(img);
            mainPanel.paintImage(img);
        }

        public JLayer<JPanel> getComponent() {
            return gridLayer;
        }

    }

    class RegisterUI extends LayerUI<JPanel> {

        private int viewX, viewY, viewWidth, viewHeight;
        private boolean shuffleIsRunning = false;
        private BufferedImage viewportImage = null;

        private void drawPCCP(Graphics g, int w, int h) {
            Graphics2D g2 = ((Graphics2D) g);
            Color c = new Color(1.0f, 1.0f, 1.0f, 0.7f);
            g2.setPaint(c);
            g2.fillRect(0, 0, w, h);
            BufferedImage highlightGrid = Scalr.pad(Scalr.crop(viewportImage, viewX, viewY, viewWidth, viewHeight), 2, Color.BLACK, Scalr.OP_ANTIALIAS);
            g2.drawImage(highlightGrid, viewX, viewY, null);
            g2.dispose();
        }

        public void paint(Graphics g, JComponent c) {
            super.paint(g, c);
            int w = c.getWidth();
            int h = c.getHeight();
            if (shuffleIsRunning) {
                drawPCCP(g, w, h);
            }
        }

        public void setupViewport(BufferedImage bi) {
            viewportImage = bi;
        }

        public void setViewSize(int w, int h) {
            viewWidth = w;
            viewHeight = h;
        }

        public void placeViewport(int x, int y) {
            viewX = x;
            viewY = y;
            if (!shuffleIsRunning) {
                shuffleIsRunning = true;
            }
            firePropertyChange("shuffleui", 0, 1);

        }

        public void removeViewPort() {
            if (!shuffleIsRunning) {
                return;
            }
            viewX = 0;
            viewY = 0;
            viewWidth = 0;
            viewHeight = 0;
            shuffleIsRunning = false;
            firePropertyChange("shuffleui", 0, 1);
        }

        @Override
        public void applyPropertyChange(PropertyChangeEvent evt, JLayer<? extends JPanel> l) {
            if ("disableui".equals(evt.getPropertyName()) || "shuffleui".equals(evt.getPropertyName())) {
                l.repaint();
            }
        }

    }

    class ImagePanel extends JPanel {

        private BufferedImage displayImage = null;
        private int x, y;

        public void setValues(int x, int y) {
            this.x = x;
            this.y = y;

        }

        public void paintImage(BufferedImage bi) {
            System.out.print(bi);
            displayImage = bi;
            repaint(); // repaint calls paintComponent method internally
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(displayImage, x, y, this);   // To Paint the image on the panel

        }
    }
}
Community
  • 1
  • 1
Jaymit Desai
  • 153
  • 1
  • 2
  • 11
  • I could do that but my application also requires a button to change viewport position randomly and the image is being set via the ImagePanel class, so that would force me to send an Instance of the Image to LayerUI class each time I change the Image. – Jaymit Desai Jul 11 '15 at 10:53
  • @JaymitDesai: `ImagePanel` will need access to both images, muted and original. – trashgod Jul 11 '15 at 14:34
  • @trashgod thanks for the help, I went with the first solution you provided. I'll soon update my SSCCE. I'd like to mark your answer as the right one but since you have commented I am unable to do so. – Jaymit Desai Jul 11 '15 at 19:35
  • @JaymitDesai: Glad it helped; more below. – trashgod Jul 11 '15 at 20:01

1 Answers1

2

Instead of using AlphaComposite directly, as shown here, try RescaleOp to alter the image's color/alpha bands, as shown in this example. This will allow you to mute the tone of the entire image as desired. Copy a portion of the original image using getSubimage() to restore the highlight.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045