Creation own JLabel - java

I use a JPanel with GridLayout and I put JLabel inside. Everithing works. But I want to use my own class (extends JLabel) there is a problem.
When I use a JLabel I have this rendering:
And when I use my own JLabel I have that:
Here is my code from my JLabel custom :
public class LabelCustom extends JLabel{
int x;
int y;
public LabelCustom(int x, int y) {
super();
this.x = x;
this.y = y;
this.setBackground(Color.white);
this.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
}
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;
}
}
And how I use it :
JPanel j = new JPanel();
j.setLayout(new GridLayout(nbCaseY, nbCaseX));
for(int i=0; i<nbCaseY; i++) {
HashMap<Integer, JLabel> ligne = new HashMap();
for(int y=0; y<nbCaseX; y++) {
LabelCustom p = new LabelCustom(i, y);
p.addMouseListener(ml);
//p.setBounds(100+ y*(hauteur), 100 + i*( hauteur), hauteur, hauteur);
p.setPreferredSize(new Dimension(hauteur, hauteur));
//p.setBounds(100+ y*( (width-200-2*hauteur)/nbCaseX), 100 + i*( (height-200)/nbCaseY), ((width-200-2*hauteur)/nbCaseX), ((height-200)/nbCaseY));
p.setTransferHandler(new TransferHandler("icon"));
p.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
p.setOpaque(true);
p.setVisible(true);
j.add(p);
ligne.put(y, p);
}
Frame.p.getListeNiveau().get(0).ajouterLigne(ligne);
}

JLabel already has a getX and getY method which is to position the label on the screen, you've (unwittingly) overridden this functionality and are now returning unrelated information.
It's not for x and y position. It is for an id of hashmap, i think it is useful ;)
So, instead of using getX/Y, I suggest making a ID class, which carries the information you need (possibly overriding the equals and hashcode methods to make it easier to do comparisons) and using that instead (providing a getID and setID methods)

Related

Why does this JButton extension cause visual problems in the frame?

I'm trying to create a JPanel that shows buttons forming a square of X size. I want to have the coordinates in a class that extends JButton, but when doing the extension some serious visual problems appear in the frame. If I remove it and use a normal JButton it doesn't happen.
I didn't find another public question with a similar problem. Can someone help me please?
Edit: Thanks to the comments noticed that I accidentally overridden the 'getX' and 'getY' methods of the Container superclass with my extension, that caused problems when it came to locating the JButtons and displaying them in the frame. Thanks.
import java.awt.GridLayout;
import javax.swing.*;
public class mainclass extends JFrame{
private int size= 10;
private class Button extends JButton{
private int x;
private int y;
public Button(int x, int y) {
super();
this.x= x;
this.y= y;
}
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 mainclass(){
GridLayout gl= new GridLayout(size,size);
JPanel buttonsPane= new JPanel(gl);
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
Button temp= new Button(row,col);
temp.setVisible(true);
buttonsPane.add(temp);
buttonsPane.revalidate();
buttonsPane.repaint();
}
}
buttonsPane.setVisible(true);
getContentPane().add(buttonsPane);
setSize(700,700);
setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("Buscaminas");
this.setVisible(true);
}
public static void main(String[] args) {
mainclass mc = new mainclass();
mc.setVisible(true);
}
}

Why does my method inside a class only draw the first circle but if i just use filloval method inside a for loop it displays all circles?

I'm writing a program that displays a circle every time you click the Jpanel. I have it all set up and I want to be able to use the drawCircle method I created in my circle class to draw the circles in the paintComponent method. I'm storing all of the circles created in a linked list. Then I interate through each Circle in the list and try to use the method in my Circle class called drawCircle().
For some reason, if I try to use c1.drawCircle() in a for loop in the My panel class it only draws the last circle that was created. But if I just use g.fillOval(with the correct parameters grabbing the values from the Circle class) in the for loop it works properly and displays all the circles. Why is it doing this and how do I go about using the method in the Circle class properly
I'm unsure what to try right now.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
public class MouseTest {
private int borderWidth = 20;
private JFrame frame;
private boolean tracking;
private boolean start;
private boolean clearBol;
private int xstart;
private int ystart;
private int xend;
private int yend;
private LinkedList<Circle> circles;
public MouseTest() {
tracking = false;
start = false;
circles = new LinkedList<Circle>();
frame = new JFrame();
frame.setBounds(250, 98, 600, 480);
frame.setTitle("Window number three");
Container cp = frame.getContentPane();
JButton clear = new JButton("Clear");
JToggleButton circleButton = new JToggleButton()("Circles");
JToggleButton drawButton = new JToggleButton("Draw");
ButtonGroup circleOrDraw = new ButtonGroup();
MyPanel pane = new MyPanel();
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
clearBol = true;
frame.repaint();
}
});
JPanel top = new JPanel();
top.setLayout(new FlowLayout());
top.add(clear);
circleOrDraw.add(circleButton);
circleOrDraw.add(drawButton);
top.add(circleOrDraw);
cp.add(top, BorderLayout.NORTH);
cp.add(pane, BorderLayout.CENTER);
pane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
xstart = e.getX();
ystart = e.getY();
start = false;
}
public void mouseReleased(MouseEvent e) {
xend = e.getX();
yend = e.getY();
if (xend < xstart) {
int tmp = xstart;
xstart = xend;
xend = tmp;
}
if (yend < ystart) {
int tmp = ystart;
ystart = yend;
yend = tmp;
}
start = true;
frame.repaint();
}
});
pane.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
if (tracking) {
int x = e.getX();
int y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
});
frame.setVisible(true);
} // constructor
public static void main(String[] arg) {
MouseTest first = new MouseTest();
} // main
public void msg(String s) {
System.out.println(s);
}
public void trackMouse() {
tracking = !tracking;
} // trackMouse
public class Circle extends JPanel {
Graphics g;
int x;
int y;
int r;
Color color;
public Circle(Graphics g, int x, int y, int r) {
this.g = g;
this.x = x;
this.y = y;
this.r = r;
int red = (int) (256 * Math.random());
int green = (int) (256 * Math.random());
int blue = (int) (256 * Math.random());
this.color = new Color(red, green, blue);
}
public void drawCircle() {
int x2 = x - (r / 2);
int y2 = y - (this.r / 2);
g.setColor(color);
g.fillOval(x2, y2, this.r, this.r);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public int getR() {
return r;
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
if (start) {
circles.add(new Circle(g, xend, yend,
(int) ((250 * Math.random() + 4))));
//Area where I'm having issues
for (Circle c1 : circles) {
msg("" + c1.getX());
// this method that I created in the circle class will only draw the first circle
//c1.drawCircle();
int r = c1.getR();
int x = c1.getX();
int y = c1.getY();
g.setColor(c1.getColor());
g.fillOval((c1.getX() - (r / 2)), (c1.getY() - (r / 2)),
r, r); // this will display all the circles
}
int size = circles.size();
msg(size + " Size");
msg("" + circles.getLast().getX());
}
if (clearBol) {
super.paintComponent(g);
circles.clear();
clearBol= false;
}
Thank you!
Most of the structure of your class needs to be changed
Your MyPanel should have a better name to give its functionality, maybe something like DrawingPanel.
The DrawingPanel is then responsible for managing the Circles to be painted. So typically you would just use an ArrayList to hold the Circle information.
Then you would add a method to the class, like addCircle(...) to add the Circle information to the ArrayList and then invoke repaint().
Then in your paintComponent(...) method the first thing you do is invoke super.paintComponent(...) to clear the panel. Then you iterate through the ArrayList and paint all the Circles. There will be no need for the Boolean values to check the state of the class. The ArrayList will either have circles or it won't.
You would also need a method like clearCircles(). This would simply remove all the Circles from the ArrayList and invoke repaint() on itself.
Your Circle class should NOT extend JPanel. It should just be a class that contains the information need to paint the circle: x/y location, size of circle and color of circle.
Now your frame is responsible of displaying your DrawingPanel and the buttons.
When you click the "Clear" button you simply invoke the clearCircles() method of the DrawingPanel.
For your MouseListener you simply invoke the addCircle(...) method of your DrawingPanel once you have all the information needed to create a Circle instance.
For a complete working example that incorporates all these suggestions check out the DrawOnComponent example found in Custom Painting Approaches

Wait for two change listeners to change both

I have a short question regarding PropertyChangeListeners.
I have a Person class which has 3 attributes. Two of them are the x and y coordinates which the person has on a map.
I want to update the map whenever the coordinates of a person change.
So my problem is to detect when not only x or y change, but both do.
That's how far I got. I hope you can help me.
Person.java:
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Person {
private int x, y, hp;
private PropertyChangeSupport changes = new PropertyChangeSupport( this );
public Person (int x, int y) {
this.x = x;
this.y = y;
}
public void setX( int x) {
int oldX = x;
this.x = x;
changes.firePropertyChange( "x", oldX, x );
}
public void setY( int y) {
int oldY = y;
this.y = y;
changes.firePropertyChange( "y", oldY, y );
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void addPropertyChangeListener( PropertyChangeListener l ) {
changes.addPropertyChangeListener( l );
}
public void removePropertyChangeListener( PropertyChangeListener l ) {
changes.removePropertyChangeListener( l );
}
}
Map.java:
private void initPeople() {
people = new Person[amount];
PropertyChangeSupport
for (Person p : people) {
person.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent e) {
// IF Person x AND y changed DO something
}
});
}
}
You can store the boolean xChanged and yChanged properties in person's property change listener class, and then in callback:
xChanged | ="x". equals(e.source);
yChanged |="y". equals(e.source);
if(xChanged & & yChanged ) {
}
You can instead of have two fields for People coordinate (x and y) merge them to other object (you can call it Coordinate). That allow you to work with coordinate of People like entire thing. And of course you have fire changing of it in one call.

JPanel GridLayout make all buttons be in same place

I was created some program for my school that should contains n*n buttons.
The buttons should be in Matrix layout with n rows and n cols.
So i created the panel, and I created a class named Position that extends JButtons - the buttons I want to add to the panel.
I added layout to the panel:
this.setLayout(new GridLayout(n,n));
And then I am creating n*n Positions buttons and adding them to the panel.
The problem is, that all the buttons are adding to the same place (top left of the screen) - even that I can click them in the places they should be! (see screen shot where n is 4)
I can click on the grey area (empty) even the button is not there:]1
The panel constructor:
public GamePanel(int n) {
super();
this.n = n;
positions = new Position[n][n];
this.setLayout(new GridLayout(n,n));
currX = new Random().nextInt(n);
currY = new Random().nextInt(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Position p = new Position(i, j);
this.add(p);
positions[i][j] = p;
}
}
The constructor of Position class:
public class Position extends JButton {
private int x;
private int y;
private boolean visited = false;
public Position(int x, int y) {
super("");
this.x = x;
this.y = y;
this.setPreferredSize(new Dimension(50,50));
}
The Frame:
public class Game extends JFrame {
private GamePanel gamePanel;
public Game(int n){
super();
gamePanel = new GamePanel(n);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
this.add(gamePanel,BorderLayout.CENTER);
this.add(new JTextField(),BorderLayout.NORTH);
this.pack();
this.setVisible(true);
}
}
Where can be my mistake?
So, after putting your incomplete example back together, I got...
Then I noticed the x/y properties in your Position buttons, which made me thing that you've probably included getX and getY methods, something like...
public class Position extends JButton {
private int x;
private int y;
private boolean visited = false;
public Position(int x, int y) {
super("");
this.x = x;
this.y = y;
this.setPreferredSize(new Dimension(50, 50));
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Which generated...
So the answer is, include a fully runnable example which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses
And don't override getX and getY of the JButton, instead, change the methods to something like getGridX and getGridY

Java swing, need to draw rectangles using the mouse without losing previous rectangles with overlap

in this class that i have extending JLabel I need to be able to use the mouse to left click, then drag down and/or right to create a rectangle and be able to repeat that process to draw multiple rectangles without losing any of the previous ones and drawing boxes for overlap as well as being able to find the rectangle made by the union of all rectangles like this
my current code was adapted as much as i could from the java demo on Performing Custom Painting the program seems to be behaving in odd ways because of how the repaint method is used to update the JLabel but i have no idea how to fix it
JLabel class
import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class JLabelx extends JLabel {
private int squareX = 0;
private int squareY = 0;
private int squareW = 0;
private int squareH = 0;
public JLabelx() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
squareX = e.getX();
squareY = e.getY();
//set coordinates of next rectangle
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
newDraw(e.getX(),e.getY());
//find length and width of next rectangle
}
});
}
protected void newDraw(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
// repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareW=x-squareX;
squareH=y-squareY;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
protected void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(Color.GREEN);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);
}
}
I have also been given a Rectangle class that looks similar to java.awt.Rectangle which has methods that find the rectangles made by overlaps and the rectangles made by the union of all rectangles, but I don't know how to create rectangle objects with mouse movements and then paint them in this JLabel
public class Rectangle {
private int x,y,width,height;
public Rectangle(int x,int y,int width,int height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public Rectangle(Rectangle a)
{
this.x = a.x;
this.y = a.y;
this.width = a.width;
this.height = a.height;
}
public String toString()
{
return "Start: ("+x+","+y+"), Width: "+width+", Height: "+height+"\n";
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public void setX(int x)
{
this.x = x;
}
public void setY(int y)
{
this.y = y;
}
public void setWidth(int width)
{
this.width = width;
}
public void setHeight(int height)
{
this.height = height;
}
public int area()
{
return width*height;
}
public boolean overlaps(Rectangle a)
{
if ((x>a.x+a.width) || (a.x>x+width) || (y>a.y+a.height) || (a.y>y+height))
{
return false;
}
return true;
}
public Rectangle intersect(Rectangle a)
{
if (!overlaps(a))
return null;
int left,right,top,bottom;
if (x<a.x)
left = a.x;
else
left = x;
if (y<a.y)
bottom = a.y;
else
bottom = y;
if ((x+width)<(a.x+a.width))
right = x+width;
else
right = a.x+a.width;
if ((y+height)<(a.y+a.height))
top = y+height;
else
top = a.y+a.height;
return new Rectangle(left,bottom,right-left,top-bottom);
}
public Rectangle union(Rectangle a)
{
int left,right,top,bottom;
if (x<a.x)
left = x;
else
left = a.x;
if (y<a.y)
bottom = y;
else
bottom = a.y;
if ((x+width)<(a.x+a.width))
right = a.x+a.width;
else
right = x+width;
if ((y+height)<(a.y+a.height))
top = a.y+a.height;
else
top = y+height;
return new Rectangle(left,bottom,right-left,top-bottom);
}
}
Not sure why you are extending a JLabel to do custom painting. The tutorial showed you how to use a JPanel.
For the two common ways to do incremental paint, check out Custom Painting Approaches:
Use a List to keep track of the Rectangles (this is probably what you want since you want to be able to test for intersections.
Use a BufferedImage.

Categories

Resources