intersectsLine() function is not working as expected - java

I am trying to check if a line intersects a set of rectangles.
This is my code:
public class Test {
public static void main(String args[]) {
Rectangle2D.Double rectangle1 = new Rectangle2D.Double(32, 64, 32, 32);
Rectangle2D.Double rectangle2 = new Rectangle2D.Double(0, 32, 32, 32);
Line2D.Double line = new Line2D.Double(36, 63, 5, 12);
System.out.println(rectangle1.intersectsLine(line)); // outputs false. Why?
System.out.println(rectangle2.intersectsLine(line)); // outputs true as expected
}
}
As you can see, the start point (36, 63) is within rectangle1, but apparently this line segment doesn't intersect the rectangle that it starts in.
However, it intersects the rectangle that stores the end point (5, 12).
Any idea why?
How do I get it to detect intersection?

The line does not intersect rectangle1, and that's why Java is giving you back the correct answer. Draw the lines in a GUI and see for yourself. Perhaps you're confused on the Rectangle2D.Double constructor -- the last parameters are width and height.
Draw the GUI and see; they almost touch, but not quite:
Drawing both rectangles:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.*;
import javax.swing.*;
public class Test extends JPanel {
private static final int PREF_W = 850;
private static final int PREF_H = PREF_W;
Rectangle2D rectangle1 = new Rectangle2D.Double(32, 64, 32, 32);
// Rectangle2D rectangle2 = new Rectangle2D.Double(0, 32, 32, 32);
Line2D line = new Line2D.Double(36, 63, 5, 12);
public Test() {
// TODO Auto-generated constructor stub
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
double scale = 8.0;
g2.scale(scale, scale); // make it big to show it for you
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.draw(rectangle1);
// g2.draw(rectangle2);
g2.draw(line);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Test mainPanel = new Test();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Related

JFrame program and running another class in Java

So currently I want to use a jframe program that would run another class in a window.
A working example:
Jframe:
import javax.swing.JFrame;
public class FaceJFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(300,400);
frame.setTitle("A Rectangle Object in a JFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Face aRectangle = new Face();
frame.add(aRectangle);
frame.setVisible(true);
}
}
The program:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
public class Face extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// Construct face and eyes
Rectangle face = new Rectangle(0, 0, 50, 50);
Rectangle eye = new Rectangle(5, 5, 15, 15);
Rectangle eye2 = new Rectangle(25, 5, 15, 15);
//make some lines for the mouth
Line2D mouth1 = new Line2D.Double(15, 30, 15, 35);
Line2D mouth2 = new Line2D.Double(15, 35, 35, 35);
Line2D mouth3 = new Line2D.Double(35, 35, 35, 30);
// draw the rectangle
g2.draw(face);
g2.draw(eye);
g2.draw(eye2);
g2.draw(mouth1);
g2.draw(mouth2);
g2.draw(mouth3);
}
}
With these two code snippets, running the Jframe one in cmd would give a pop-up window with a little face on it.
I want to do the same with the following code:
Jframe:
import javax.swing.JFrame;
public class Car_JFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(300,400);
frame.setTitle("a car");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Car aRectangle = new Car();
frame.add(aRectangle);
frame.setVisible(true);
}
}
and the main class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
public class Car
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Rectangle body = new Rectangle(0, 10, 60, 20);
Line2D roof1 = new Line2D.Double(10, 10, 20, 0);
Line2D roof2 = new Line2D.Double(20, 0, 40, 0);
Line2D roof3 = new Line2D.Double(40, 0, 50, 10);
Ellipse2D.Double wheel1 = new Ellipse2D.Double(15, 25, 10,10);
Ellipse2D.Double wheel2 = new Ellipse2D.Double(45, 25, 10,10);
// draw the rectangle
g2.draw(body);
g2.draw(roof1);
g2.draw(roof2);
g2.draw(roof3);
g2.draw(wheel1);
g2.draw(wheel2);
}
}
It doesn't produce the same result. In fact, running car_jframe in cmd would output the face program. (they're in the same blueJ project)
What should I do?
Your main problem is that your Car class does not extend JPanel or JComponent or any class that derives from these, and so it cannot be added to your JFrame, and any attempts to do so will result in a compilation error. You have two main possible solutions:
Make Car a true component by having it extend JPanel (or JComponent, but I recommend JPanel).
Or if you want Car to be a logical class and not a component class, then create a JPanel that contains a Car object and that draw the Car object by directly calling that object's paintComponent method within the JPanel's own paintComponent method.
Other notes:
You almost always want to call the super.paintComponent(g) method within your override so that the JPanel can do housekeeping painting.
You always want to preface any method that you think is an override method with the #Override annotation as this way the compiler will warn you if your assumption is incorrect.
e.g.,
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.*;
import javax.swing.*;
public class TestCar {
private static void createAndShowGui() {
Car mainPanel = new Car();
JFrame frame = new JFrame("A Car");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
// start all code on the Swing event thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Car extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
private static final Rectangle BODY = new Rectangle(0, 10, 60, 20);
private static final Line2D ROOF_1 = new Line2D.Double(10, 10, 20, 0);
private static final Line2D ROOF_2 = new Line2D.Double(20, 0, 40, 0);
private static final Line2D ROOF_3 = new Line2D.Double(40, 0, 50, 10);
private static final Ellipse2D WHEEL_1 = new Ellipse2D.Double(15, 25, 10,10);
private static final Ellipse2D WHEEL_2 = new Ellipse2D.Double(45, 25, 10,10);
public Car() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw the rectangle
g2.draw(BODY);
g2.draw(ROOF_1);
g2.draw(ROOF_2);
g2.draw(ROOF_3);
g2.draw(WHEEL_1);
g2.draw(WHEEL_2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
If you want to get real fancy, use a Path2D object, AffineTransform and a Swing Timer and give your GUI a little animation:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Car2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
private static final Rectangle BODY = new Rectangle(0, 10, 60, 20);
private static final Line2D ROOF_1 = new Line2D.Double(10, 10, 20, 0);
private static final Line2D ROOF_2 = new Line2D.Double(20, 0, 40, 0);
private static final Line2D ROOF_3 = new Line2D.Double(40, 0, 50, 10);
private static final Ellipse2D WHEEL_1 = new Ellipse2D.Double(15, 25, 10,
10);
private static final Ellipse2D WHEEL_2 = new Ellipse2D.Double(45, 25, 10,
10);
private static final int TIMER_DELAY = 30;
private static final int CAR_DELTA_X = 1;
private static final int CAR_DELTA_Y = CAR_DELTA_X;
private Path2D path2D = new Path2D.Double();
public Car2() {
path2D.append(BODY, false);
path2D.append(ROOF_1, false);
path2D.append(ROOF_2, false);
path2D.append(ROOF_3, false);
path2D.append(WHEEL_1, false);
path2D.append(WHEEL_2, false);
new Timer(TIMER_DELAY, new CarTimerListener()).start();;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.draw(path2D);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
class CarTimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
path2D.transform(AffineTransform.getTranslateInstance(CAR_DELTA_X, CAR_DELTA_Y));
repaint();
}
}
}
You should only have one main method in your application. I'd change it like below to let the user select which shape to print when running the application.
import javax.swing.JFrame;
public class DrawFrame {
public static void main(String[] args) {
if(args[0].equals("face") {
paintFace()
}
else if(args[0].equals("car") {
paintCar();
}
else {
System.out.println("No Shape Selected to Print");
}
}
private static paintFace() {
JFrame frame = new JFrame();
frame.setSize(300,400);
frame.setTitle("A Rectangle Object in a JFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Face face = new Face();
frame.add(face);
frame.setVisible(true);
}
private static paintCar() {
JFrame frame = new JFrame();
frame.setSize(300,400);
frame.setTitle("a car");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Car car = new Car();
frame.add(car);
frame.setVisible(true);
}
}
Also your car does not extend Component. It won't work.
Correct it as
public class Car extends JComponent { ... }

How to make circles randomize in a JFrame when I run the program

public class SplatPanel extends JPanel
{
private Circle circle1, circle2, circle3, circle4, circle5;
private Rectangle rec1, rec2, rec3;
// Constructor: Creates five Circle objects.
public SplatPanel()
{
circle1 = new Circle (30, Color.red, 70, 35);
circle2 = new Circle (50, Color.green, 30, 20);
circle3 = new Circle (100, Color.cyan, 60, 85);
circle4 = new Circle (45, Color.yellow, 200, 100);
circle5 = new Circle (60, Color.blue, 350, 200);
// (positionX, positionY, color, width, length)
rec1 = new Rectangle (200, 40, Color.GRAY, 90, 70);
rec2 = new Rectangle (150, 250, Color.red, 10, 10);
rec3 = new Rectangle (40, 200, Color.pink, 50, 300);
setPreferredSize (new Dimension(500, 400));
setBackground (Color.black);
}
// Draws this panel by requesting that each circle draw itself.
public void paintComponent (Graphics page)
{
super.paintComponent(page);
circle1.draw(page);
circle2.draw(page);
circle3.draw(page);
circle4.draw(page);
circle5.draw(page);
rec1.draw(page);
rec2.draw(page);
rec3.draw(page);
}
The objective is to make the circles randomize, how would I go about to randomize the circles so when I run the "Splat" program the circles will randomize in different places and sizes? I have a Rectangle class, a Circle class, a Splat class and then the SplatPanel class. I'm only assuming I would be using the randomizer in the the SplatPanel class
The problem is you are using hard coded values for the Circles. Instead you can randomize the values using the Random class
Random random = new Random();
int randX = random.nextInt(500); // or whatever the width of your panel is
int randY = random.nextInt(400); // or whatever the height of your panel is
int randRadius = random.nextInt(100); // max radius
Circle circle = new Circle(randRadius, Color.BLUE, randX, randY);
You could also use a List<Circle> to add the circles to and just loop through them in the paintComponent method (which is pretty common).
Here's a full running example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SplatPanel extends JPanel {
private static final int D_W = 500;
private static final int D_H = 500;
private List<Color> colors;
private List<Circle> circles;
Random random = new Random();
public SplatPanel() {
colors = createColorList();
circles = new ArrayList<>();
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int randX = random.nextInt(D_W); // or whatever the width of your panel is
int randY = random.nextInt(D_H); // or whatever the height of your panel is
int randRadius = random.nextInt(100); // max radius
Color color = colors.get(random.nextInt(colors.size()));
Circle circle = new Circle(randRadius, color, randX, randY);
circles.add(circle);
repaint();
}
});
timer.start();
}
private List<Color> createColorList() {
List<Color> list = new ArrayList<>();
list.add(Color.BLUE);
list.add(Color.CYAN);
list.add(Color.PINK);
list.add(Color.ORANGE);
list.add(Color.GREEN);
list.add(Color.MAGENTA);
list.add(Color.YELLOW);
list.add(Color.RED);
return list;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Circle circle : circles) {
circle.drawCircle(g);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
public class Circle {
int radius, x, y;
Color color;
public Circle(int radius, Color color, int x, int y) {
this.radius = radius;
this.color = color;
this.x = x;
this.y = y;
}
public void drawCircle(Graphics g) {
g.setColor(color);
g.fillOval(x, y, radius * 2, radius * 2);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new SplatPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Errors with setFrame, JSlider

So I am testing out a JSlider for a bigger project and can't get it to work. The slider is supposed to adjust the size of a circle, and it's not working. I thought I might have an issue with the creation of the circle, and I am trying to use setFrame, and it's giving an error saying it's "undefined." Can anyone see why? Since it should take in either float or double as parameters. Or if you can see why it's not adjusting the size of the shape that would help a lot too... Here's what I have:
public class DrawShape extends JPanel{
private float width = 300;
private Shape circle = new Ellipse2D.Float(100, 20, width, 300);
public DrawShape() {
}
public DrawShape(float width) {
this.width = width;
}
public void setWidth(int w) {
this.width = w;
circle.setFrame(100, 20, width, 300);//This is where the error is
}
public void paintComponent (Graphics g) {
super.paintComponents(g);
Graphics2D graphics = (Graphics2D)g;
graphics.setColor(Color.black);
graphics.fill(circle);
}//end paintComponent
}//end class
Class with main:
public class SliderTest extends JFrame{
private static DrawShape circle = new DrawShape();
JSlider slider;
JLabel label;
public SliderTest() {
setLayout(new FlowLayout());
slider = new JSlider(JSlider.HORIZONTAL, 150, 450, 300);//orientation, min val, max value, starting val
slider.setMajorTickSpacing(50);//every 5 integers will be a new tick position
slider.setPaintTicks(true);
add(slider);
label = new JLabel("Current value 300");
add(label);
event e = new event();
slider.addChangeListener(e);;
}//end cons
public class event implements ChangeListener{
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider)e.getSource();
int value = slider.getValue();
label.setText("Current Value " + value);
circle.setWidth(value);
repaint();
}//end stateChanged
}//end class event
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Circle");
frame.add(circle);
frame.setSize(500,400);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
JFrame frame1 = new SliderTest ();
frame1.setTitle("Toolbar");
frame1.setSize(300,200);
frame1.setLocation(200,100);
frame1.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame1.setVisible(true);
}
}
Shape does not have a setFrame method. RectangularShape does...
Instead of
private Shape circle = new Ellipse2D.Float(100, 20, width, 300);
You might try using...
private Ellipse2D circle = new Ellipse2D.Float(100, 20, width, 300);
instead...
Your public DrawShape(float width) { constructor is also wrong, as it does not actually do anything.
You should also consider overriding the getPreferredSize method so it can return the width of the shape as a part of the preferred size.
I'm not sure you actually need to maintain the width reference as you can ascertain this from the circle directly...IMHO
For Example
I've not tested this...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
public class DrawShape extends JPanel {
private final Ellipse2D circle = new Ellipse2D.Float(100, 20, 300, 300);
public DrawShape() {
}
public DrawShape(float width) {
circle.setFrame(100, 20, width, 300);
}
public void setWidth(int w) {
circle.setFrame(100, 20, w, 300);
revalidate();
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
size.width = circle.getBounds().width;
return size;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D graphics = (Graphics2D) g;
graphics.setColor(Color.black);
graphics.fill(circle);
}//end paintComponent
}//end class

Creating and overriding a shape to fit into JPanel?

In this program a polygon is created to show up into a JPanel tab.
In-order to make it show I had to over-ride the shape and create a setter method for it. Unfortunately it is not showing and the program is not running either.
The error:
Exception in thread "main" java.lang.IllegalArgumentException: adding
a window to a container
at SelectShape component1 = new SelectShape(x, y, vert); in method
Page1.
The only way it would work is by making a frame and removing the JTab and assigning the shape onto the frame but that is not what I want to make. I want to make a program that can distribute shapes to * different tabs* using one graphics method.
Here is the code:
import java.awt.*;
import java.io.IOException;
import javax.swing.*;
/* This program create a graphics component that draws a polygon
*/
public class SelectShape extends JFrame
{
private JTabbedPane tabbedPane;
private JPanel panel1;
// //////////////////////////
static int[] x = { 20, 40, 50, 65, 80, 95 }; // Co-ords for a polygon
static int[] y = { 60, 105, 105, 110, 95, 95 };
static int vert = 6;
public SelectShape() throws IOException // Builds GUI
{
setTitle("Program");
setSize(900, 600);
setBackground(Color.gray);
JPanel topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
getContentPane().add(topPanel);
// Create the tab pages
createPage1();
// Create a tabbed pane
tabbedPane = new JTabbedPane();
tabbedPane.addTab("Shape Panel", panel1);
}
public void createPage1() throws IOException // Creates JPanel
{
panel1 = new JPanel();
panel1.setLayout(null);
SelectShape component1 = new SelectShape(x, y, vert); //error
SelectShape component2 = new SelectShape(x, y, vert); //over-rides shape
component1.setBounds(290, 70, 120, 40);
component2.setBounds(290, 70, 120, 40);
panel1.add(component1); // is not displayed!
panel1.add(component2); // component2 overwrites component1!!!
panel1.setVisible(true);
}
// overrides javax.swing.JComponent.paintComponent
public void paintComponent(Graphics g) {
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
// Construct a polygon then draw it
Polygon polygon = new Polygon(x, y, vert);
g2.draw(polygon);
g2.fill(polygon);
}
public SelectShape(int[] x, int y[], int vert) { // setter method
this.x = x;
this.y = y;
this.vert = vert;
}
public static void main(String[] args) throws IOException {
SelectShape mainFrame = new SelectShape(); //Frame
mainFrame.setVisible(true);
}
}
I think you are mixing many concepts together in your code which eventually leads to ununderstandable code.
JFrame does not extends JComponent and does not have a paintComponent method. Consider using the #Override annotation on methods that override another. This will allow you to easily mistakes like this.
No need to extend JFrame anyway and never override the paint() method of a Top-level container (JDialog, JFrame, ...)
Always invoke the super method of paintXXX methods
public SelectShape(int[] x, int y[], int vert) { // setter method is not a setter method. It is a constructor that takes 3 arguments and assign them. In all cases, this does absolutely nothing in your case because you made those variables static. Avoid the use of static unless if you describe constants, in which case it should be also followed by the final keyword.
Start the UI, and perform all modifications to the UI, on the Event Dispatching Thread (EDT). This can easily be done by using SwingUtilities.invokeLater().
The error you are seeing: Exception in thread "main" java.lang.IllegalArgumentException: adding a window to a container is thrown because you are trying to add a JFrame to a JComponent which is forbidden. JFrame cannot be added to anything. If you want to do that, you need to use JDesktopPane and add JInternalFrame (but that is another story).
I am not too sure as to what you are trying to achieve, but here is a working code derived from yours which works much better:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
/* This program create a graphics component that draws a polygon
*/
public class SelectShape extends JPanel {
// Constants
private static final int[] x = { 20, 40, 50, 65, 80, 95 }; // Co-ords for a polygon
private static final int[] y = { 60, 105, 105, 110, 95, 95 };
private static final Polygon POLYGON = new Polygon(x, y, Math.min(x.length, y.length));
private static final Ellipse2D CIRCLE = new Ellipse2D.Double(100, 40, 45, 45);
// Class variables
private final Shape shape;
private Dimension preferredSize;
public SelectShape(Shape shape) {
this.shape = shape;
Rectangle bounds = shape.getBounds();
this.preferredSize = new Dimension(bounds.x + bounds.width, bounds.y + bounds.height);
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.BLUE);
g2.draw(shape);
g2.fill(shape);
}
public static void main(String[] args) throws IOException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame mainFrame = new JFrame("Program");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SelectShape polygon = new SelectShape(POLYGON);
SelectShape circle = new SelectShape(CIRCLE);
// Create a tabbed pane
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Polygon", polygon);
tabbedPane.addTab("Circle", circle);
mainFrame.add(tabbedPane);
mainFrame.pack();
mainFrame.setVisible(true);
}
});
}
}

Internal padding for JTextArea with background Image

My ultimate goal is to have a JTextArea with a background image. I found code online that showed me how to do this, but now I'm having an issue with the text being on top of the image.
This Is what I mean:
Is there any way I can add a sort of inward indent so that the text is not overlapping the edges of the image?
Here is the raw comment bubble image.
Here is the code:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.GrayFilter;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class myBackgroundSample {
String file;
public myBackgroundSample(String i) {
file = i;
setItUp();
}
public void setItUp() {
final ImageIcon imageIcon = new ImageIcon(file);
JTextArea textArea = new JTextArea() {
Image image = imageIcon.getImage();
public void paint(Graphics g) {
setOpaque(false);
g.drawImage(image, 0, 0, this);
super.paint(g);
}
};
JFrame frame = new JFrame("Background Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane(textArea);
Container content = frame.getContentPane();
content.add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String right = "chat1.jpg";
myBackgroundSample temp = new myBackgroundSample(right);
}
}
Use a custom border that extends AbstractBorder. Something like this:
Getting the exact shape & color is left as an exercise for the reader. :)
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
class TextBubbleBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private int pointerSize = 7;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
RenderingHints hints;
TextBubbleBorder(
Color color) {
new TextBubbleBorder(color, 4, 8, 7);
}
TextBubbleBorder(
Color color, int thickness, int radii, int pointerSize) {
this.thickness = thickness;
this.radii = radii;
this.pointerSize = pointerSize;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness/2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + pointerSize + strokePad;
insets = new Insets(pad,pad,bottomPad,pad);
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
#Override
public void paintBorder(
Component c,
Graphics g,
int x, int y,
int width, int height) {
Graphics2D g2 = (Graphics2D)g;
int bottomLineY = height-thickness-pointerSize;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0+strokePad,
0+strokePad,
width-thickness,
bottomLineY,
radii,
radii
);
Polygon pointer = new Polygon();
// left point
pointer.addPoint(
strokePad+radii+pointerPad,
bottomLineY);
// right point
pointer.addPoint(
strokePad+radii+pointerPad+pointerSize,
bottomLineY);
// bottom point
pointer.addPoint(
strokePad+radii+pointerPad+(pointerSize/2),
height-strokePad);
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
Area spareSpace = new Area(new Rectangle(0,0,width,height));
spareSpace.subtract(area);
g2.setClip(spareSpace);
g2.clearRect(0,0,width,height);
g2.setClip(null);
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JLabel l = new JLabel(
"The quick brown fox jumped over the lazy dog!");
l.setBorder(new TextBubbleBorder(Color.MAGENTA.darker(),2,4,0));
l.setOpaque(true);
l.setBackground(Color.BLACK);
JOptionPane.showMessageDialog(null, l);
}
});
}
}
You should use an Border for that, more specifictly you should use BorderFactory.createEmptyBorder(int top, int left, int bottom, int right):
textArea.setBorder(BorderFactory.createEmptyBorder(10,10,15,10));
You should also override paintComponent instead of paint. Also, use setRows() and setColumns() to set the size of the textArea, then you can use pack() instead of setSize(400,400) which is not recommended. See this example:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class Test extends JFrame {
class MyTextArea extends JTextArea {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.PINK);
g2.setStroke(new BasicStroke(4));
g2.drawRoundRect(3, 3, getWidth()-7, getHeight()-7, 5, 5);
}
}
public Test() {
JPanel panel = new JPanel(new BorderLayout());
JTextArea textArea = new MyTextArea();
textArea.setRows(3);
textArea.setColumns(25);
textArea.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(textArea, BorderLayout.NORTH);
add(panel);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}
To post code, indent every line by four spaces.
I assume you are overriding paintComponent()* for your JTextArea. If you are, make sure that it is transparent by adding
setOpaque(false);
*This also works if you override paint(), but as trashgod correctly states, that would interfere with paintBorder().
A better version of TextBubbleBorder.
https://gist.github.com/wenerme/6940534
pointer padding control
pointer side control
dynamic change

Categories