My experience in Java is very little but I like programming and everything I make I want it to be as good as possible. Having studied Java for a total time of at most 2 days, it is not so easy.
I've been asked to make a Logic Gate Simulator. I've done everything besides the GUI. It is not necessary as given by our teacher but it is for me as communication with the user in such a program is complicated. A GUI will make it much more clear.
I would like to create the gates on a canvas and then be able to move them around. I started by making an AND gate and got it to move around with the mouse when clicked.
I noticed, however, that now I have a canvas on top of everything. Every label,button, etc I add is behind the canvas. It seems like the canvas is necessary in order to move the gate as it is actually repainted when I move it.
The gate AND is made inside a class with paintComponent. Will I have to make every gate in this single class so they can be on the same canvas? How can I make every gate,label,button share the same canvas ?
Here is my code finally.Gates move with a double-click. It is long though.
Main:
package Pack;
import java.util.Scanner;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class Main {
public static JFrame f;
public static void main(String[] args) {
ShapeAnd sh=new ShapeAnd();
ShapeOr sh2=new ShapeOr();
f=new JFrame();
f.add(sh);
f.add(sh2);
f.setVisible(true);
f.setSize(700,600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("LGS");
f.getContentPane().setBackground(Color.RED);
}
}
OR:
package Pack;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class ShapeOr extends JPanel implements MouseListener,MouseMotionListener{
int preX,preY,preX2,preY2,difX,difY;
Graphics g2;
GeneralPath Or;
int lim1x,lim2x,lim1y,lim2y;
boolean check;
public ShapeOr() {
preX=15;
preY=0;
addMouseMotionListener(this);
addMouseListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
lim1x=preX;
lim2x=preX+80;
lim1y=preY;
lim2y=preY+60;
int x1Points[] = {preX,preX+50,preX+60,preX+70,preX+80,preX+70,preX+60,preX+50,preX,preX+10,preX+20,preX+30,preX+20,preX+10,preX};
int y1Points[] = {preY,preY,preY+5,preY+15,preY+30,preY+45,preY+55,preY+60,preY+60,preY+55,preY+45,preY+30,preY+15,preY+5,preY};
GeneralPath Or = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
x1Points.length);
Or.moveTo(preX-15,preY+15);
Or.lineTo(preX+20,preY+15);
Or.moveTo(preX-15,preY+45);
Or.lineTo(preX+20,preY+45);
Or.moveTo(preX,preY);
for (int index = 1; index < x1Points.length; index++) {
Or.lineTo(x1Points[index], y1Points[index]);
};
Or.closePath();
g2.draw(Or);
//check=false;
}
public void mousePressed(MouseEvent e) {
difX=preX-e.getX();
difY=preY-e.getY();
}
public void updateLocation(MouseEvent e){
preX=e.getX()+difX;
preY=e.getY()+difY;
repaint();
}
public void mouseReleased(MouseEvent e) {
check=false;
}
public void mouseMoved(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
int mouseX=e.getX();
int mouseY=e.getY();
if(mouseX>lim1x && mouseX<lim2x && mouseY>lim1y && mouseY<lim2y){
check=true;
}
}
public void mouseExited(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
if(check==true){
updateLocation(e);
}
}
}
AND:
package Pack;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class ShapeAnd extends JPanel implements MouseListener,MouseMotionListener{
int preX,preY,preX2,preY2,difX,difY;
Graphics g2;
GeneralPath And;
int lim1x,lim2x,lim1y,lim2y;
boolean check;
public ShapeAnd() {
addMouseMotionListener(this);
addMouseListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
lim1x=preX+15;
lim2x=preX+95;
lim1y=preY;
lim2y=preY+75;
int x1Points[] = {preX,preX+ 50, preX+60,preX +70,preX+80,preX+70,preX+60,preX+50,preX+0};
int y1Points[] = {preY+0,preY+ 0,preY+5,preY+15,preY+30,preY+45,preY+55,preY+60,preY+60};
GeneralPath And = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
x1Points.length);
And.moveTo(preX,preY+15);
And.lineTo(preX+15,preY+15);
And.moveTo(preX,preY+45);
And.lineTo(preX+15,preY+45);
And.moveTo(preX+15,y1Points[0]);
for (int index = 1; index < x1Points.length; index++) {
And.lineTo(x1Points[index]+15, y1Points[index]);
};
And.closePath();
g2.draw(And);
//check=false;
}
public void mousePressed(MouseEvent e) {
difX=preX-e.getX();
difY=preY-e.getY();
}
public void updateLocation(MouseEvent e){
preX=e.getX()+difX;
preY=e.getY()+difY;
repaint();
}
public void mouseReleased(MouseEvent e) {
check=false;
}
public void mouseMoved(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
int mouseX=e.getX();
int mouseY=e.getY();
if(mouseX>lim1x && mouseX<lim2x && mouseY>lim1y && mouseY<lim2y){
check=true;
}
}
public void mouseExited(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
if(check==true){
updateLocation(e);
}
}
}
PS:Needs a better title, I know.
Thank you for your code post as that helps clarify things quite a bit. My assumption was correct -- you're making your gates extend a GUI component, adding a lot of unnecessary "weight" to them, and making them hard to move around as you'd like, or place multiple ones of them on your GUI.
Suggestions for a solution include:
Make your gates much more light-weight by not having them extend JPanel or any GUI component.
Instead make them "logical" (non-GUI components) that can be drawn by a single drawing component via a public void draw(Graphics2d g2) method. I usually use the paintComponent(Graphics g) method of a single JPanel to do this drawing.
Give this drawing JPanel an ArrayList of your gate objects, and then draw the gates by iterating through the list in the JPanel's single paintComponent method.
Add to the same JPanel a MouseAdapter as both mouse listener and motion listener, and allow this listener to change the state of any of your gate shapes that have been clicked or dragged on.
Allow the gates to draw themselves by giving them a draw(...) method that a drawing component can call,
Give your gate objects a public boolean contains(Point p) method that allows you to tell if the mouse clicks on them
And give them getter and setter methods for their positions, so that this can be checked and changed.
Utilize the functionality classes that derive from the Shape interface (by composition) to help give your own shape the ability to draw itself and move. I've used Path2D objects for this as they can be easily moved by using AffineTransforms.
Example code forthcoming....
All Gate objects can share the same interface,...
interface MyGate {
void draw(Graphics2D g2);
void setPoint(Point p);
Point getPoint();
boolean contains(Point p);
}
an example gate class that implements the above interface
class OrGate implements MyGate {
private Path2D path;
private Point point = new Point(0, 0); // initial Point
public OrGate() {
// initialize the Path2D and give it a winding rule
path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
// lots of "magic" numbers below, a code design "smell"
// better to not do this. Perhaps have a data file to hold
// this information, and have it read on program startup
int preX = 15;
int preY = 0;
int x1Points[] = { preX, preX + 50, preX + 60, preX + 70, preX + 80, preX + 70, preX + 60,
preX + 50, preX, preX + 10, preX + 20, preX + 30, preX + 20, preX + 10, preX };
int y1Points[] = { preY, preY, preY + 5, preY + 15, preY + 30, preY + 45, preY + 55,
preY + 60, preY + 60, preY + 55, preY + 45, preY + 30, preY + 15, preY + 5, preY };
path.moveTo(preX - 15, preY + 15);
path.lineTo(preX + 20, preY + 15);
path.moveTo(preX - 15, preY + 45);
path.lineTo(preX + 20, preY + 45);
path.moveTo(preX, preY);
for (int index = 1; index < x1Points.length; index++) {
path.lineTo(x1Points[index], y1Points[index]);
}
path.closePath();
}
#Override
public void draw(Graphics2D g2) {
// simple method that leverages the Path2D path object
g2.draw(path);
}
#Override
public boolean contains(Point p) {
// simple method that leverages the Path2D path object
return path.contains(p);
}
#Override
public Point getPoint() {
return point;
}
#Override
public void setPoint(Point p) {
Point pOld = this.point;
Point pNew = p;
this.point = p;
// create a transform that helps us move our Path2D
int tx = pNew.x - pOld.x;
int ty = pNew.y - pOld.y;
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
path.transform(at); // and then move it
}
}
Main JPanel that shows use of the MouseAdapter and drawing/dragging of shapes:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class MainGates2 extends JPanel {
private static final int PREF_W = 700;
private static final int PREF_H = 600;
private List<MyGate> gates = new ArrayList<>();
public MainGates2() {
// create a few Gates
MyGate gate1 = new OrGate();
gate1.setPoint(new Point(200, 300)); // move this guy
MyGate gate2 = new OrGate();
// add them to the gates ArrayList
gates.add(gate1);
gates.add(gate2);
// create our mouse listener / adapter and add to JPanel
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// rendering hints to smooth graphics
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through collection and draw
for (MyGate myGate : gates) {
myGate.draw(g2);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
// give our JPanel some size
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
private MyGate selectedGate = null;
private Point p0; // initial Gate location
private Point p1; // first mouse press location
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
p1 = e.getPoint();
for (int i = gates.size() - 1; i >= 0; i--) {
if (gates.get(i).contains(e.getPoint())) {
selectedGate = gates.get(i);
p0 = selectedGate.getPoint();
return;
}
}
p1 = null;
}
#Override
public void mouseReleased(MouseEvent e) {
if (selectedGate != null) {
dragShape(e);
// de-select the gate
selectedGate = null;
p0 = null;
p1 = null;
}
}
public void mouseDragged(MouseEvent e) {
if (selectedGate != null) {
dragShape(e);
}
}
private void dragShape(MouseEvent e) {
Point p2 = e.getPoint(); // current mouse location
int x = p0.x + p2.x - p1.x;
int y = p0.y + p2.y - p1.y;
Point p = new Point(x, y);
selectedGate.setPoint(p);
repaint();
};
}
private static void createAndShowGui() {
// main JPanel
MainGates2 mainPanel = new MainGates2();
JFrame frame = new JFrame("Main Gates2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Related
I am making Conways Game of Life. In the mouse listener I want the cell to appear/disappear on the screen when I click once. I use a 40x40 boolean array (gameState) of 20x20 pixel cells. I want to paint the squares in my paint method using the co-ordinates of my mouse which i get in its clicked method. However, I am getting a null-pointer exception at line 71 and do not know what to do to solve it.
Main
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;
public class mainApplication extends JFrame implements Runnable, MouseListener {
private static final Dimension windowsize = new Dimension(80, 600);
private BufferStrategy strategy;
private Graphics offscreenGraphics;
private static boolean isGraphicsInitialised = false;
private static int rows = 40;
private static int columns = 40;
private static int height = windowsize.height;
private static int width = windowsize.width;
private static Cells cells;
private int xArrayElement,yArrayElement, xPosition, yPosition;
private static boolean gameState[][] = new boolean[rows][columns];
public mainApplication() {
System.out.println(System.getProperty("user.dir"));
setDefaultCloseOperation(EXIT_ON_CLOSE);
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width / 2 - windowsize.width / 2;
int y = screensize.height / 2 - windowsize.height / 2;
setBounds(x, y, screensize.width, screensize.height);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
offscreenGraphics = strategy.getDrawGraphics();
isGraphicsInitialised = true;
// MouseEvent mouseEvent = new MouseEvent();
addMouseListener(this);
// addMouseMotionListener(MouseEvent);
Thread t = new Thread(this);
t.start();
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 1){
xPosition = e.getX();
yPosition = e.getY();
cells.setPosition(xPosition,yPosition);
xArrayElement = (xPosition/20);
yArrayElement = (yPosition/20);
if(gameState[xArrayElement][yArrayElement]){
gameState[xArrayElement][yArrayElement] = false;
}
else if (!gameState[xArrayElement][yArrayElement]) {
gameState[xArrayElement][yArrayElement] = true;
}
}
}
#Override
public void run() {
while (true) {
try { //threads entry point
Thread.sleep(20); //forces us to catch exception
}
catch (InterruptedException e) {
}
}
}
public void paint(Graphics g) {
if (isGraphicsInitialised) {
g = strategy.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 800);
if (gameState[xArrayElement][yArrayElement]) {
g.setColor(Color.WHITE);
cells.paint(g);
}
else if (!gameState[xArrayElement][yArrayElement]) {
g.setColor(Color.BLACK);
g.fillRect(xPosition, yPosition, 20, 20);
}
strategy.show();
}
}
public static void main(String[]args){
mainApplication test = new mainApplication();
}
}
Cells class
import java.awt.*;
public class Cells {
int x;
int y;
public Cells(){
}
public void setPosition(int xi, int xj){
x = xi;
y = xi;
System.out.println(xi);
System.out.println("sjdkgffdjv" + y);
}
public boolean cellState(boolean visible){
return visible;
}
public void paint(Graphics g){
g.drawRect(x, y, 20,20);
}
}
It's because you haven't initialized your cells variable in Main class..
So try this
private static Cells cells = new Cells();
As #nullPointer has pointed out (sorry, dad joke) you're getting a NPE because you haven't initialized the class member Cells. There are also a few other points to make that might unrelated to the question.
Don't create that thread
Swing already uses a thread to handle UI events and drawing so creating another thread is dangerous.
Make Cells immutable
Cells should be immutable. At no point should you need to set the position of a cell. If you need to change where a Cell is at, just dispose of the object and create a new one at that position.
I want to implement a panel that draws two eyes that moving to look up, to the center, or down depending on whether the mouse cursor is above, inside, or below the eyes. I first used this code to make the eyes:
public class EyesPanel extends JPanel implements ActionListener {
// images
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.drawOval(130, 100, 120, 120);
g.drawOval(250, 100, 120, 120);
g.fillOval(175, y, 30, 30); // x: 175 y: 145
g.fillOval(295, y, 30, 30); // x: 295 y: 145
}
And then is time to add event listener to make this class works, but here is the part I stuck. I know how to make graphics move (ActionListener) and I know how to implement MouseInputListener (extends MouseInputListener). However, combining those two together make me feel frustrated. Can anybody tell me how to do it, give me a sample code can be really helpful.
The following is my code so far, not a functioning and complete code:
public class EyesPanel extends JPanel implements ActionListener {
private JPanel panel;
private int y;
private int dy;
private Timer t;
private Mouse move;
public EyesPanel() {
dy = 5;
y = 145;
// mouse detector
this.addMouseListener(new Mouse());
this.addMouseMotionListener(new Mouse());
// Timer
t = new Timer(100, this);
}
// images
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.drawOval(130, 100, 120, 120);
g.drawOval(250, 100, 120, 120);
g.fillOval(175, y, 30, 30); // x: 175 y: 145
g.fillOval(295, y, 30, 30); // x: 295 y: 145
}
public void actionPerformed(ActionEvent event) {
moveDown(); //➜ not complete, don't know how to implement
}
// move up
private void moveUp() {
if (move.move() == 1) {
t.start();
y = y + dy;
repaint();
} else {
t.stop();
}
}
// move down
private void moveDown() {
if (move.move() == -1) {
t.start();
y = y - dy;
repaint();
} else {
t.stop();
}
}
// ➜ not complete, trying, but no clue
}
My mouse event class:
public class Mouse extends MouseInputAdapter {
private int y;
public void mouseEntered(MouseEvent event) {
JPanel pane = (JPanel) event.getSource();
y = pane.getHeight(); // ➜ not complete
}
}
make your class like this, and your gota take the s off super.paintComponents(g);
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.Timer;
import javax.swing.JPanel;
public class EyesPanel extends JPanel implements ActionListener,MouseMotionListener{
private JPanel panel;
private int y;
private int dy;
private Timer t;
public EyesPanel() {
dy = 5;
y = 145;
// mouse detector
this.addMouseMotionListener(this);
// Timer
}
// images
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(130, 100, 120, 120);
g.drawOval(250, 100, 120, 120);
g.fillOval(175, y, 30, 30); // x: 175 y: 145
g.fillOval(295, y, 30, 30); // x: 295 y: 145
}
// move up
// ➜ not complete, trying, but no clue
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println(arg0.getY());
if(arg0.getY() > 101 && arg0.getY() < 187)
y = arg0.getY();
repaint();
}
}
The math for having the eyes follow the cursor is not that complicated.
Here's what my GUI looks like.
I created an Eye class to hold the center of the outer eye socket and the center of the inner eyeball.
I created a MovingEyes class to create the JFrame and a DrawingPanel class to draw the eyes on the DrawingPanel. I created the Eye array to hold 2 eyes in the constructor of the MovingEyes class.
The paintComponent method of the DrawingPanel class does nothing but draw the eyes. The calculation of the center of the black eyeballs happens in another class. I created a couple of convenience methods so that I could draw a circle and fill a circle using the center point and radius.
The EyeballListener class performs the calculation of the two black eyeballs. We compute the theta angle (in radians) for the line that extends from the center of the eye socket to the mouse pointer. Then, we compute the x and y position of the black eyeball using the theta angle and the eyeball distance.
Here's the code.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MovingEyes implements Runnable {
private static final int drawingWidth = 400;
private static final int drawingHeight = 400;
private static final int eyeballHeight = 150;
private static final int eyeballWidthMargin = 125;
private static final int eyeballOuterRadius = 50;
private static final int eyeballInnerRadius = 20;
private DrawingPanel drawingPanel;
private Eye[] eyes;
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new MovingEyes());
}
public MovingEyes() {
this.eyes = new Eye[2];
this.eyes[0] = new Eye(new Point(eyeballWidthMargin, eyeballHeight));
this.eyes[1] = new Eye(new Point(drawingWidth - eyeballWidthMargin,
eyeballHeight));
}
#Override
public void run() {
frame = new JFrame("Moving Eyes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingPanel = new DrawingPanel();
frame.add(drawingPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = -2977860217912678180L;
public DrawingPanel() {
this.addMouseMotionListener(new EyeballListener());
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(drawingWidth, drawingHeight));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
for (Eye eye : eyes) {
drawCircle(g, eye.getOrigin(), eyeballOuterRadius);
fillCircle(g, eye.getEyeballOrigin(), eyeballInnerRadius);
}
}
private void drawCircle(Graphics g, Point origin, int radius) {
g.drawOval(origin.x - radius, origin.y - radius, radius + radius,
radius + radius);
}
private void fillCircle(Graphics g, Point origin, int radius) {
g.fillOval(origin.x - radius, origin.y - radius, radius + radius,
radius + radius);
}
}
public class Eye {
private final Point origin;
private Point eyeballOrigin;
public Eye(Point origin) {
this.origin = origin;
this.eyeballOrigin = origin;
}
public Point getEyeballOrigin() {
return eyeballOrigin;
}
public void setEyeballOrigin(Point eyeballOrigin) {
this.eyeballOrigin = eyeballOrigin;
}
public Point getOrigin() {
return origin;
}
}
public class EyeballListener extends MouseMotionAdapter {
private final double eyeballDistance = eyeballOuterRadius
- eyeballInnerRadius - 5;
#Override
public void mouseMoved(MouseEvent event) {
Point p = event.getPoint();
for (Eye eye : eyes) {
Point origin = eye.getOrigin();
double theta = Math.atan2((double) (p.y - origin.y),
(double) (p.x - origin.x));
int x = (int) Math.round(Math.cos(theta) * eyeballDistance)
+ origin.x;
int y = (int) Math.round(Math.sin(theta) * eyeballDistance)
+ origin.y;
eye.setEyeballOrigin(new Point(x, y));
}
drawingPanel.repaint();
}
}
}
You're looking for the method mouseMoved instead of mouseEntered.
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);
I'm trying to build a custom triangle component that has the same features as a JComponent (like a JButton per say).
The porpoise of the program will be to add triangle on a mouse click exactly where the mouse is and to handle a mouseover event by highlighting the bg of the shape.
I let the default layouts(or null), because while using others, the applications just doesn't place the triangles where I want...
Right now my major issue is how to adjust the size of the triangles with direct proportionality relative to the form size? So that if I reduce the frame size 50% all the components are down that value as well.
One other issue is that the JComponent requires a rectangular area to handle events, for what I've seen there's no way countering this, so if I try to click on the affected area it will just ignore it instead of creating a new triangle there.
And yet another problem is that sometimes while moving out of the triangle from the bottom it is still green.
Thanks!
Here is the SSCCE:
// TriangleCustom.java
package TriangleCustom;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TriangleCustom {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame f = new JFrame("Triangle");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1200, 800);
Panel p = new Panel();
f.add(p);
f.setVisible(true);
}
}
class Panel extends JPanel {
// the offsets are the area (rect border) to contain the triangle shape
private final int xOFFSET = 25;
private final int yOFFSET = 50;
ArrayList<TriangleShape> triangleAL = new ArrayList<TriangleShape>();
public Panel() {
setBounds(0, 0, 800, 400);
// setBorder(BorderFactory.createLineBorder(Color.black,2));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
addTriangle(new Point(e.getX(), e.getY()), new Point(e.getX()
- xOFFSET, e.getY() + yOFFSET), new Point(e.getX()
+ xOFFSET, e.getY() + yOFFSET));
}
});
}
private void addTriangle(Point topCorner, Point leftCorner,
Point rightCorner) {
final TriangleDTO tdto = new TriangleDTO(new Point(25, 0), new Point(0,
50), new Point(50, 50));
TriangleShape ts = new TriangleShape(tdto);
ts.setBorderColor(Color.BLACK);
ts.setFillColor(Color.RED);
ts.setBounds((int) (topCorner.getX() - 25), (int) topCorner.getY(), 51,
51);
triangleAL.add(ts);
this.add(ts);
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.draw(new Rectangle2D.Double(0, 0, 799, 399));
}
}
// the custom component in a shape of a triangle
class TriangleShape extends JComponent {
private GeneralPath triangle = new GeneralPath();
private TriangleDTO tdto = new TriangleDTO();
private Color borderColor = new Color(0);
private Color fillColor = new Color(0);
// Constructor
public TriangleShape(TriangleDTO tdto) {
this.tdto = tdto;
triangle.moveTo(tdto.getTopCorner().getX(), tdto.getTopCorner().getY());
triangle.lineTo(tdto.getLeftCorner().getX(), tdto.getLeftCorner()
.getY());
triangle.lineTo(tdto.getRightCorner().getX(), tdto.getRightCorner()
.getY());
triangle.closePath();
addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
// there are some issues when going out of the triangle from
// bottom
if (triangle.contains((Point2D) e.getPoint())) {
setFillColor(Color.GREEN);
repaint();
} else {
setFillColor(Color.RED);
repaint();
}
}
});
}
public void setBorderColor(Color borderColor) {
this.borderColor = borderColor;
}
public void setFillColor(Color fillColor) {
this.fillColor = fillColor;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(fillColor);
g2d.fill(triangle);
g2d.setPaint(borderColor);
g2d.draw(triangle);
}
}
// just a plain DTO for the triangle points
class TriangleDTO {
private Point topCorner = new Point();
private Point leftCorner = new Point();
private Point rightCorner = new Point();
// Constructors
public TriangleDTO() {
}
public TriangleDTO(Point topCorner, Point leftCorner, Point rightCorner) {
super();
this.topCorner = topCorner;
this.leftCorner = leftCorner;
this.rightCorner = rightCorner;
}
// Getters and Setters
public Point getTopCorner() {
return topCorner;
}
public void setTopCorner(Point topCorner) {
this.topCorner = topCorner;
}
public Point getLeftCorner() {
return leftCorner;
}
public void setLeftCorner(Point leftCorner) {
this.leftCorner = leftCorner;
}
public Point getRightCorner() {
return rightCorner;
}
public void setRightCorner(Point rightCorner) {
this.rightCorner = rightCorner;
}
}