I have a class called "GridPanel" that paints the coordinate system on the screen.
public class GridPanel extends JPanel
{
protected paintComponent(Graphics g){
// draws the Coordinate System with grid
}
}
And another class called "Shapes" that paints custom shapes on the coordinate system.
public class Shape extends JComponent{
protected paintComponent(Graphics g){
// draws the shape on to the coordinate system
}
}
I am looking for a way to do the painting inside the shape class without having to paint the coordinate system again and again.
"How" will come down to "what".
Generally speaking, you'll find it easier to paint things onto the GridPane if you do it yourself, and not rely on things like layout managers.
For example. This creates a simple interface, with a single method which is used to paint things onto the grid.
public interface GridShape {
public void draw(Graphics2D g2d, JComponent parent);
}
This is then implemented by what ever wants to paint onto the grid
public class WaveShape implements GridShape {
#Override
public void draw(Graphics2D g2d, JComponent parent) {
g2d.setColor(Color.RED);
int xDiff = parent.getWidth() / 4;
int height = parent.getHeight() - 1;
int xPos = 0;
GeneralPath path = new GeneralPath();
path.moveTo(0, 0);
path.curveTo(xPos + xDiff, 0, xPos, height, xPos + xDiff, height);
xPos += xDiff;
path.curveTo(xPos + xDiff, height, xPos, 0, xPos + xDiff, 0);
xPos += xDiff;
path.curveTo(xPos + xDiff, 0, xPos, height, xPos + xDiff, height);
xPos += xDiff;
path.curveTo(xPos + xDiff, height, xPos, 0, xPos + xDiff, 0);
g2d.draw(path);
}
}
The GridPane then paints itself and then paints what ever "shape" it has (this example is pretty basic, but you could have a setter which changes the "shape" which is painted or, if required, have a List which allows you to paint multiple shapes simultaneously)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestGrid {
public static void main(String[] args) {
new TestGrid();
}
public TestGrid() {
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 GridPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GridPane extends JPanel {
private WaveShape waveShape;
public GridPane() {
waveShape = new WaveShape();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
g2d.dispose();
// I don't trust you
g2d = (Graphics2D) g.create();
waveShape.draw(g2d, this);
g2d.dispose();
}
}
public interface GridShape {
public void draw(Graphics2D g2d, JComponent parent);
}
public class WaveShape implements GridShape {
#Override
public void draw(Graphics2D g2d, JComponent parent) {
g2d.setColor(Color.RED);
int xDiff = parent.getWidth() / 4;
int height = parent.getHeight() - 1;
int xPos = 0;
GeneralPath path = new GeneralPath();
path.moveTo(0, 0);
path.curveTo(xPos + xDiff, 0, xPos, height, xPos + xDiff, height);
xPos += xDiff;
path.curveTo(xPos + xDiff, height, xPos, 0, xPos + xDiff, 0);
xPos += xDiff;
path.curveTo(xPos + xDiff, 0, xPos, height, xPos + xDiff, height);
xPos += xDiff;
path.curveTo(xPos + xDiff, height, xPos, 0, xPos + xDiff, 0);
g2d.draw(path);
}
}
}
Related
I am trying to design a JButton.
I want the JButton to look like this:
I tried to achieve this using Polygon but I couldn't make the corners be round as seen above.
The one I designed looks like this:
The code that generated this button is below:
public class arcButton extends JButton{
public arcButton() {
Dimension size = getPreferredSize();
size.width = size.height = Math.max(size.width, size.height);
setPreferredSize(size);
setContentAreaFilled(false);
}
protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
g.setColor(Color.CYAN.darker().darker());
} else {
g.setColor(Color.CYAN.darker());
}
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
g.fillPolygon(xPoints, yPoints, xPoints.length);
super.paintComponent(g);
}
protected void paintBorder(Graphics g) {
g.setColor(Color.cyan);
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
g.drawPolygon(xPoints, yPoints, xPoints.length);
}
Polygon polygon;
public boolean contains(int x, int y) {
if (polygon == null ||
!polygon.getBounds().equals(getBounds())) {
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
polygon = new Polygon(xPoints,yPoints,xPoints.length);
}
return polygon.contains(x, y);
}
}
I tried to draw with arcs but when I use ((Graphics2D)g).draw(arc) in the paintComponent. It kept giving a lot of errors when mouse was on the GUI.
How should I approach this?
I created the following GUI.
Instead of extending a JButton, I created a class to hold two BufferedImages. One for the arrow, and one to signify a pressed button.
I created a test GUI so I could draw the arrow one small piece at a time. I wound up creating two Polygons, one for the semi-circle and one for the arrowhead.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CustonButtonGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CustonButtonGUI());
}
private ButtonImages buttonImages;
public CustonButtonGUI() {
this.buttonImages = new ButtonImages();
}
#Override
public void run() {
JFrame frame = new JFrame("Custom JButton");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
BufferedImage image = buttonImages.getMainImage();
JButton button = new JButton();
button.setPreferredSize(new Dimension(image.getWidth(panel),
image.getHeight(panel)));
button.setIcon(new ImageIcon(image));
button.setPressedIcon(new ImageIcon(buttonImages.getPressedImage()));
panel.add(button);
return panel;
}
private class ButtonImages {
private final BufferedImage mainImage;
private final BufferedImage pressedImage;
public ButtonImages() {
this.mainImage = createMainImage(120, 200);
this.pressedImage = createPressedImage(120, 200);
}
private BufferedImage createMainImage(int width, int height) {
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
g2d.setColor(Color.BLACK);
g2d.fillPolygon(createArrowPolygon(width, height));
g2d.fillPolygon(createCircularPolygon(width, height));
g2d.dispose();
return image;
}
private Polygon createArrowPolygon(int width, int height) {
Polygon polygon = new Polygon();
int margin = 10;
int arrowWidth = 30;
int x = width - margin;
int y = height - margin;
polygon.addPoint(x, y - arrowWidth);
polygon.addPoint(x - arrowWidth, y - arrowWidth - arrowWidth);
polygon.addPoint(x - arrowWidth, y);
return polygon;
}
private Polygon createCircularPolygon(int width, int height) {
Polygon polygon = new Polygon();
int centerY = height / 2;
int margin = 10;
Point centerPoint = new Point(width - margin - 30, centerY);
double radius = centerY - 55.0;
for (int angle = 90; angle <= 270; angle++) {
double theta = Math.toRadians(angle);
int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
polygon.addPoint(x, y);
}
radius += 25.0;
for (int angle = 270; angle >= 90; angle--) {
double theta = Math.toRadians(angle);
int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
polygon.addPoint(x, y);
}
return polygon;
}
private BufferedImage createPressedImage(int width, int height) {
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
return image;
}
public BufferedImage getMainImage() {
return mainImage;
}
public BufferedImage getPressedImage() {
return pressedImage;
}
}
}
I need to draw a ring, with given thickness, that looks something like this:
The center must be transparent, so that it doesn't cover previously drawn shapes. (or other rings) I've tried something like this:
//g is a Graphics2D object
g.setColor(Color.RED);
g.drawOval(x,y,width,height);
g.setColor(Color.WHITE);
g.drawOval(x+thickness,y+thickness,width-2*thickness,height-2*thickness);
which draws a satisfactory ring, but it covers other shapes; the interior is white, not transparent. How can I modify/rewrite my code so that it doesn't do that?
You can create an Area from an Ellipse2D that describes the outer circle, and subtract the ellipse that describes the inner circle. This way, you will obtain an actual Shape that can either be drawn or filled (and this will only refer to the area that is actually covered by the ring!).
The advantage is that you really have the geometry of the ring available. This allows you, for example, to check whether the ring shape contains a certain point, or to fill it with a Paint that is more than a single color:
Here is an example, the relevant part is the createRingShape method:
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RingPaintTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RingPaintTestPanel p = new RingPaintTestPanel();
f.getContentPane().add(p);
f.setSize(800,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class RingPaintTestPanel extends JPanel
{
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.RED);
g.drawString("Text", 100, 100);
g.drawString("Text", 300, 100);
Shape ring = createRingShape(100, 100, 80, 20);
g.setColor(Color.CYAN);
g.fill(ring);
g.setColor(Color.BLACK);
g.draw(ring);
Shape otherRing = createRingShape(300, 100, 80, 20);
g.setPaint(new GradientPaint(
new Point(250, 40), Color.RED,
new Point(350, 200), Color.GREEN));
g.fill(otherRing);
g.setColor(Color.BLACK);
g.draw(otherRing);
}
private static Shape createRingShape(
double centerX, double centerY, double outerRadius, double thickness)
{
Ellipse2D outer = new Ellipse2D.Double(
centerX - outerRadius,
centerY - outerRadius,
outerRadius + outerRadius,
outerRadius + outerRadius);
Ellipse2D inner = new Ellipse2D.Double(
centerX - outerRadius + thickness,
centerY - outerRadius + thickness,
outerRadius + outerRadius - thickness - thickness,
outerRadius + outerRadius - thickness - thickness);
Area area = new Area(outer);
area.subtract(new Area(inner));
return area;
}
}
You can use the Shape and Area classes to create interesting effects:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.net.*;
public class Subtract extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int size = 100;
int thickness = 10;
int innerSize = size - (2 * thickness);
Shape outer = new Ellipse2D.Double(0, 0, size, size);
Shape inner = new Ellipse2D.Double(thickness, thickness, innerSize, innerSize);
Area circle = new Area( outer );
circle.subtract( new Area(inner) );
int x = (getSize().width - size) / 2;
int y = (getSize().height - size) / 2;
g2d.translate(x, y);
g2d.setColor(Color.CYAN);
g2d.fill(circle);
g2d.setColor(Color.BLACK);
g2d.draw(circle);
g2d.dispose();
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Subtract");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Subtract());
frame.setLocationByPlatform( true );
frame.setSize(200, 200);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
Using an Area you can also add multiple Shapes together or get the intersection of multiple Shapes.
You could use graphics.setStroke(...) for this. This way the center will be fully transparent and therefore won't cover previously drawn shapes. In my example I had to do some additional calculations because of this method though, to make sure the displayed x and y coordinates are actually the same as the ones of the Ring instance:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example {
public Example() {
ArrayList<Ring> rings = new ArrayList<Ring>();
rings.add(new Ring(10, 10, 100, 20, Color.CYAN));
JPanel panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gg = (Graphics2D) g.create();
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Ring ring : rings) {
// Previously drawn
gg.setColor(Color.BLACK);
String str = "Hello!";
gg.drawString(str, ring.getX() + (ring.getWidth() - gg.getFontMetrics().stringWidth(str)) / 2,
ring.getY() + ring.getHeight() / 2 + gg.getFontMetrics().getAscent());
// The actual ring
ring.draw(gg);
}
gg.dispose();
}
};
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
}
class Ring {
private int x, y, width, height, thickness;
private Color color;
public Ring(int x, int y, int width, int height, int thickness, Color color) {
setX(x);
setY(y);
setWidth(width);
setHeight(height);
setThickness(thickness);
setColor(color);
}
public Ring(int x, int y, int radius, int thickness, Color color) {
this(x, y, radius * 2, radius * 2, thickness, color);
}
public void draw(Graphics2D gg) {
Stroke oldStroke = gg.getStroke();
Color oldColor = gg.getColor();
gg.setColor(Color.BLACK);
gg.setStroke(new BasicStroke(getThickness()));
gg.drawOval(getX() + getThickness() / 2, getY() + getThickness() / 2, getWidth() - getThickness(),
getHeight() - getThickness());
gg.setColor(getColor());
gg.setStroke(new BasicStroke(getThickness() - 2));
gg.drawOval(getX() + getThickness() / 2, getY() + getThickness() / 2, getWidth() - getThickness(),
getHeight() - getThickness());
gg.setStroke(oldStroke);
gg.setColor(oldColor);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getThickness() {
return thickness;
}
public void setThickness(int thickness) {
this.thickness = thickness;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
I want to make JTextArea has a rounded corners, and i did this code :
public BPosTxtArea() {
super();
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground());
g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 15, 15);
super.paintComponent(g);
}
#Override
protected void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(102, 102, 102));
g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 15, 15);
}
but it still has a square border outside like picture bellow :
Can anyone help me?
Start by having a look at How to Use Borders
This is a very simple example:
public class RoundBorder implements Border {
private int radius;
public RoundBorder(int radius) {
this.radius = radius;
}
public int getRadius() {
return radius;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.draw(new RoundRectangle2D.Double(x, y, width - 1, height - 1, getRadius(), getRadius()));
g2d.dispose();
}
#Override
public Insets getBorderInsets(Component c) {
int value = getRadius() / 2;
return new Insets(value, value, value, value);
}
#Override
public boolean isBorderOpaque() {
return false;
}
}
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
public class Example {
public static void main(String[] args) {
new Example();
}
public Example() {
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());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
JTextArea ta = new JTextArea(10, 20);
ta.setBorder(new RoundBorder(20));
JScrollPane sp = new JScrollPane(new JTextArea(10, 20));
sp.setBorder(new RoundBorder(20));
add(ta, gbc);
add(sp, gbc);
}
}
public class RoundBorder implements Border {
private int radius;
public RoundBorder(int radius) {
this.radius = radius;
}
public int getRadius() {
return radius;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.draw(new RoundRectangle2D.Double(x, y, width - 1, height - 1, getRadius(), getRadius()));
g2d.dispose();
}
#Override
public Insets getBorderInsets(Component c) {
int value = getRadius() / 2;
return new Insets(value, value, value, value);
}
#Override
public boolean isBorderOpaque() {
return false;
}
}
}
Problems, the border is painted "within" the component fill area, meaning that the corners will be the same color as the fill area. There's no way around it using Border.
The trick would be to create a second component, onto which you could paint the border (via the paintComponent, filling the area within the border the same color as the text area) and then add the component into that.
Updated
Based on you code example, you're not overriding getInsets, which is going to be very important, the other thing is, it appears that your JTextArea is within a JScrollPane...
public class BPosTextArea extends JTextArea {
private int radius;
public BPosTextArea() {
super(10, 20);
setOpaque(false);
setBorder(null);
setRadius(20);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground());
g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, getRadius(), getRadius());
super.paintComponent(g);
}
#Override
protected void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(102, 102, 102));
g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, getRadius(), getRadius());
}
public void setRadius(int radius) {
this.radius = radius;
repaint();
}
public int getRadius() {
return radius;
}
#Override
public Insets getInsets() {
int value = getRadius() / 2;
return new Insets(value, value, value, value);
}
}
A solution is to set the border to null for the JScrollPane
For a problem I have to draw a circle on the screen with center at coordinates (280,300) with a radius of 50. The hint says: A circle is an oval with the same width and height. The center of this circle is 50 pixels below and 50 pixels to the right of the NW corner of this oval.
There is the TryoutPanel class:
import java.awt.*;
import javax.swing.*;
public class TryoutPanel extends JPanel{
private Color myColor;
public TryoutPanel(Color c){
myColor = c;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
setForeground(myColor);
g.drawString("top",10,50);
g.drawLine(10,60, 200,60);
g.drawString("middle",10,80);
g.drawLine(10,90, 200,90);
g.drawString("bottom",10,110);
g.drawLine(10,120, 200,120);
g.drawRect(200,300,100,50);
g.drawOval(200,300,100,50);
for(int j = 0; j < 9; j++)
g.drawOval(50,200, 10 + 20*j, 210 - 20*j);
}
}
I have to fill in the code in the following:
public void paintComponent(Graphics g){
super.paintComponent(g);
setForeground(myColor);
//INSERT CODE HERE
I tried:
g.drawOval(280,300,50,50);
But it says I used incorrect parameters. What am I doing wrong.
The x/y parameter of drawOval is the top/left corner from where the oval will be drawn
In order to be able to draw the circle around the center point if 230x300, you will need to subtract the radius from each point and then generate a width and height (diameter) of double that...
g.drawOval(230 - radius, 300 - radius, radius * 2, radius * 2);
So, this example basic draws a rectangle around the point of 230x300 with a width/height of 200 (radius = 100) and draws lines through this point to illustrate the center point the oval then drawn about...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TryoutOval {
public static void main(String[] args) {
new TryoutOval();
}
public TryoutOval() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TryoutPanel(Color.RED));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TryoutPanel extends JPanel {
private Color myColor;
public TryoutPanel(Color c) {
myColor = c;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int centerX = 280;
int centerY = 300;
int radius = 50;
int diameter = radius * 2;
int x = centerX - radius;
int y = centerY - radius;
g.setColor(Color.BLACK);
g.drawRect(x, y, diameter, diameter);
g.drawLine(x, y, x + diameter, y + diameter);
g.drawLine(x + diameter, y, x, y + diameter);
g.setColor(myColor);
g.drawOval(x, y, diameter, diameter);
g.fillOval(centerX - 5, centerY - 5, 10, 10);
}
}
}
Oh, and setForeground(myColor); is a horribly bad idea within any paint method as it will cause a paint event to be added to the event queue each time the method is called, which will cause a never ending repaint request which will eventually consume your CPU
Hello i'm trying to do a string inside a rectangle to make custom menus in java I'm using a canvas and doing the following method, but I can't seem to get it right!
public void render(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.WHITE);
Font font = new Font("Verdana", Font.PLAIN, 20);
g2d.setFont(font);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
FontMetrics fm = root.getFontMetrics(font);
g2d.drawString(option, (int)getX() - fm.stringWidth(option)/2, (int) getY() + fm.getHeight());
g2d.drawRect((int)getX() - fm.stringWidth(option)/2 - 20, (int) getY() - fm.getHeight() - 10, (int)getX() - fm.stringWidth(option)/2 + 40 , (int) getY() - fm.getHeight() + 10);
}
The basic problem you have is that you are using the components x/y position where the Graphics context is already translated so that 0x0 is the top/left corner of the component.
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.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawText {
public static void main(String[] args) {
new DrawText();
}
public DrawText() {
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() {
setBackground(Color.BLACK);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
render(g);
g2d.dispose();
}
public void render(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.WHITE);
Font font = new Font("Verdana", Font.PLAIN, 20);
g2d.setFont(font);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
FontMetrics fm = g2d.getFontMetrics();
String option = "This is a test";
int x = (getWidth() - fm.stringWidth(option)) / 2;
int y = ((getHeight() - fm.getHeight()) / 2);
g2d.drawString(option, x, y + fm.getAscent());
g2d.drawRect(
(int)x - 20,
(int)y - 10,
(int)fm.stringWidth(option) + 40,
(int)fm.getHeight() + 20);
}
}
}
For example...
Centering String in Panel
Java center text in rectangle
Updated...
If, each menu item is printed within a single component, then the concept provided above should work. If you are printing multiple items within a single component, you could use something like...
public void render(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.WHITE);
Font font = new Font("Verdana", Font.PLAIN, 20);
g2d.setFont(font);
int x = 0;
int y = 0;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
FontMetrics fm = g2d.getFontMetrics();
String option = "This is a test";
while (x < getWidth()) {
while (y < getHeight()) {
int width = fm.stringWidth(option);
int height= fm.getHeight();
g2d.drawString(option, x + 20, y + fm.getAscent() + 10);
width += 40;
height += 20;
g2d.drawRect(
(int) x,
(int) y,
(int) width,
(int) height);
x += width;
y += height;
}
}
}