Excluding areas while coloring in Java - java

I have a graphics object and I want to color all the area except some rectangles. For e.g.
I want to color all area except these black areas. Can I do that? There can be many rectangles in the image.

I recommend you to fill all area with White color, and then draw Black rectangles on that, because it's simplier that draw figure with holes. For example like next:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawExample extends JPanel{
List<Rectangle> rctangles = new ArrayList<>();
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawExample drawExample = new DrawExample();
drawExample.addRect(new Rectangle(20,20,25,25));
drawExample.addRect(new Rectangle(50,50,25,25));
frame.add(drawExample);
frame.setSize(200,200);
frame.setVisible(true);
}
private void addRect(Rectangle rectangle) {
rctangles.add(rectangle);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
for(Rectangle r : rctangles){
g.fillRect(r.x, r.y, r.width,r.height);
}
}
}

Related

How to do right packing of paintComponent in java?

1. Need set 1024*768 the size of paintComponent Area.
2. Need set drawing orientation of line on (0, 0, 1366,1024) but not a center.
I try to change the size in getPreferredSize() method but It's doesn't help me or doing another effect. I can't do this.
I try to change the size in getPreferredSize() method but It's doesn't help me or doing another effect.
I try to change
This is code which I can't change for my needs!
This is code which I can't change for my needs!
package j;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Letter {
LetterDraw letterDraw = new LetterDraw();
public Letter() {
JFrame frame = new JFrame();
JPanel letterDrawWrapper = new JPanel(new GridBagLayout());
letterDrawWrapper.add(letterDraw);
letterDrawWrapper.setSize(1024,760);
frame.add(createColorChooser(), BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setSize(111, 111);
frame.setVisible(true);
}
private JColorChooser createColorChooser() {
JColorChooser colorChooser = new JColorChooser();
colorChooser.getSelectionModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
letterDraw.setColor(colorChooser.getColor());
}
});
return colorChooser;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Letter();
}
});
}
}
class LetterDraw extends JPanel {
private Color color;
public void setColor(Color color) {
this.color = color;
repaint();
}
#Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g = (Graphics2D) graphics;
g.setColor(color);
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(3));
//g.setStroke(new BasicStroke(4, BasicStroke.JOIN_BEVEL, 0));
g.setColor(color);
g.drawLine(11,11,1024,1024);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
}```
Need set 1024*768 the size of paintComponent Area.
You should NOT be hard coding size values. You don't know what the resolution will be.
Also, The resolution of your screen is NOT the space available for painting. The frame has a title bar and border which takes away space for custom painting.
Painting code should be dynamic based on the space available to your panel, so the painting code would use methods like getWidth() and getHeight() to determine the painting area.
I try to change the size in getPreferredSize()
Yes that will work to give a suggestion for the preferred size. Then you just pack() the frame. Don't use setSize() on the frame.
//frame.setSize(111, 111);
That statement is overriding the size determined by the pack() method. Get rid of it.
g.drawLine(11,11,1024,1024);
Don't hard code values. The size of the panel will change as the frame is resized. For example to draw a diagonal line on the panel the code should be:
g.drawLine(0, 0, getWidth(), getHeight());
Try manually resizing the frame to see how the size of the line changes.
Edit:
You didn't add your panel to the frame:
frame.add(letterDraw);

Java Swing drawing PlayButton for a basic music player

Maybe my case it's a simple confusion of ideas. How do draw a button like this using Shape?
I don't mind the rounded corners, heres my aproach for a round corner button.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.JComponent;
import javax.swing.plaf.basic.BasicButtonUI;
public class PlayButtonUI extends BasicButtonUI{
protected Shape shape;
#Override
protected void installDefaults(AbstractButton b) {
super.installDefaults(b);
b.setOpaque(false);//removes that annoying default background
}
#Override public void paint(Graphics g, JComponent c) {
Graphics2D g2 = (Graphics2D)g;
AbstractButton b = (AbstractButton) c;
ButtonModel model = b.getModel();
drawButtonShape(b);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);//smoth borders
if(model.isArmed()) {
g2.setColor(Color.RED);//color when button is pressed
}else{
g2.setColor(Color.GREEN);//default button color
}
g2.fill(shape);//aplying color
super.paint(g2, c);
}
private void drawButtonShape(JComponent c) {
//button shape is drawn here, 16 are the border radius
shape = new RoundRectangle2D.Float(0, 0, c.getWidth()-1, c.getHeight()-1,16, 16);
}
}
I don't really know how to draw anything at all, this class was a result from a chaotic example that i found somewhere, and then simplified by myself until it just worked, i left some comments for the important lines.
I've been looking for a while, and found this example in oracle docs.
https://docs.oracle.com/javase/tutorial/2d/geometry/arbitrary.html
I don't really know how to convert Graphics2D to Shape, please tell me if i'm taking the wrong way.
So, I've spent the better of the day banging my head against this problem, trying to do a whole bunch of trig magic ... I can't even do simple card tricks :P
Then I realised, there are other tricks I could do...
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicButtonUI;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JButton btn = new JButton();
btn.setUI(new PlayButtonUI());
frame.add(btn);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PlayButtonUI extends BasicButtonUI {
#Override
public Dimension getPreferredSize(JComponent c) {
return new Dimension(200, 200);
}
#Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2 = (Graphics2D) g;
AbstractButton b = (AbstractButton) c;
ButtonModel model = b.getModel();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//smoth borders
if (model.isArmed()) {
g2.setColor(Color.BLACK);//color when button is pressed
} else {
g2.setColor(Color.GRAY);//default button color
}
float thinkness = Math.min(c.getWidth(), c.getHeight()) * 0.1f;
Shape shape = shapeFor(c, thinkness);
g2.setStroke(new BasicStroke(thinkness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.fill(shape);//aplying color
g2.draw(shape);
super.paint(g2, c);
}
private Shape shapeFor(JComponent c, float thickness) {
GeneralPath gp = new GeneralPath();
double width = c.getWidth();
double height = c.getHeight();
double vPos = height / 2.0;
double hPos = width - thickness;
gp.moveTo(0.0 + thickness, 0.0 + thickness);
gp.lineTo(hPos, vPos);
gp.lineTo(0.0 + thickness, height - thickness);
gp.closePath();
return gp;
}
}
}
So, this is a slight "cheat". What this actually does is uses the properties of the Stroke to generate rounded edges, rather than trying to use curveTo or compound shapes
Have a look at Stroking and Filling Graphics Primitives for more details

How can I resize and paintComponent inside a frame

Write a program that fills the window with a larrge ellipse. The ellipse shoud touch the window boundaries, even if the window is resized.
I have the following code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
public class EllipseComponent extends JComponent {
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double ellipse = new Ellipse2D.Double(0,0,150,200);
g2.draw(ellipse);
g2.setColor(Color.red);
g2.fill(ellipse);
}
}
And the main class:
import javax.swing.JFrame;
public class EllipseViewer {
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(150, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
EllipseComponent component = new EllipseComponent();
frame.add(component);
frame.setVisible(true);
}
}
in your EllipseComponent you do:
Ellipse2D.Double ellipse = new Ellipse2D.Double(0,0,getWidth(),getHeight());
I'd also recommend the changes given by Hovercraft Full Of Eels. In this simple case it might not be an issue but as the paintComponent method grows in complexity you realy want as little as possible to be computed in the paintComponent method.
Do not resize components within paintComponent. In fact, do not create objects or do any program logic within this method. The method needs to be lean, fast as possible, do drawing, and that's it. You must understand that you do not have complete control over when or even if this method is called, and you certainly don't want to add code to it unnecessarily that may slow it down.
You should create your ellipse in the class's constructor. To resize it according to the JComponent's size and on change of size, use a ComponentListener.:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
public class EllipseComponent extends JComponent {
Ellipse2D ellipse = null;
public EllipseComponent {
ellipse = new Ellipse2D.Double(0,0,150,200);
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// set the size of your ellipse here
// based on the component's width and height
}
});
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.draw(ellipse);
g2.setColor(Color.red);
g2.fill(ellipse);
}
}
Caveat: code not run nor tested

Drawing between 2 images in 1 JPanel

I want to draw the lines between 2 JScrollPanes (first scroll pane on the left side, second on the right). These JScrollPanes contain images. I want to draw lines between these 2 images (use some layers, use some trick etc.). I tried do it different ways, but i failed. Is it possible? (if not, i will have to make 2 images in one JScrollPane and it won't be nice).
EDIT
I want to draw between 2 images - throught components - get some points from images and draw lines between them. I apologize for poorly formulated question.
In order to accomplish this, I believe you'll need to make use of the Glass Pane. The Glass Pane sits on top of everything in the JRootPane and fills the entire view. This particular position allows two distinct capabilities:
Intercepting mouse and keyboard events
Drawing over the entire user interface
I believe your question is addressed by the second capability. The following is an example implementation, which you can later tailor to meet your own needs. Note that I've left out a lot of detail with regard to Glass Pane that you'll need to research on your own.
CODE
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
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 GlassPaneDemo {
private static BufferedImage bi;
public static void main(String[] args){
try {
loadImages();
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
} catch (IOException e) {
// handle exception
}
}
private static void loadImages() throws IOException{
bi = ImageIO.read(new File("src/resources/person.png"));
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setGlassPane(new CustomGlassPane());
frame.getContentPane().add(getButtonPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.getGlassPane().setVisible(true);
frame.setVisible(true);
}
private static final JPanel getButtonPanel(){
#SuppressWarnings("serial")
final JPanel panel = new JPanel(){
#Override
protected void paintComponent(Graphics g){
Graphics gCopy = g.create();
gCopy.setColor(Color.BLUE.darker());
gCopy.fillRect(0, 0, getWidth(), getHeight());
gCopy.dispose();
}
};
final JLabel labelOne = new JLabel();
labelOne.setIcon(new ImageIcon(bi));
final JLabel labelTwo = new JLabel();
labelTwo.setIcon(new ImageIcon(bi));
panel.add(labelOne);
panel.add(labelTwo);
return panel;
}
#SuppressWarnings("serial")
private static class CustomGlassPane extends JComponent{
private Point p1;
private Point p2;
private boolean lineDrawn;
public CustomGlassPane(){
addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e){
if(p1 == null || lineDrawn){
if(lineDrawn){
p1 = null;
p2 = null;
lineDrawn = false;
}
p1 = e.getPoint();
}else{
p2 = e.getPoint();
repaint(); // not optimal
lineDrawn = true;
}
}
});
// Block all other input events
addMouseMotionListener(new MouseMotionAdapter(){});
addKeyListener(new KeyAdapter(){});
addComponentListener(new ComponentAdapter(){
#Override
public void componentShown(ComponentEvent e){
requestFocusInWindow();
}
});
setFocusTraversalKeysEnabled(false);
}
#Override
protected void paintComponent(Graphics g){
if(p1 != null && p2 != null){
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
g2.drawLine((int)p1.getX(), (int)p1.getY(), (int)p2.getX(), (int)p2.getY());
g2.dispose();
}
}
}
}
OUTPUT
EXPLANATION
In this example, I clicked two arbitrary points within each JLabel, and then drew a connecting line.
This should be very possible. You will need to create a custom component that is aware of both vertical ScrollBars. It should add itself as an AdjustmentListener to each scroll bar in order to detect changes and repaint the lines between the two.
See:
addAdjustmentListener method in the API
You can use this
http://java-sl.com/connector.html
as an example of such code.

java swing : Polygon fill color problem

Could any body diagnose the problem I am facing?
As you run the demo you can see the middle part left blank, I need to fill the entire area..
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class FillDemo
{
public static void main(String aths[])
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel pnl = new PolygonDemo();
pnl.setSize(100, 200);
f.getContentPane().add(pnl);
f.setSize(400,280);
f.setLocation(200,200);
f.setVisible(true);
}
}
class PolygonDemo extends JPanel
{
public PolygonDemo()
{
setBackground(Color.white);
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
Polygon p=new Polygon();
p.addPoint(100,0);
p.addPoint(100,100);
p.addPoint(0,100);
p.addPoint(0,0);
p.addPoint(80,0);
p.addPoint(80,20);
p.addPoint(40,20);
p.addPoint(40,40);
p.addPoint(80,40);
p.addPoint(80,100);
p.addPoint(20,100);
p.addPoint(20,80);
p.addPoint(60,80);
p.addPoint(60,60);
p.addPoint(20,60);
p.addPoint(20,0);
p.addPoint(0,0);
g2.setColor(Color.BLACK);
g2.draw(p);
g2.setColor(new Color(120,250,100));
g2.fillPolygon(p);
//g2.fillPolygon(p.xpoints,p.ypoints,p.npoints);
}
}
Many thanks in advance
Your polygon intersects with itself. The fillPolygon method can not clearly decide which point is in and which is out. From the fillPolygon javadoc:
The area inside the polygon is defined using an even-odd fill rule, also known as the alternating rule.
Perhaps you can split your polygon into three single ones.
Draw Rectangle and Fill Color.....
public void paint(Graphics g)
{
int[] xPoints = {100,50,150};
int[] yPoints = {100,200,200};
g.setColor(Color.black);
g.drawPolygon(xPoints, yPoints, 3);
g.setColor(Color.red);
g.fillPolygon(xPoints, yPoints, 3);
}

Categories