esQmo_
esQmo_

Reputation: 1709

How to set different colors to lines depending on path on 2D grid

I have this simple program that plots lines from cell to cell which form a path. I have two groups of paths: one formed by red cells and another formed by blue cells. I'm just able to set one color at a time and it's applying to both groups.

Now what I want to do is set the color of lines to match the cell's color, each group with it own line color. I use custom painting to draw the lines on glassPane with the below code:

 @Override
    public void paintComponent(Graphics g) {    
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.RED); //Lines' Color is set here
        g2d.setStroke(new BasicStroke(3));

        for(List<JLabel> line : lines) {

            for(int i=0; i <(line.size()) ; i++) {
                JLabel label1 = line.get(i);
                int n = (i == (line.size()-1)) ? 0: i+1;
                JLabel label2 = line.get(n);
                g2d.draw(new Line2D.Float(getCenter(label1), getCenter(label2)));
            }
        }

        g2d.dispose();
    }

Screenshot of the result of the above code. A grid contains four red dots connected by red lines and four blue dots connected by red lines.

How can I achieve this? I'm thinking about making a variable color which depends to each cell group, but didn't find how to do this.

Below is the an example you can test (note: I removed all import statements):

public class Example extends JPanel {

    enum Token {VIDE, CERCLE_BLEU, CERCLE_ROUGE}

    private static final int ICON_W = 21;
    private JLabel[][] grid;
    private Map<Token, Icon> iconMap = new EnumMap<>(Token.class);

    List<JLabel> redCels = new ArrayList<>();
    List<JLabel> blueCells  = new ArrayList<>();
    List<List<JLabel>> paths = new ArrayList<>();

    Example(int rows, int cols) {

        setLayout(new GridLayout(rows, cols, 1, 1));
        setBorder(BorderFactory.createLineBorder(Color.BLACK));
        setBackground(Color.BLACK);

        iconMap.put(Token.VIDE, createIcon(new Color(0, 0, 0, 0)));
        iconMap.put(Token.CERCLE_BLEU, createIcon(Color.BLUE));
        iconMap.put(Token.CERCLE_ROUGE, createIcon(Color.RED));
        createGrid(rows, cols);
        setTestData();
    }

    private Icon createIcon(Color color) {

        BufferedImage img = new BufferedImage(ICON_W, ICON_W, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(color);
        g2.fillOval(1, 1, ICON_W - 2, ICON_W - 2);
        g2.dispose();

        return new ImageIcon(img);
    }

    void createGrid(int rows, int cols) {

        grid = new JLabel[rows][cols];
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[r].length; c++) {
                grid[r][c] = new JLabel(iconMap.get(Token.VIDE));
                grid[r][c].setOpaque(true);
                grid[r][c].setBackground(Color.WHITE);
                grid[r][c].setPreferredSize(new Dimension(ICON_W, ICON_W));
                add(grid[r][c]);
            }
        }
    }

    void setTestData() {

        //test data
        set(11, 3, Token.CERCLE_ROUGE);
        set(10, 2, Token.CERCLE_ROUGE);
        set(9, 3, Token.CERCLE_ROUGE);
        set(10, 4, Token.CERCLE_ROUGE);

        set(8, 13, Token.CERCLE_BLEU);
        set(9, 12, Token.CERCLE_BLEU);
        set(10, 13, Token.CERCLE_BLEU);
        set(9, 14, Token.CERCLE_BLEU);

        paths.add(redCels); paths.add(blueCells);
    }

    void set(int row, int col, Token token) {

        grid[row][col].setIcon(iconMap.get(token));

        if(token == Token.CERCLE_ROUGE) {
            redCels.add(grid[row][col]);
        }else {
            blueCells.add(grid[row][col]);
        }
    }

    private List<List<JLabel>> getPahs() {
        return paths;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {

                JFrame frame = new JFrame("TEST CASE");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                Example example = new Example(20, 20);
                frame.add(example);
                DrawLines glassPane = new DrawLines(example.getPahs());
                frame.setGlassPane(glassPane);
                frame.getGlassPane().setVisible(true);
                frame.setLocationRelativeTo(null);
                frame.pack();
                frame.setResizable(false);
                frame.setVisible(true);
            }
        });
    }
}

//used as glass pane to draw lines
class DrawLines extends JPanel {


    private List<List<JLabel>> lines;
    DrawLines(List<List<JLabel>> lines) {

        this.lines = lines;
        setOpaque(false);
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.RED);
        g2d.setStroke(new BasicStroke(3));

        for(List<JLabel> line : lines) {

            for(int i=0; i <(line.size()) ; i++) {
                JLabel label1 = line.get(i);
                int n = (i == (line.size()-1)) ? 0: i+1;
                JLabel label2 = line.get(n);
                g2d.draw(new Line2D.Float(getCenter(label1), getCenter(label2)));
            }
        }

        g2d.dispose();
    }

    private Point getCenter(JComponent comp) {
        int x = comp.getX()+ (comp.getWidth()/2);
        int y = comp.getY() + (comp.getHeight()/2);
        return new Point(x,y);
    }
}

Upvotes: 2

Views: 1478

Answers (1)

c0der
c0der

Reputation: 18792

I suggest the following approach :
Modify Token enum so it holds color and icon information:

enum Token {

    VIDE (Color.WHITE), CERCLE_BLEU (Color.BLUE), CERCLE_ROUGE(Color.RED);

    private static final int ICON_W = 21;
    public Color color;
    public Icon icon;

    Token(Color color) {

        this.color = color;
        icon = createIcon(color);
    }

    private Icon createIcon(Color color) {

        BufferedImage img = new BufferedImage(ICON_W, ICON_W, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(color);
        g2.fillOval(1, 1, ICON_W - 2, ICON_W - 2);
        g2.dispose();

        return new ImageIcon(img);
    }
}

Subclass JLabel to create a JLabelthat can be initialized using a Token :

class TLabel extends JLabel{

    Token token;
    TLabel(Token token) {
        setToken(token);
    }

    void setToken(Token token) {

        this.token = token;
        setIcon(token.icon);
        setPreferredSize(new Dimension(
                token.icon.getIconWidth(), token.icon.getIconHeight()));
    }
    Token getToken() {
        return token;
    }

    Color getColor() {
        return token.color;
    }
}


Note that an instance of TLabel holds Token and color information, has the appropriate icon and the right prefered size.
Use TLabel in you application as follows:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class Example extends JPanel {

    private TLabel[][] grid;

    List<TLabel> redCels = new ArrayList<>();
    List<TLabel> blueCells  = new ArrayList<>();
    List<List<TLabel>> paths = new ArrayList<>();

    Example(int rows, int cols) {

        setLayout(new GridLayout(rows, cols, 1, 1));
        setBorder(BorderFactory.createLineBorder(Color.BLACK));
        setBackground(Color.BLACK);
        createGrid(rows, cols);
        setTestData();
    }

    void createGrid(int rows, int cols) {

        grid = new TLabel[rows][cols];
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[r].length; c++) {
                grid[r][c] = new TLabel(Token.VIDE);
                grid[r][c].setOpaque(true);
                grid[r][c].setBackground(Color.WHITE);
                add(grid[r][c]);
            }
        }
    }

    void setTestData() {

        //test data
        set(11, 3, Token.CERCLE_ROUGE);
        set(10, 2, Token.CERCLE_ROUGE);
        set(9, 3, Token.CERCLE_ROUGE);
        set(10, 4, Token.CERCLE_ROUGE);

        set(8, 13, Token.CERCLE_BLEU);
        set(9, 12, Token.CERCLE_BLEU);
        set(10, 13, Token.CERCLE_BLEU);
        set(9, 14, Token.CERCLE_BLEU);

        paths.add(redCels); paths.add(blueCells);
    }

    void set(int row, int col, Token token) {

        grid[row][col].setToken(token);

        if(token == Token.CERCLE_ROUGE) {
            redCels.add(grid[row][col]);
        }else {
            blueCells.add(grid[row][col]);
        }
    }

    private List<List<TLabel>> getPahs() {
        return paths;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {

                JFrame frame = new JFrame("TEST CASE");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                Example example = new Example(20, 20);
                frame.add(example);
                DrawLines glassPane = new DrawLines(example.getPahs());
                frame.setGlassPane(glassPane);
                frame.getGlassPane().setVisible(true);
                frame.setLocationRelativeTo(null);
                frame.pack();
                frame.setResizable(false);
                frame.setVisible(true);
            }
        });
    }


}

enum Token {

    VIDE (Color.WHITE), CERCLE_BLEU (Color.BLUE), CERCLE_ROUGE(Color.RED);

    private static final int ICON_W = 21;
    public Color color;
    public Icon icon;

    Token(Color color) {

        this.color = color;
        icon = createIcon(color);
    }

    private Icon createIcon(Color color) {

        BufferedImage img = new BufferedImage(ICON_W, ICON_W, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(color);
        g2.fillOval(1, 1, ICON_W - 2, ICON_W - 2);
        g2.dispose();

        return new ImageIcon(img);
    }
}

class TLabel extends JLabel{

    Token token;
    TLabel(Token token) {
        setToken(token);
    }

    void setToken(Token token) {

        this.token = token;
        setIcon(token.icon);
        setPreferredSize(new Dimension(
                token.icon.getIconWidth(), token.icon.getIconHeight()));
    }
    Token getToken() {
        return token;
    }

    Color getColor() {
        return token.color;
    }
}

//used as glass pane to draw lines
class DrawLines extends JPanel {

    private List<List<TLabel>> lines;
    DrawLines(List<List<TLabel>> lines) {

        this.lines = lines;
        setOpaque(false);
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setStroke(new BasicStroke(3));

        for(List<TLabel> line : lines) {

            //use color information from TLabel
            //the whole path is of the same color so do it one per path
            g2d.setColor(line.get(0).getColor());

            for(int i=0; i <(line.size()) ; i++) {
                TLabel label1 = line.get(i);
                int n = (i == (line.size()-1)) ? 0: i+1;
                TLabel label2 = line.get(n);
                g2d.draw(new Line2D.Float(getCenter(label1), getCenter(label2)));
            }
        }

        g2d.dispose();
    }


Note that for setting the line color, you simply get the color from a TLabel like: g2d.setColor(tLabel.getColor());

enter image description here

Upvotes: 3

Related Questions