Is there a way to duplicate a generalpath, mirror it, and move it?
I was creating a cartoon character, and I realized her left side of the hair, body is the same as the right side.
For example:
I have done the left part of her hair and body and the code is very long.
So to finish the character faster, I thought maybe there is a way of duplicating the code, flip it horizontally and move it to the right position.
I have this sample code:
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
GeneralPath body, mirror;
body = new GeneralPath();
mirror = new GeneralPath();
body.moveTo(205.5,97);
body.lineTo(207,132);
body.quadTo(193,105, 197,80);
body.curveTo(188,98, 156,127, 159,167);
body.quadTo(163,174, 166,184);
body.curveTo(173,196, 193,210, 213,208);
body.curveTo(247,208, 267,196, 274,184);
g2d.setPaint(new Color(255,251,223));
g2d.fill(body);
g2d.setPaint(Color.black);
g2d.draw(body);
//mirror = duplicate(body)
//flip(mirror)
//mirror.moveTo(x,y)
//..something like that
}
You can use a transformation. See Transforming Shapes, Text, and Images tutorial for some examples.
Here is an example based on the original code in the question:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JPanel panel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
final Graphics2D g2d = (Graphics2D) g.create();
try {
GeneralPath body, mirror;
body = new GeneralPath();
mirror = new GeneralPath();
body.moveTo(205.5, 97);
body.lineTo(207, 132);
body.quadTo(193, 105, 197, 80);
body.curveTo(188, 98, 156, 127, 159, 167);
body.quadTo(163, 174, 166, 184);
body.curveTo(173, 196, 193, 210, 213, 208);
body.curveTo(247, 208, 267, 196, 274, 184);
g2d.setPaint(new Color(255, 251, 223));
g2d.fill(body);
g2d.setPaint(Color.black);
g2d.draw(body);
AffineTransform tx = AffineTransform
.getScaleInstance(-1, 1);
tx.translate(-274 * 2, 0);
g2d.transform(tx);
g2d.setPaint(Color.YELLOW);
g2d.fill(body);
g2d.setPaint(Color.BLACK);
g2d.draw(body);
} finally {
g2d.dispose();
}
}
};
JOptionPane.showMessageDialog(null, panel, "Mirror",
JOptionPane.INFORMATION_MESSAGE);
}
});
}
}
The result looks like this:
Related
I am trying to draw a ring/partial ring using arc's.
But I need the middle of the partial ring/ring to be transparent and show whats behind it. Since I am using an arc and spinning it, is there a way to subtract away the inner portion of each arc and leave only the end at the desired thickness which will be spun to create the ring?
This is my code so far: I have the arcs working, but I am only simulating the ring by layering over each one with a couple circles, I need to actually subtract out the area of each circle from each arc.
Not sure how to do that to achieve transparency in the center. If there is a better way to do this please let me know, this is going to be a custom progress bar.
public class JCustomProgressBar extends JComponent{
private final Dimension SIZE = new Dimension( 50, 50 );
public JCustomProgressBar() {
super();
this.setVisible(true);
System.out.println("CAlled");
}
int progress = 1;
public void updateProgress (int progress){
this.progress = progress;
}
#Override
public void paintComponent (Graphics g){
super.paintComponent(g);
System.out.println("called");
Graphics2D g2D = (Graphics2D) g.create();
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2D.translate(this.getWidth()/2, this.getHeight()/2);
g2D.rotate(Math.toRadians(270));
Arc2D.Float arc = new Arc2D.Float (Arc2D.PIE);
Ellipse2D circle = new Ellipse2D.Float(0, 0, 80, 80);
arc.setFrameFromCenter (new Point(0,0), new Point (90, 90));
circle.setFrameFromCenter(new Point(0,0), new Point (80, 80));
arc.setAngleExtent(-progress*360/100);
g2D.setColor(new Color(120,192,0));
g2D.draw(arc);
g2D.fill(arc);
g2D.setColor(this.getParent().getBackground());
g2D.draw(circle);
g2D.fill(circle);
arc.setFrameFromCenter (new Point(0,0), new Point (75, 75));
arc.setAngleExtent(-90*360/100);
g2D.setColor(new Color(197,228,146));
g2D.draw(arc);
g2D.fill(arc);
circle.setFrameFromCenter(new Point(0,0), new Point (70, 70));
g2D.setColor(this.getParent().getBackground());
g2D.draw(circle);
g2D.fill(circle);
circle.setFrameFromCenter(new Point(0,0), new Point (60, 60));
g2D.setColor(new Color(245, 245, 245));
g2D.draw(circle);
g2D.fill(circle);
g2D.setColor(Color.black);
g2D.rotate(Math.toRadians(90));
g2D.setFont(new Font("Verdana", Font.PLAIN, 30));
FontMetrics fm = g2D.getFontMetrics();
Rectangle2D r2D = fm.getStringBounds(progress + "%", g);
int x = (0 - (int) r2D.getWidth())/2;
int y = (0 - (int) r2D.getHeight())/2 +fm.getAscent();
g2D.drawString(progress + "%", x, y-10);
//Rectangle2D r2d = fm.getStringBounds(progress + "", g);
// g2D.setFont(new Font("Verdana", Font.PLAIN, 22));
// g2D.drawString("%", x + 40, y-10);
g2D.setFont(new Font("Verdana", Font.PLAIN, 15));
g2D.drawString("Progress", -35, y+5);
g2D.dispose();
}
}
There are a number of ways you "might" do this, but the simplest might be to just use BasicStroke and simply draw the arcs (and not fill anything at all)
This example deliberately sets the background color so you can see that it's transparent.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JCustomProgressBar pb = new JCustomProgressBar();
pb.setProgress(25);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pb);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class JCustomProgressBar extends JPanel {
private final Dimension SIZE = new Dimension(200, 200);
public JCustomProgressBar() {
super();
setBackground(Color.RED);
// Uncomment this to make it transparent
//setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return SIZE;
}
int progress = 1;
public void setProgress(int progress) {
this.progress = progress;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g.create();
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2D.translate(this.getWidth() / 2, this.getHeight() / 2);
BasicStroke bs = new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
Arc2D.Float arc = new Arc2D.Float(Arc2D.OPEN);
arc.setAngleStart(90);
arc.setFrameFromCenter(new Point(0, 0), new Point(90, 90));
arc.setAngleExtent(-((progress / 100d) * 360));
g2D.setStroke(bs);
g2D.setColor(new Color(120, 192, 0));
g2D.draw(arc);
bs = new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
arc.setFrameFromCenter(new Point(0, 0), new Point(75, 75));
arc.setAngleExtent(-(((100 - progress) / 100d) * 360));
g2D.setStroke(bs);
g2D.setColor(new Color(197, 228, 146));
g2D.draw(arc);
g2D.setColor(Color.black);
g2D.setFont(new Font("Verdana", Font.PLAIN, 30));
FontMetrics fm = g2D.getFontMetrics();
Rectangle2D r2D = fm.getStringBounds(progress + "%", g);
int x = (0 - (int) r2D.getWidth()) / 2;
int y = (0 - (int) r2D.getHeight()) / 2 + fm.getAscent();
g2D.drawString(progress + "%", x, y - 10);
g2D.setFont(new Font("Verdana", Font.PLAIN, 15));
g2D.drawString("Progress", -35, y + 5);
g2D.dispose();
}
}
}
You can take a look at Stroking and Filling Graphics Primitives for more details.
Before you tell me how you "don't want the ends rounded" (because I like it that way), make sure you take the time to read the BasicStroke JavaDocs
I have this program:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class TestLine {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestLine().start();
}
});
}
private static void start() {
JFrame frame = new JFrame();
frame.setContentPane(new CarthPanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static class CarthPanel extends JComponent {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
int w = gg.getClipBounds().width;
int h = gg.getClipBounds().height;
System.out.println("(w,h)=(" + w + "," + h + ")");
gg.translate(w - 1, 0); // <<< when uncommenting both lines, mirroring applies
gg.scale(-1.0, 1.0); //
paintTest(gg, w, h);
}
private static void paintTest(Graphics2D g, int w, int h) {
// black background
g.setColor(Color.black);
g.fillRect(0, 0, w, h);
// colored corners
g.setColor(Color.RED);
g.drawLine(0, 0, 10, 0);
g.drawLine(0, 0, 0, 10);
g.setColor(Color.RED);
g.drawLine(0, 199, 10, 199);
g.drawLine(0, 199, 0, 189);
g.setColor(Color.CYAN);
g.drawLine(189, 0, 199, 0);
g.drawLine(199, 0, 199, 10);
g.setColor(Color.CYAN);
g.drawLine(189, 199, 199, 199);
g.drawLine(199, 199, 199, 189);
// yellow squares
g.setColor(Color.yellow);
g.drawRect(3, 3, 10, 10);
g.fillRect(186, 3, 11, 11);
g.fillRect(3, 186, 11, 11);
g.drawRect(186, 186, 10, 10);
String chars = "ABC";
g.setFont(Font.decode("Arial 72"));
Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g);
g.drawString(chars, (int) (200 - rect.getWidth()) / 2, (int) (200 - rect.getHeight()));
}
}
}
If you run this program once with two particular lines commented in and then once with the same lines commented out (see the code), then you get to see this:
[
If you didn't spot the problem, here's a zoomed pic:
One would expect the image to be perfectly mirrored. This is true for all strokes and hollow shapes (= drawXxx() methods). All filled shapes however (= fillXxx() methods) are drawn exactly one pixel to the left of where I expect them; e.g. the filled yellow rectangles, and you can also notice that the black background has shifted, as seen by the white line at the right border.
Is this a bug or is this intended? I suspect that it has something to do with the difference how "width" and "height" are being handled in drawXxx() and fillXxx() methods:
drawRect(x,y,w,h) results in a hollow rectangle with X-axis boundaries x and x+w, so the rectangle is w+1 pixels wide.
fillRect(x,y,w,h) results in a filled rectangle with X-axis boundaries x and x+w-1, so the rectangle is w pixels wide.
What am I missing?
Not an answer, rather a hypothesis - the "contains(x,y)" of a rectangle will be true for the sides which forms the (x,y) corner of the rect and false for the sides making the (maxx, maxy) corner. Demo:
Rectangle r=new Rectangle(0, 0, 10, 10);
System.out.println(r.contains(0, 5)); // true
System.out.println(r.contains(5, 0)); // true
System.out.println(r.contains(10, 5)); // false
System.out.println(r.contains(5, 10)); // false
The hypothesis is that fillRect will not consider the "max sides" as inside points to be filled.
To assess the hypothesis, I'd suggest you to try using a GeneralPath which defines the same rectangle and see it there is any difference in filling it. GeneralPath should be forbidden to make any assumption on "the right-top borders are out of the shape's interior"
It is a bug, it is not a feature :)
Surely it is not intended, the mirrored image should be perfect, there's no reason why it shouldn't.
There is a way to use BufferedImage to render on it normally, and then drawing this BufferedImage flipped, the only drawback is a little performance influence and not well looking text drawn using LCD subpixeling.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class TestLine {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestLine().start();
}
});
}
private static void start() {
JFrame frame = new JFrame();
frame.setContentPane(new CarthPanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static class CarthPanel extends JComponent {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D) g;
// System.out.println("(w,h)=(" + w + "," + h + ")");
gg.translate(getWidth(), 0); // <<< when uncommenting both lines, mirroring applies
gg.scale(-1.0, 1.0); //
BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
try {
paintTest(img.createGraphics());
} catch (Exception e) {
e.printStackTrace();
}
g.drawImage(img, 0, 0, null);
}
private void paintTest(Graphics2D g) {
// black background
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
// colored corners
g.setColor(Color.RED);
g.drawLine(0, 0, 10, 0);
g.drawLine(0, 0, 0, 10);
g.setColor(Color.RED);
g.drawLine(0, 199, 10, 199);
g.drawLine(0, 199, 0, 189);
g.setColor(Color.CYAN);
g.drawLine(189, 0, 199, 0);
g.drawLine(199, 0, 199, 10);
g.setColor(Color.CYAN);
g.drawLine(189, 199, 199, 199);
g.drawLine(199, 199, 199, 189);
// yellow squares
g.setColor(Color.yellow);
g.drawRect(3, 3, 10, 10);
g.fillRect(186, 3, 11, 11);
g.fillRect(3, 186, 11, 11);
g.drawRect(186, 186, 10, 10);
String chars = "ABC";
g.setFont(Font.decode("Arial 72"));
Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g);
g.drawString(chars, (int) (200 - rect.getWidth()) / 2, (int) (200 - rect.getHeight()));
}
}
}
This example draws a simple PolyLine.
Is it possible to draw an outline around this PolyLine in red.
Not a single large red square but one that outlines the original PolyLine by 3-5 points away from all areas.
Some calculations were attempted and work for a fixed value, but when the PolyLine values are random, the algorithm doesn't always work as the next section of the line could turn right instead of left or up instead of down.
You almost have to look 2-3 points ahead to know if you are going to have add or subtract.
Is there an easier way to do it?
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PolyLine extends JPanel
{
public void paint(Graphics g) {
int[] xs = {25, 125, 85, 75, 25, 65, };
int[] ys = {50, 50, 100, 110, 150, 100};
BasicStroke traceStroke = new BasicStroke (1);
Graphics2D gc = (Graphics2D) g.create();
gc.setStroke(traceStroke);
gc.setColor(Color.BLUE);
gc.drawPolyline(xs, ys, 6);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new PolyLine());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(20,20, 1500,1500);
frame.setVisible(true);
}
}
First, a remark: It's usually preferable to have the geometric primitives as a Shape. The drawPolyline function (which uses these odd integer array coordinates) is somewhat out-dated. Creating the polyline as a Path2D is far more flexible.
For the task that you described, it will also be necessary to convert the polyline coordinates into a Path2D (if you switched to Path2D anyhow, you could omit this conversion step).
When you have the polyline as a Shape, the task is rather simple: You can create a stroked version of this shape, using a BasicStroke with the desired thickness and cap/join characteristics, by calling BasicStroke#createStrokedShape. This shape will basically be the shape of a "thick line". In order to avoid artifacts at the joins, you can create an Area from this Shape, and then draw this area.
So in the end, painting the actual outline is done with 2 lines of code, and the result is as follows:
But the MCVE here, for completeness:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ShapeOutlineTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new ShapeOutlineTestPanel());
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ShapeOutlineTestPanel extends JPanel
{
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
int[] xs = { 25, 125, 85, 75, 25, 65, };
int[] ys = { 50, 50, 100, 110, 150, 100 };
BasicStroke traceStroke = new BasicStroke(1);
g.setStroke(traceStroke);
g.setColor(Color.BLUE);
g.drawPolyline(xs, ys, 6);
Path2D path = new Path2D.Double();
for (int i = 0; i < xs.length; i++)
{
if (i == 0)
{
path.moveTo(xs[i], ys[i]);
}
else
{
path.lineTo(xs[i], ys[i]);
}
}
g.setColor(Color.RED);
BasicStroke stroke = new BasicStroke(
10.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
g.draw(new Area(stroke.createStrokedShape(path)));
}
}
So I have some code to change the background color of a button, but when I use the code, it sets the background color and border color.
Is there a way to not make this happen?
Thanks!
Code:
public void highlight(ArrayList<JButton> buttons){
for (JButton j : buttons) {
j.setBorder(new JButton().getBorder());
j.setBackground(Color.GREEN);
j.setForeground(Color.WHITE);
j.setOpaque(true);
j.setBorderPainted(false);
j.setFocusPainted(false);
j.setBorderPainted(false);
}
}
Okay, so this is a hacked version and is based on the idea that you want to maintain the current "look and feel" of the button, but want to use a different fill color
This simply applies a "highlight" color over the button...
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.kaizen.core.ui.ImageUtilities;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
HighlightButton btn = new HighlightButton("Help");
btn.setMargin(new Insets(20, 20, 20, 20));
btn.setHighlight(new Color(255, 0, 0, 64));
add(btn);
btn = new HighlightButton("Help");
btn.setMargin(new Insets(20, 20, 20, 20));
btn.setHighlight(new Color(0, 255, 0, 64));
add(btn);
btn = new HighlightButton("Help");
btn.setMargin(new Insets(20, 20, 20, 20));
btn.setHighlight(new Color(0, 0, 255, 64));
add(btn);
btn = new HighlightButton("Help");
btn.setMargin(new Insets(20, 20, 20, 20));
add(btn);
}
}
public class HighlightButton extends JButton {
private Color highlight;
public HighlightButton() {
setOpaque(false);
}
public HighlightButton(String text) {
super(text);
setOpaque(false);
}
public void setHighlight(Color color) {
if (color != highlight) {
Color old = highlight;
this.highlight = color;
firePropertyChange("highlight", old, highlight);
repaint();
}
}
public Color getHighlight() {
return highlight;
}
#Override
protected void paintComponent(Graphics g) {
Color highlight = getHighlight();
if (highlight != null) {
BufferedImage img = createCompatibleImage(getWidth(), getHeight(), Transparency.TRANSLUCENT);
Graphics2D g2d = img.createGraphics();
super.paintComponent(g2d);
g2d.dispose();
BufferedImage mask = generateMask(img, getHighlight(), 1f);
g.drawImage(img, 0, 0, this);
g.drawImage(mask, 0, 0, this);
} else {
super.paintComponent(g);
}
}
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
public static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
public static BufferedImage generateMask(BufferedImage imgSource, Color color, float alpha) {
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight, Transparency.TRANSLUCENT);
Graphics2D g2 = imgMask.createGraphics();
applyQualityRenderingHints(g2);
g2.drawImage(imgSource, 0, 0, null);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2.setColor(color);
g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2.dispose();
return imgMask;
}
public static void applyQualityRenderingHints(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
}
}
Basically, what this does, is paints a "masked" image, colored in the highlighted color OVER the top of the button. This is important to remember. The higher the alpha value of the color becomes, the less likely you are to see the text.
I've not tested this on windows, so I can't guarantee the results.
The content filling is performed by the look and feel delegate and generally ignores the color properties of the class (yeah, I know, awesome), so if you want to try and do something which was a little more robust, you'd need to define your own look and feel delegate and take over the painting process, no simple task.
Of course, you could just dispense with the content filling and borders used by the look and feel delegate and paint your own (overriding the paintComponent method), but this will not take advantage of the look and feel settings, so that's a balancing act you need to decide on
I have two classes in my project, Client and Card. When I try to import an image into the Card class, the paintComponent method in the client does not start. The timer still fires, and and outputs after repaint in the timer listener still print. The cause of this problem appears to be the try catch in the constructor of the card.
package card;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Card {
BufferedImage cardImage;
Point loc = new Point(50, 50);
int scale = 1;
public Card(){
try {
cardImage = ImageIO.read(new File("Penguins.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void draw(Graphics2D g2){
g2.setColor(Color.GRAY);
if(cardImage == null)
g2.fillRect(loc.x, loc.y, 150, 225);
else
g2.drawImage(cardImage, loc.x, loc.y, 50, 150, null);
}
}
New class
package core;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import card.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Client extends JPanel {
ArrayList<Card>[] board;
Card card;
Timer timer;
static Client player;
public static void main(String[] args) {
JFrame window = new JFrame("Game");
window.setSize(1080, 720);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.setVisible(true);
window.setLocation(50, 50);
window.setBackground(Color.GREEN);
player = new Client();
window.setContentPane(player);
}
public Client() {
//board = new ArrayList<Card>[4];
card = new Card();
ActionListener game = new TimerListener();
timer = new Timer(100, game);
timer.start();
}
public class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
repaint();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(5));
g2.drawOval(15, 75, 200, 200);
g2.drawOval(15, 350, 200, 200);
g2.drawRoundRect(355, -10, 450, 60, 15, 15);
g2.drawRoundRect(230, 75, 700, 90, 20, 20);
g2.drawRoundRect(230, 190, 700, 90, 20, 20);
g2.drawRoundRect(230, 350, 700, 90, 20, 20);
g2.drawRoundRect(230, 475, 700, 90, 20, 20);
g2.drawRoundRect(355, 590, 450, 90, 15, 15);
g2.drawRoundRect(950, 75, 90, 90, 10, 10);
g2.drawRoundRect(950, 190, 90, 90, 10, 10);
g2.drawRoundRect(950, 350, 90, 90, 10, 10);
g2.drawRoundRect(950, 475, 90, 90, 10, 10);
card.draw(g2);
}
}