I have a JFrame with BorderLayout as the layout manager.
In the south border, I have a JPanel, I want this JPanel's size to be adjustable by the user, i.e. the user can click on the edge of the border and drag it up to make it larger.
Is there any way you know that I can do this?
In order to make panels in a frame individually resizable you need to add them onto a JSplitPane.
Instead of putting it in the South portion of the Frame, put the JSplitPane in the Center. The split pane will make the bottom panel in the split seem like it is in the South, and the top panel in the split will be in the Center of the frame.
Make sure you set the orientation of the two panels with setOrientation(JSplitPane.VERTICAL_SPLIT ).
Then, you can resize the panels that are in the pane.
I think you meant to say JPanel. You can add a custom mouseListener and handle mouse clicks, drags and mouse releases and then resize the panel programmaticaly.
This will demonstrate this. Note that the jframe does NOT resize automatically with the JPanel. To make the effect more visible i painted the panel red and added a beveled border :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
#SuppressWarnings("serial")
public class ResizablePanel extends JPanel {
private boolean drag = false;
private Point dragLocation = new Point();
public ResizablePanel() {
setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
setPreferredSize(new Dimension(500, 500));
final JFrame f = new JFrame("Test");
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
drag = true;
dragLocation = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
drag = false;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (drag) {
if (dragLocation.getX()> getWidth()-10 && dragLocation.getY()>getHeight()-10) {
System.err.println("in");
setSize((int)(getWidth()+(e.getPoint().getX()-dragLocation.getX())),
(int)(getHeight()+(e.getPoint().getY()-dragLocation.getY())));
dragLocation = e.getPoint();
}
}
}
});
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(this,BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
new ResizablePanel();
}
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
I made a class for that if you want to take a look. It isn`t finished yet.
package projetoSplitPainel;
import java.awt.Component;
import java.util.ArrayList;
import javax.swing.JSplitPane;
/**
* This Components is based on the JSplitPane. JSplitPane is used to divide two
* (and only two) Components. This class intend to manipulate the JSplitPane in
* a way that can be placed as many Component as wanted.
*
* #author Bode
*
*/
public class JSplitPaneMultiTabs extends JSplitPane {
private ArrayList<JSplitPane> ecanpsulationList = new ArrayList<JSplitPane>();
private int numberOfComponents = 1;
private int sizeOfDivision = 6;
/**
* Builds the Pane
*/
public JSplitPaneMultiTabs() {
super();
this.setLeftComponent(null);
this.setBorder(null);
ecanpsulationList.add(this);
setAllBorders(sizeOfDivision);
}
/**
*
* #param comp - adds a Component to the Pane
*/
public void addComponent(Component comp) {
JSplitPane capsule = new JSplitPane();
capsule.setRightComponent(null);
capsule.setLeftComponent(comp);
capsule.setDividerSize(sizeOfDivision);
capsule.setBorder(null);
ecanpsulationList.get(numberOfComponents - 1).setRightComponent(capsule);
ecanpsulationList.add(capsule);
numberOfComponents++;
this.fixWeights();
}
/**
*
* #param orientation
* JSplitPane.HORIZONTAL_SPLIT - sets the orientation of the
* Components to horizontal alignment
* #param orientation
* JSplitPane.VERTICAL_SPLIT - sets the orientation of the
* Components to vertical alignment
*/
public void setAlignment(int orientation) {
for (int i = 0; i < numberOfComponents; i++) {
ecanpsulationList.get(i).setOrientation(orientation);
}
}
/**
*
* #param newSize - resizes the borders of the all the Components of the Screen
*/
public void setAllBorders(int newSize) {
this.setDividerSize(newSize);
for (int i = 0; i < numberOfComponents; i++) {
ecanpsulationList.get(i).setDividerSize(newSize);
}
}
/**
* each Component added needs to be readapteded to the screen
*/
private void fixWeights() {
ecanpsulationList.get(0).setResizeWeight(1.0);
for (int i = 1; i < numberOfComponents; i++) {
double resize = (double) 1 / (double) (i + 1);
ecanpsulationList.get(numberOfComponents - i - 1).setResizeWeight(
resize);
}
ecanpsulationList.get(numberOfComponents - 1).setResizeWeight(0.0);
}
}
So i Made a Class which does mostly what the OP wanted. Basically it is a Pannel which can be resized when clicking at the border. It also (tries) to resize all the components contained inside it to fit the new size. It also tries to detect collision between other components in the parent frame to prevent overlapping as much as possible.
Anyway here you go:
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JDesktopPane;
#SuppressWarnings("serial")
public class ResizablePanel extends JDesktopPane {
private boolean drag = false;
private boolean top =false;
private boolean bottom =false;
private boolean left=false;
private boolean right =false;
private Point dragLocation = new Point();
public ResizablePanel() {
setMinimumSize(new Dimension(200, 200));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
evaluateMousePress(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
drag = false;
setCursor(Cursor.getDefaultCursor());
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
evaluateMouseDrag(e.getPoint());
}
#Override
public void mouseMoved(MouseEvent e) {
evaluateMouseHover(e.getPoint());
}
});
}
#Override
public void setBounds(int x, int y, int width, int height) {
Rectangle oldBounds=getBounds();
Rectangle newBounds = new Rectangle(x, y, width, height);
super.setBounds(x, y, width, height);
resizeSingleComponent(this,oldBounds, newBounds);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Stroke stroke = g2.getStroke();
g2.setStroke(new BasicStroke(5));
g.drawRect(0, 0, getBounds().width, getBounds().height);
g2.setStroke(stroke);
}
private void resizeSingleComponent(Component component , Rectangle oldBounds , Rectangle newBounds) {
if(component instanceof Container) {
if(!component.equals(this)) {
Rectangle componentBounds = component.getBounds();
double x = getNew(componentBounds.getX(), oldBounds.getWidth(), newBounds.getWidth());
double y = getNew(componentBounds.getY(), oldBounds.getHeight(), newBounds.getHeight());
double width = getNew(componentBounds.getWidth(), oldBounds.getWidth(), newBounds.getWidth());
double height = getNew(componentBounds.getHeight(), oldBounds.getHeight(), newBounds.getHeight());
componentBounds.width = (int) Math.round(width);
componentBounds.height = (int) Math.round(height);
componentBounds.x = (int) Math.round(x);
componentBounds.y = (int) Math.round(y);
component.setBounds(componentBounds);
}
for(Component child:((Container) component).getComponents())
resizeSingleComponent(child, oldBounds, newBounds);
}
else {
Rectangle componentBounds = component.getBounds();
double x = getNew(componentBounds.getX(), oldBounds.getWidth(), newBounds.getWidth());
double y = getNew(componentBounds.getY(), oldBounds.getHeight(), newBounds.getHeight());
double width = getNew(componentBounds.getWidth(), oldBounds.getWidth(), newBounds.getWidth());
double height = getNew(componentBounds.getHeight(), oldBounds.getHeight(), newBounds.getHeight());
componentBounds.width = (int) Math.round(width);
componentBounds.height = (int) Math.round(height);
componentBounds.x = (int) Math.round(x);
componentBounds.y = (int) Math.round(y);
component.setBounds(componentBounds);
}
}
private void evaluateMouseDrag(Point point) {
if (drag) {
if (top || left || right || bottom) {
int heightIncrement=0;
int widthIncrement=0;
int posX = getBounds().x;
int posY = getBounds().y;
if(top || bottom)
heightIncrement = (int) (point.getY()-dragLocation.getY());
if(left || right)
widthIncrement = (int) (point.getX()-dragLocation.getX());
if(top) {
posY = posY+heightIncrement;
heightIncrement=-heightIncrement;
}
if(left) {
posX=posX+widthIncrement;
widthIncrement=-widthIncrement;
}
if(right)
dragLocation.x=(int) point.getX();
if(bottom)
dragLocation.y=(int) point.getY();
Rectangle bounds = new Rectangle(posX, posY, getWidth()+ widthIncrement,getHeight()+ heightIncrement);
justifyCollision(bounds,point);
}
}
}
private void evaluateMousePress(Point point) {
drag = true;
dragLocation = point;
top=dragLocation.getY() <=5;
left=dragLocation.getX() <=5;
bottom = dragLocation.getY() >=getHeight()-5;
right = dragLocation.getX() >=getWidth()-5;
setResizeCursor(point);
}
private void evaluateMouseHover(Point point) {
if(!drag) {
top=point.getY() <=5;
left=point.getX() <=5;
bottom = point.getY() >=getHeight()-5;
right = point.getX() >=getWidth()-5;
setResizeCursor(point);
}
}
private void justifyCollision(Rectangle bounds, Point point) {
//justify undersizing
if(bounds.width<getMinimumSize().width) {
if(left)
bounds.x= getBounds().x;
bounds.width=getWidth();
}
if(bounds.height<getMinimumSize().height) {
if(top)
bounds.y=getBounds().y;
bounds.height=getHeight();
}
Container parent = getParent();
//justify parent container bounds
if(bounds.x<0 ||bounds.width+bounds.x>parent.getWidth()) {
bounds.width = getWidth();
if(right &&!(bounds.width+bounds.x>parent.getWidth()))
dragLocation.x=(int) point.getX();
if(bounds.x<0)
bounds.x=0;
}
if(bounds.y<0 ||bounds.height+bounds.y>parent.getHeight()) {
bounds.height = getHeight();
if(bottom &&!(bounds.height+bounds.y>parent.getHeight()))
dragLocation.y=(int) point.getY();
if(bounds.y<0)
bounds.y=0;
}
//justify any other component in it's way
for(Component c:parent.getComponents()) {
if(!c.equals(this) &&c.getBounds().intersects(bounds)) {
evaluateOverlaps(bounds, c,point);
}
}
setBounds(bounds);
}
private Rectangle evaluateOverlaps(Rectangle bounds , Component component,Point point) {
if(bounds.intersects(component.getBounds())) {
if(component instanceof ResizablePanel) {
ResizablePanel panel=(ResizablePanel) component;
Rectangle panelBound=panel.getBounds();
if(top || bottom) {
panelBound.height = panelBound.height - bounds.intersection(panelBound).height;
if(panelBound.height<panel.getMinimumSize().height) {
panelBound.height=panel.getMinimumSize().height;
bounds.height = getHeight();
if(top) {
bounds.y = component.getBounds().y+component.getHeight();
}
}
else if(bottom) {
panelBound.y = panelBound.y + bounds.intersection(panelBound).height;
}
}
else if(left || right) {
panelBound.width = panelBound.width - bounds.intersection(panelBound).width;
if(panelBound.width<panel.getMinimumSize().width) {
panelBound.width=panel.getMinimumSize().width;
bounds.width = getWidth();
if(left) {
bounds.x = component.getBounds().x+component.getWidth();
}
}
else if(right) {
panelBound.x = panelBound.x + bounds.intersection(panelBound).width;
}
}
panel.setBounds(panelBound);
return bounds;
}
if(left || right) {
bounds.width = getWidth();
if(left) {
bounds.x = component.getBounds().x+component.getWidth();
}
}
if(top || bottom) {
bounds.height = getHeight();
if(top) {
bounds.y = component.getBounds().y+component.getHeight();
}
}
}
return bounds;
}
private void setResizeCursor(Point point) {
if(top) {
if(left)
setCursor(new Cursor(Cursor.NW_RESIZE_CURSOR));
else if(right)
setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
else
setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
}
else if(bottom) {
if(left)
setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
else if(right)
setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
else
setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
}
else if (left)
setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
else if (right)
setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
else
setCursor(Cursor.getDefaultCursor());
}
private long getNew(double size,double oldMax,double newMax) {
double value = ((size/oldMax)*newMax);
return Math.round(value);
}
}
You might have to specify JFrame.setResizeable = true; on both the Parent JFrame(the one with the border layout) and the child JFrame.
You also might want to use a JPanel in the south border.
Related
I'm trying to make a racing game with the top down view on a static player in the middle of the screen, so instead of moving the player through the map, the map would move around the player. Since it's a racing game, I wanted it to also be somewhat similar to a car, but I've been having trouble with rotating the map around the player and having that work with translations.
I've tried keeping track of the center by adding or subtracting from it, which is what I did for the translations, but it doesn't work with the rotate method. The rotate function wouldn't rotate about the player and instead would rotate the player around some other point, and the translations would snap to a different location from the rotations. I'm sure my approach is flawed, and I have read about layers and such, but I'm not sure what I can do with them or how to use them. Also, any recommendations as to how to use java graphics in general would be greatly appreciated!
This is what I have in my main:
import javax.swing.JFrame;
import java.awt.BorderLayout;
public class game
{
public static void main(String []args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 1000;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Map b = new Map();
frame.add(b,BorderLayout.CENTER);
frame.setVisible(true);
b.startAnimation();
}
}
And this is the class that handles all the graphics
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Map extends JComponent implements Runnable, KeyListener
{
private int speed = 5;
private int xcenter = 500; // starts on player
private int ycenter = 300;
private double angle = 0.0;
private int[] xcords = {xcenter+10, xcenter, xcenter+20};
private int[] ycords = {ycenter-10, ycenter+20, ycenter+20};
private boolean moveNorth = false;
private boolean moveEast = false;
private boolean moveSouth = false;
private boolean moveWest = false;
public Map()
{
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void startAnimation()
{
Thread t = new Thread(this);
t.start();
}
public void paintComponent(Graphics g)
{
g.fillPolygon(xcords, ycords, 3);
// move screen
if(moveNorth)
{
ycenter += speed;
g.translate(xcenter, ycenter);
}
else if(moveEast)
{
angle += ((1 * Math.PI/180) % (2 * Math.PI));
((Graphics2D) g).rotate(angle, 0, 0);
}
else if(moveSouth)
{
System.out.println(xcenter + ", " + ycenter);
ycenter -= speed;
((Graphics2D) g).rotate(angle, 0, 0);
g.translate(xcenter, ycenter);
}
else if(moveWest)
{
angle -= Math.toRadians(1) % (2 * Math.PI);
((Graphics2D) g).rotate(angle, 0, 0);
}
for(int i = -10; i < 21; i++)
{
g.drawLine(i * 50, -1000, i * 50, 1000);
g.drawLine(-1000, i * 50, 1000, i * 50);
}
g.drawOval(0, 0, 35, 35);
}
public void run()
{
while (true)
{
try
{
if(moveNorth || moveEast || moveSouth || moveWest)
{
repaint();
}
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
public void keyPressed(KeyEvent e)
{
if(e.getExtendedKeyCode() == 68) // d
{
moveEast = true;
}
else if(e.getExtendedKeyCode() == 87) // w
{
moveNorth = true;
}
else if(e.getExtendedKeyCode() == 65) // a
{
moveWest = true;
}
else if(e.getExtendedKeyCode() == 83) // s
{
moveSouth = true;
}
}
public void keyReleased(KeyEvent e)
{
moveNorth = false;
moveEast = false;
moveSouth = false;
moveWest = false;
}
public void keyTyped(KeyEvent e)
{
}
}
You have to keep in mind that transformations are compounding, so if you rotate the Graphics context by 45 degrees, everything painted after it will be rotated 45 degrees (around the point of rotation), if you rotate it again by 45 degrees, everything painted after it will be rotated a total of 90 degrees.
If you want to paint additional content after a transformation, then you either need to undo the transformation, or, preferably, take a snapshot of the Graphics context and dispose of it (the snapshot) when you're done.
You also need to beware of the point of rotation, Graphics2D#rotate(double) will rotate the Graphics around the point of origin (ie 0x0), which may not be desirable. You can change this by either changing the origin point (ie translate) or using Graphics2D#rotate(double, double, double), which allows you to define the point of rotation.
For example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class TestPane extends JPanel {
enum Direction {
LEFT, RIGHT;
}
protected enum InputAction {
PRESSED_LEFT, PRESSED_RIGHT, RELEASED_LEFT, RELEASED_RIGHT
}
private BufferedImage car;
private BufferedImage road;
private Set<Direction> directions = new TreeSet<>();
private double directionOfRotation = 0;
public TestPane() throws IOException {
car = ImageIO.read(getClass().getResource("/images/Car.png"));
road = ImageIO.read(getClass().getResource("/images/Road.png"));
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), InputAction.PRESSED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), InputAction.RELEASED_LEFT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), InputAction.PRESSED_RIGHT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), InputAction.RELEASED_RIGHT);
am.put(InputAction.PRESSED_LEFT, new DirectionAction(Direction.LEFT, true));
am.put(InputAction.RELEASED_LEFT, new DirectionAction(Direction.LEFT, false));
am.put(InputAction.PRESSED_RIGHT, new DirectionAction(Direction.RIGHT, true));
am.put(InputAction.RELEASED_RIGHT, new DirectionAction(Direction.RIGHT, false));
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (directions.contains(Direction.RIGHT)) {
directionOfRotation += 1;
} else if (directions.contains(Direction.LEFT)) {
directionOfRotation -= 1;
}
// No doughnuts for you :P
if (directionOfRotation > 180) {
directionOfRotation = 180;
} else if (directionOfRotation < -180) {
directionOfRotation = -180;
}
repaint();
}
});
timer.start();
}
protected void setDirectionActive(Direction direction, boolean active) {
if (active) {
directions.add(direction);
} else {
directions.remove(direction);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(213, 216);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
drawRoadSurface(g2d);
drawCar(g2d);
g2d.dispose();
}
protected void drawCar(Graphics2D g2d) {
g2d = (Graphics2D) g2d.create();
int x = (getWidth() - car.getWidth()) / 2;
int y = (getHeight() - car.getHeight()) / 2;
g2d.drawImage(car, x, y, this);
g2d.dispose();
}
protected void drawRoadSurface(Graphics2D g2d) {
g2d = (Graphics2D) g2d.create();
// This sets the point of rotation at the center of the window
int midX = getWidth() / 2;
int midY = getHeight() / 2;
g2d.rotate(Math.toRadians(directionOfRotation), midX, midY);
// We then need to offset the top/left corner so that what
// we want draw appears to be in the center of the window,
// and thus will be rotated around it's center
int x = midX - (road.getWidth() / 2);
int y = midY - (road.getHeight() / 2);
g2d.drawImage(road, x, y, this);
g2d.dispose();
}
protected class DirectionAction extends AbstractAction {
private Direction direction;
private boolean active;
public DirectionAction(Direction direction, boolean active) {
this.direction = direction;
this.active = active;
}
#Override
public void actionPerformed(ActionEvent e) {
setDirectionActive(direction, active);
}
}
}
}
I'm trying to create a graphical component that allows me to draw one rectangle on a selected image (the rectangle must be drawn using drag-and-drop operations): the purpose of this component is to get the coordinates and the size of the rectangle drawn; the second goal is to provide a component which can be easily integrated in a graphical user interface.
The authors of this example created a subclass of JLabel in order to draw the image, then they added a MouseInputAdapter to the instance of this subclass in order to deal with the drawing of the rectangle.
I was inspired by that example, with the difference that I have created a subclass of JPanel class: I named it FigurePanel class. Then I made some changes in order to provide the following features:
if the image is larger than the instance of FigurePanel, then the scrollers must appear;
if the image is smaller than the instance of FigurePanel, then this image must be placed in the center of the panel;
while the user draws the rectangle, it should not extend beyond the limits of the image.
Here is the source code of FigurePanel class.
package imageselectionproject;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;
public class FigurePanel extends JPanel
{
private Image backgroundImage = null;
private Rectangle imageLimits = new Rectangle(0, 0, getWidth(), getHeight());
private Rectangle currentRect = null;
private Rectangle rectToDraw = null;
private final Rectangle previousRectDrawn = new Rectangle();
public FigurePanel()
{
setOpaque(true);
SelectionListener listener = new SelectionListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize()
{
return backgroundImage == null ? super.getPreferredSize() : new Dimension(backgroundImage.getWidth(this), backgroundImage.getHeight(this));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g); //paints the background and image
if (backgroundImage != null)
{
g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
}
// If currentRect exists, paint a box on top.
if (currentRect != null)
{
// Draw a rectangle on top of the image.
g.setXORMode(Color.white); // Color of line varies
// depending on image colors
g.drawRect(rectToDraw.x, rectToDraw.y,
rectToDraw.width - 1, rectToDraw.height - 1);
System.out.println(rectToDraw);
}
}
public void setImage(Image image)
{
int x = 0;
int y = 0;
if (image != null)
{
backgroundImage = image;
// The following instructions are used to center the image on the panel.
/*x = (getSize().width - image.getWidth(this)) / 2;
y = (getSize().height - image.getHeight(this)) / 2;
if (x < 0) x = 0;
if (y < 0) y = 0;*/
}
else
{
backgroundImage = null;
}
currentRect = null;
setSize(getPreferredSize());
imageLimits.setBounds(x, y, getWidth(), getHeight());
System.out.println("imageLimits = " + imageLimits);
repaint();
}
private void updateDrawableRect()
{
int x = currentRect.x;
int y = currentRect.y;
int width = currentRect.width;
int height = currentRect.height;
// Make the width and height positive, if necessary.
if (width < 0)
{
width = 0 - width;
x = x - width + 1;
if (x < 0)
{
width += x;
x = 0;
}
}
if (height < 0)
{
height = 0 - height;
y = y - height + 1;
if (y < 0)
{
height += y;
y = 0;
}
}
// The rectangle should not extend beyond the boundaries of the image.
if (x < imageLimits.x)
{
width -= (imageLimits.x - x);
x = imageLimits.x;
}
else if ((x + width) > imageLimits.x + imageLimits.width)
{
width = imageLimits.x + imageLimits.width - x;
}
if (y < imageLimits.y)
{
height -= (imageLimits.y - y);
y = imageLimits.y;
}
if ((y + height) > imageLimits.y + imageLimits.height)
{
height = imageLimits.y + imageLimits.height - y;
}
// Update rectToDraw after saving old value.
if (rectToDraw != null)
{
previousRectDrawn.setBounds(rectToDraw.x, rectToDraw.y,
rectToDraw.width, rectToDraw.height);
rectToDraw.setBounds(x, y, width, height);
}
else
{
rectToDraw = new Rectangle(x, y, width, height);
}
}
private class SelectionListener extends MouseInputAdapter
{
#Override
public void mousePressed(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
updateDrawableRect();
repaint();
}
#Override
public void mouseDragged(MouseEvent e)
{
updateSize(e.getX(), e.getY());
}
#Override
public void mouseReleased(MouseEvent e)
{
updateSize(e.getX(), e.getY());
}
/*
* Update the size of the current rectangle
* and call repaint. Because currentRect
* always has the same origin, translate it
* if the width or height is negative.
*
* For efficiency (though
* that isn't an issue for this program),
* specify the painting region using arguments
* to the repaint() call.
*
*/
void updateSize(int x, int y)
{
currentRect.setSize(x - currentRect.x, y - currentRect.y);
updateDrawableRect();
Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
repaint(totalRepaint.x, totalRepaint.y,
totalRepaint.width, totalRepaint.height);
}
}
}
The method setImage is used to set a new image, so it invokes the method repaint to redraw the graphical component. In the code shown above, I disabled (via comments) instructions to center the image: in this way, the component seems to work properly.
Instead, if I enable such instructions, the image is correctly positioned in the center of the panel when it is smaller than the panel itself, however, I encountered the following problem: suppose that it is currently displayed an image larger than the panel, if the new image that I decide to load is smaller than the currently displayed image, then the new image is not displayed; if I try to reload the new image, then it appears.
Why does this problem occur? How to solve it?
I also created the FigurePanelTest class in order to test the FigurePanel class.
package imageselectionproject;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
public class FigurePanelTest extends JFrame
{
public FigurePanelTest()
{
FigurePanel imagePanel = new FigurePanel();
JScrollPane imageScrollPane = new JScrollPane();
imageScrollPane.setPreferredSize(new Dimension(420, 250));
imageScrollPane.setViewportView(imagePanel);
JButton imageButton = new JButton("Load Image");
imageButton.addActionListener(
new ActionListener()
{
#Override
public void actionPerformed(ActionEvent evt)
{
JFileChooser fc = new JFileChooser();
int returnValue = fc.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
File selectedFile = fc.getSelectedFile();
System.out.println(selectedFile.getName());
try
{
Image image = ImageIO.read(selectedFile.getAbsoluteFile());
imagePanel.setImage(image);
imageScrollPane.getViewport().setViewPosition(new Point(0, 0));
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
);
Container container = getContentPane();
container.setLayout(new FlowLayout());
container.add(imageScrollPane);
container.add(imageButton);
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Here is the main.
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FigurePanelTest().setVisible(true);
}
});
}
For Andrew, a single program:
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.MouseInputAdapter;
public class TestDrawPanel {
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FigurePanelTest().setVisible(true);
}
});
}
}
class FigurePanelTest extends JFrame {
public FigurePanelTest() {
final FigurePanel imagePanel = new FigurePanel();
final JScrollPane imageScrollPane = new JScrollPane();
imageScrollPane.setPreferredSize(new Dimension(420, 250));
imageScrollPane.setViewportView(imagePanel);
JButton imageButton = new JButton("Load Image");
imageButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
JFileChooser fc = new JFileChooser();
int returnValue = fc.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
File selectedFile = fc.getSelectedFile();
System.out.println(selectedFile.getName());
try {
Image image = ImageIO.read(selectedFile.getAbsoluteFile());
imagePanel.setImage(image);
imageScrollPane.getViewport()
.setViewPosition(new Point(0, 0));
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Container container = getContentPane();
container.setLayout(new FlowLayout());
container.add(imageScrollPane);
container.add(imageButton);
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class FigurePanel extends JPanel {
private Image backgroundImage = null;
private Rectangle imageLimits = new Rectangle(0, 0, getWidth(), getHeight());
private Rectangle currentRect = null;
private Rectangle rectToDraw = null;
private final Rectangle previousRectDrawn = new Rectangle();
public FigurePanel() {
setOpaque(true);
SelectionListener listener = new SelectionListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return backgroundImage == null ? super.getPreferredSize()
: new Dimension(backgroundImage.getWidth(this),
backgroundImage.getHeight(this));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // paints the background and image
if (backgroundImage != null) {
g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
}
// If currentRect exists, paint a box on top.
if (currentRect != null) {
// Draw a rectangle on top of the image.
g.setXORMode(Color.white); // Color of line varies
// depending on image colors
g.drawRect(rectToDraw.x, rectToDraw.y, rectToDraw.width - 1,
rectToDraw.height - 1);
System.out.println(rectToDraw);
}
}
public void setImage(Image image) {
int x = 0;
int y = 0;
if (image != null) {
backgroundImage = image;
// The following instructions are used to center the image on the
// panel.
/*
* x = (getSize().width - image.getWidth(this)) / 2; y =
* (getSize().height - image.getHeight(this)) / 2;
*
* if (x < 0) x = 0; if (y < 0) y = 0;
*/
} else {
backgroundImage = null;
}
currentRect = null;
setSize(getPreferredSize());
imageLimits.setBounds(x, y, getWidth(), getHeight());
System.out.println("imageLimits = " + imageLimits);
repaint();
}
private void updateDrawableRect() {
int x = currentRect.x;
int y = currentRect.y;
int width = currentRect.width;
int height = currentRect.height;
// Make the width and height positive, if necessary.
if (width < 0) {
width = 0 - width;
x = x - width + 1;
if (x < 0) {
width += x;
x = 0;
}
}
if (height < 0) {
height = 0 - height;
y = y - height + 1;
if (y < 0) {
height += y;
y = 0;
}
}
// The rectangle should not extend beyond the boundaries of the image.
if (x < imageLimits.x) {
width -= (imageLimits.x - x);
x = imageLimits.x;
} else if ((x + width) > imageLimits.x + imageLimits.width) {
width = imageLimits.x + imageLimits.width - x;
}
if (y < imageLimits.y) {
height -= (imageLimits.y - y);
y = imageLimits.y;
}
if ((y + height) > imageLimits.y + imageLimits.height) {
height = imageLimits.y + imageLimits.height - y;
}
// Update rectToDraw after saving old value.
if (rectToDraw != null) {
previousRectDrawn.setBounds(rectToDraw.x, rectToDraw.y,
rectToDraw.width, rectToDraw.height);
rectToDraw.setBounds(x, y, width, height);
} else {
rectToDraw = new Rectangle(x, y, width, height);
}
}
private class SelectionListener extends MouseInputAdapter {
#Override
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
updateDrawableRect();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
updateSize(e.getX(), e.getY());
}
#Override
public void mouseReleased(MouseEvent e) {
updateSize(e.getX(), e.getY());
}
/*
* Update the size of the current rectangle and call repaint. Because
* currentRect always has the same origin, translate it if the width or
* height is negative.
*
* For efficiency (though that isn't an issue for this program), specify
* the painting region using arguments to the repaint() call.
*/
void updateSize(int x, int y) {
currentRect.setSize(x - currentRect.x, y - currentRect.y);
updateDrawableRect();
Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
repaint(totalRepaint.x, totalRepaint.y, totalRepaint.width,
totalRepaint.height);
}
}
}
The problem is calculating the x and y in the setImage().It's not calculating the center of panel correctly.I'm saying this by checking the values of x and y after loading small and large images many times
However I tried putting the centering the image inside paintComponent and it worked perfectly
if (backgroundImage != null) {
imageLimits.x = (this.getWidth() - backgroundImage.getWidth(this)) / 2;
imageLimits.y = (this.getHeight() - backgroundImage.getHeight(this)) / 2;
g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
}
I made a mini code that draw oval and link each other , now i try to move the oval(Circle) but I have a problem (in coding)
// Panneau.java
public class Panneau extends JPanel {
private int R = 20;
private boolean isDrag = false;
String text = "stack";
int x = 250, y = 200;
int height = 50, width = 50;
Random Rnd = new Random();
int rand=Rnd.nextInt();
int r=Math.abs(rand%250);
int r2=Math.abs(rand%250);
public Panneau() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if ((x<=e.getX() && x+R>=e.getX()) && ( y<=e.getY() && y+R>=e.getY())) {
moveVertex(e.getX(),e.getY());
isDrag = true;
}
}
#Override
public void mouseReleased(MouseEvent e) {
isDrag = false;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (isDrag) moveVertex(e.getX(),e.getY());
}
});
}
private void moveVertex(int x1, int y1) {
if ((x!=x1) || (y!=y1)) {
x=x1-10;
y=y1-10;
repaint();
}
}
#Override
protected void paintComponent(Graphics g){
// declaration
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine(x,y,x+r,y+r2);
g.setColor(Color.yellow);
g.fillOval(x-height/2, y-width/2,width, height);
g.fillOval((x-height/2)+r, (y-width/2)+r2,width, height);
FontMetrics fm = g.getFontMetrics();
double textWidth = fm.getStringBounds(text, g).getWidth();
g.setColor(Color.blue);
g.drawString(text, (int) (x - textWidth/2),(int) (y + fm.getMaxAscent() / 2));
g.drawString(text, (int) (x - textWidth/2)+r,(int) (y + fm.getMaxAscent() / 2)+r2);
}
}
I must move the two circles and the line must not move(Graph node)
please help me and thanks :)
After the update ( thanks to MadProgrammer) now I can move all the figure ( but if I clicked in the red circle only) , I want to move just circles thanks :)
Basically, because instead of using reapint(int, int) you could use repaint()
private void moveVertex(int x1, int y1) {
int OFFSET = 1;
if ((x != x1) || (y != y1)) {
x = x1 - 10;
y = y1 - 10;
repaint();
}
}
This will ensure that the entire component is repainted.
While I wouldn't discount the use of repaint(int, int), because your painting process is relatively simple, it's not going to provide you with a great deal of benefit at this stage
Updated with additional example
IF I understand, you want to be able to move a single node and have the line remain joined.
While it might be possible to implement within the code you have available, a simpler soltution would be to take advantage of the 2D Graphics Shape API, this provides a number of really useful functions, including determining of points fall within a given shape.
It also means you don't need to keep track of a large number of parameters, but instead, get a self contained object that just knows how it should be painted...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestGraphNode {
public static void main(String[] args) {
new TestGraphNode();
}
public TestGraphNode() {
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 Panneau());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Panneau extends JPanel {
private int radius = 50;
private String text = "stack";
private List<Ellipse2D> nodes;
private Ellipse2D dragged;
private Point offset;
public Panneau() {
nodes = new ArrayList<>(25);
nodes.add(new Ellipse2D.Float(50 - (radius / 2), 100 - (radius / 2), radius, radius));
nodes.add(new Ellipse2D.Float(350 - (radius / 2), 100 - (radius / 2), radius, radius));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
for (Ellipse2D node : nodes) {
if (node.contains(e.getPoint())) {
System.out.println("Clicked...");
dragged = node;
// Adjust for the different between the top/left corner of the
// node and the point it was clicked...
offset = new Point(node.getBounds().x - e.getX(), node.getBounds().y - e.getY());
// Highlight the clicked node
repaint();
break;
}
}
}
#Override
public void mouseReleased(MouseEvent e) {
// Erase the "click" highlight
if (dragged != null) {
repaint();
}
dragged = null;
offset = null;
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (dragged != null && offset != null) {
// Adjust the position of the drag point to allow for the
// click point offset
Point to = e.getPoint();
to.x += offset.x;
to.y += offset.y;
// Modify the position of the node...
Rectangle bounds = dragged.getBounds();
bounds.setLocation(to);
dragged.setFrame(bounds);
// repaint...
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
// declaration
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Draw the connecting lines first
// This ensures that the lines are under the nodes...
Point p = null;
for (Ellipse2D node : nodes) {
g2d.setColor(Color.BLACK);
Point to = node.getBounds().getLocation();
to.x += radius / 2;
to.y += radius / 2;
if (p != null) {
g2d.draw(new Line2D.Float(p, to));
}
p = to;
}
// Draw the nodes...
for (Ellipse2D node : nodes) {
g2d.setColor(Color.yellow);
g2d.fill(node);
if (node == dragged) {
g2d.setColor(Color.BLUE);
g2d.draw(node);
}
g2d.setColor(Color.BLUE);
FontMetrics fm = g.getFontMetrics();
int textWidth = fm.stringWidth(text);
int x = node.getBounds().x;
int y = node.getBounds().y;
int width = node.getBounds().width;
int height = node.getBounds().height;
g.drawString(text,
x + ((width - textWidth)) / 2,
y + ((height - fm.getHeight()) / 2) + fm.getAscent());
}
g2d.dispose();
}
}
}
I am using JButton's Action listener to draw different shapes.To keep previously drawn shapes on panel all time, I've used an arraylist in which all drawn shapes has added and repaint whole list.How can I drag any shape while others display on Jpanel all the time?
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("====>>> " + s);
switch (s) {
case "Button1":
Activity act = new Activity();
act.setArcH(15);
act.setArcW(15);
act.setBreadth(40);
act.setLength(50);
act.setXpoint(x);
act.setYpoint(y);
//==========================================================
obj = new ShapePoints();
obj.setShapeId(ShapesID.ROUND_RECTANGLE_ID);
obj.setxPoint(act.getXpoint());
obj.setyPoint(act.getYpoint());
obj.setLength(act.getLength());
obj.setBreadth(act.getBreadth());
obj.setArcW(act.getArcW());
obj.setArcH(act.getArcH());
shapePoints.add(obj);
Iterator itr = shapePoints.iterator();
while (itr.hasNext()) {
ShapePoints sp = (ShapePoints) itr.next();
switch (sp.getShapeId()) {
case ShapesID.ARROW_ID:
break;
case ShapesID.CIRCLE_ID:
g.drawOval(obj.getxPoint(), obj.getyPoint(), obj.getLength(), obj.getBreadth());
break;
case ShapesID.CON_CIRCLE_ID:
g.drawOval(sp.getxPoint(), sp.getyPoint(), sp.getLength(), sp.getLength());
g.fillOval(sp.getxPoint() + 10, sp.getyPoint() + 10, sp.getBreadth() / 2, sp.getBreadth() / 2);
break;
case ShapesID.RECTANGLE_ID:
break;
case ShapesID.ROUND_RECTANGLE_ID:
g.drawRoundRect(obj.getxPoint(), obj.getyPoint(), obj.getLength(), obj.getBreadth(),
obj.getArcW(), obj.getArcH());
break;
}
}
break;
this is for 1 button
You need to add a mouselistener and a mousemotionlistener (usually you make a single instance for both) and check wheter your shape contains the mouse pressed event or not. If yes, you keep track of where the mouse is dragged to translate your shape and continuously call repaint(), like usual.
Single click creates a vertex of a polygon
Double click creates the current drawn polygon (if it has at least 3 vertices) and we create a new one
Right-click clears the current drawn polygon and creates a new one
Press/Drag/Release moves the polygon located under the mouse (if there are several, it takes the first one found. it would probably better to make a reverse for-loop)
Here is an example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestNaming {
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 600;
public static class Drawing extends JPanel {
private static final Font FONT = new Font("Arial", Font.PLAIN, 12);
private List<Polygon> polygons = new ArrayList<Polygon>();
private Polygon currentPolygon = new Polygon();
private MouseAdapter mouseListener = new MouseAdapter() {
private Polygon dragged;
private Point lastLocation;
#Override
public void mousePressed(java.awt.event.MouseEvent e) {
for (Polygon p : polygons) {
if (p.contains(e.getPoint())) {
dragged = p;
lastLocation = e.getPoint();
break;
}
}
}
#Override
public void mouseDragged(java.awt.event.MouseEvent e) {
if (dragged != null) {
dragged.translate(e.getX() - lastLocation.x, e.getY() - lastLocation.y);
lastLocation = e.getPoint();
repaint();
}
}
#Override
public void mouseReleased(java.awt.event.MouseEvent e) {
dragged = null;
lastLocation = null;
}
#Override
public void mouseClicked(java.awt.event.MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
if (e.getClickCount() == 1) {
addPoint(e.getX(), e.getY());
} else if (e.getClickCount() == 2) {
createPolygon();
}
} else if (SwingUtilities.isRightMouseButton(e)) {
clearCurrentPolygon();
}
}
};
public Drawing() {
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
}
protected void addPoint(int x, int y) {
currentPolygon.addPoint(x, y);
repaint();
}
protected void clearCurrentPolygon() {
currentPolygon = new Polygon();
repaint();
}
protected void createPolygon() {
if (currentPolygon.npoints > 2) {
polygons.add(currentPolygon);
}
clearCurrentPolygon();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.setFont(FONT);
for (Polygon polygon : polygons) {
drawPolygon(g, polygon);
}
g.setColor(Color.GREEN);
drawPolygon(g, currentPolygon);
}
private void drawPolygon(Graphics g, Polygon polygon) {
if (polygon.npoints < 3) {
if (polygon.npoints == 1) {
g.fillOval(polygon.xpoints[0] - 2, polygon.ypoints[0] - 2, 4, 4);
drawNthPoint(g, polygon, 0);
} else if (polygon.npoints == 2) {
g.drawLine(polygon.xpoints[0], polygon.ypoints[0], polygon.xpoints[1], polygon.ypoints[1]);
drawNthPoint(g, polygon, 0);
drawNthPoint(g, polygon, 1);
}
} else {
g.drawPolygon(polygon);
for (int i = 0; i < polygon.npoints; i++) {
drawNthPoint(g, polygon, i);
}
}
}
private void drawNthPoint(Graphics g, Polygon polygon, int nth) {
// Only works 26 times!
String name = Character.toString((char) ('A' + nth));
int x = polygon.xpoints[nth];
int height = g.getFontMetrics().getHeight();
int y = polygon.ypoints[nth] < height ? polygon.ypoints[nth] + height : polygon.ypoints[nth];
Rectangle2D stringBounds = g.getFontMetrics().getStringBounds(name, g);
g.drawString(name, x, y);
}
}
protected static void initUI() {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Drawing());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
I'm designing an interface using java swing. There is a canvas for the user to draw shapes (circle, triangle, square, etc.). When the user draws a shape, I want to name each point in the shape alphabetically. I know how to get the coordinates but how do I name the points?
Here is one way to do it. You use Character.toString(char) and use 'A'+offset to get any char from the alphabet.
See in this small demo example, which draws polygons.
Single click creates vertices of your polygon
Double-click stores the current polygon and starts creating a new polygon
Right-click clears the current polygon and starts a new one.
Side-note: positioning of the text is not smart, so it overlaps lines of the polygon sometimes.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestNaming {
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 600;
public static class Drawing extends JPanel {
private static final Font FONT = new Font("Arial", Font.PLAIN, 12);
private List<Polygon> polygons = new ArrayList<Polygon>();
private Polygon currentPolygon = new Polygon();
private MouseAdapter mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(java.awt.event.MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
if (e.getClickCount() == 1) {
addPoint(e.getX(), e.getY());
} else if (e.getClickCount() == 2) {
createPolygon();
}
} else if (SwingUtilities.isRightMouseButton(e)) {
clearCurrentPolygon();
}
}
};
public Drawing() {
addMouseListener(mouseListener);
}
protected void addPoint(int x, int y) {
currentPolygon.addPoint(x, y);
repaint();
}
protected void clearCurrentPolygon() {
currentPolygon = new Polygon();
repaint();
}
protected void createPolygon() {
if (currentPolygon.npoints > 2) {
polygons.add(currentPolygon);
}
clearCurrentPolygon();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.setFont(FONT);
for (Polygon polygon : polygons) {
drawPolygon(g, polygon);
}
g.setColor(Color.GREEN);
drawPolygon(g, currentPolygon);
}
private void drawPolygon(Graphics g, Polygon polygon) {
if (polygon.npoints < 3) {
if (polygon.npoints == 1) {
g.fillOval(polygon.xpoints[0] - 2, polygon.ypoints[0] - 2, 4, 4);
drawNthPoint(g, polygon, 0);
} else if (polygon.npoints == 2) {
g.drawLine(polygon.xpoints[0], polygon.ypoints[0], polygon.xpoints[1], polygon.ypoints[1]);
drawNthPoint(g, polygon, 0);
drawNthPoint(g, polygon, 1);
}
} else {
g.drawPolygon(polygon);
for (int i = 0; i < polygon.npoints; i++) {
drawNthPoint(g, polygon, i);
}
}
}
private void drawNthPoint(Graphics g, Polygon polygon, int nth) {
// Only works 26 times!
String name = Character.toString((char) ('A' + nth));
int x = polygon.xpoints[nth];
int height = g.getFontMetrics().getHeight();
int y = polygon.ypoints[nth] < height ? polygon.ypoints[nth] + height : polygon.ypoints[nth];
g.drawString(name, x, y);
}
}
protected static void initUI() {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Drawing());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
If I'm understanding you correctly, you want to label the coordinates alphabetically (like A, B, C, D)
Since you said you know the coordinates already...use a JLabel:
JLabel A_label = new JLabel("A");
JLabel B_label = new JLabel("B");
A_label.setLocation(shape1_x, shape1_y);
B_label.setLocation(shape2_x, shape2_y);