CompositeTest.java Source code

Java tutorial

Introduction

Here is the source code for CompositeTest.java

Source

/*
   This program is a part of the companion code for Core Java 8th ed.
   (http://horstmann.com/corejava)
    
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
    
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
    
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * This program demonstrates the Porter-Duff composition rules.
 * @version 1.03 2007-08-16
 * @author Cay Horstmann
 */
public class CompositeTest {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new CompositeTestFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}

/**
 * This frame contains a combo box to choose a composition rule, a slider to change the source alpha
 * channel, and a component that shows the composition.
 */
class CompositeTestFrame extends JFrame {
    public CompositeTestFrame() {
        setTitle("CompositeTest");
        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

        canvas = new CompositeComponent();
        add(canvas, BorderLayout.CENTER);

        ruleCombo = new JComboBox(new Object[] { new Rule("CLEAR", "  ", "  "), new Rule("SRC", " S", " S"),
                new Rule("DST", "  ", "DD"), new Rule("SRC_OVER", " S", "DS"), new Rule("DST_OVER", " S", "DD"),
                new Rule("SRC_IN", "  ", " S"), new Rule("SRC_OUT", " S", "  "), new Rule("DST_IN", "  ", " D"),
                new Rule("DST_OUT", "  ", "D "), new Rule("SRC_ATOP", "  ", "DS"), new Rule("DST_ATOP", " S", " D"),
                new Rule("XOR", " S", "D "), });
        ruleCombo.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                Rule r = (Rule) ruleCombo.getSelectedItem();
                canvas.setRule(r.getValue());
                explanation.setText(r.getExplanation());
            }
        });

        alphaSlider = new JSlider(0, 100, 75);
        alphaSlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent event) {
                canvas.setAlpha(alphaSlider.getValue());
            }
        });
        JPanel panel = new JPanel();
        panel.add(ruleCombo);
        panel.add(new JLabel("Alpha"));
        panel.add(alphaSlider);
        add(panel, BorderLayout.NORTH);

        explanation = new JTextField();
        add(explanation, BorderLayout.SOUTH);

        canvas.setAlpha(alphaSlider.getValue());
        Rule r = (Rule) ruleCombo.getSelectedItem();
        canvas.setRule(r.getValue());
        explanation.setText(r.getExplanation());
    }

    private CompositeComponent canvas;
    private JComboBox ruleCombo;
    private JSlider alphaSlider;
    private JTextField explanation;
    private static final int DEFAULT_WIDTH = 400;
    private static final int DEFAULT_HEIGHT = 400;
}

/**
 * This class describes a Porter-Duff rule.
 */
class Rule {
    /**
     * Constructs a Porter-Duff rule
     * @param n the rule name
     * @param pd1 the first row of the Porter-Duff square
     * @param pd2 the second row of the Porter-Duff square
     */
    public Rule(String n, String pd1, String pd2) {
        name = n;
        porterDuff1 = pd1;
        porterDuff2 = pd2;
    }

    /**
     * Gets an explanation of the behavior of this rule.
     * @return the explanation
     */
    public String getExplanation() {
        StringBuilder r = new StringBuilder("Source ");
        if (porterDuff2.equals("  "))
            r.append("clears");
        if (porterDuff2.equals(" S"))
            r.append("overwrites");
        if (porterDuff2.equals("DS"))
            r.append("blends with");
        if (porterDuff2.equals(" D"))
            r.append("alpha modifies");
        if (porterDuff2.equals("D "))
            r.append("alpha complement modifies");
        if (porterDuff2.equals("DD"))
            r.append("does not affect");
        r.append(" destination");
        if (porterDuff1.equals(" S"))
            r.append(" and overwrites empty pixels");
        r.append(".");
        return r.toString();
    }

    public String toString() {
        return name;
    }

    /**
     * Gets the value of this rule in the AlphaComposite class
     * @return the AlphaComposite constant value, or -1 if there is no matching constant.
     */
    public int getValue() {
        try {
            return (Integer) AlphaComposite.class.getField(name).get(null);
        } catch (Exception e) {
            return -1;
        }
    }

    private String name;
    private String porterDuff1;
    private String porterDuff2;
}

/**
 * This component draws two shapes, composed with a composition rule.
 */
class CompositeComponent extends JComponent {
    public CompositeComponent() {
        shape1 = new Ellipse2D.Double(100, 100, 150, 100);
        shape2 = new Rectangle2D.Double(150, 150, 150, 100);
    }

    public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;

        BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D gImage = image.createGraphics();
        gImage.setPaint(Color.red);
        gImage.fill(shape1);
        AlphaComposite composite = AlphaComposite.getInstance(rule, alpha);
        gImage.setComposite(composite);
        gImage.setPaint(Color.blue);
        gImage.fill(shape2);
        g2.drawImage(image, null, 0, 0);
    }

    /**
     * Sets the composition rule.
     * @param r the rule (as an AlphaComposite constant)
     */
    public void setRule(int r) {
        rule = r;
        repaint();
    }

    /**
     * Sets the alpha of the source
     * @param a the alpha value between 0 and 100
     */
    public void setAlpha(int a) {
        alpha = (float) a / 100.0F;
        repaint();
    }

    private int rule;
    private Shape shape1;
    private Shape shape2;
    private float alpha;
}