Updating JPanels and keeping JLabels Visible - java

I am developing a GUI for processing images, and I have trouble with displaying the images.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BottomLeftPanel extends JPanel {
public static BottomLeftPanel BLP;
public static BufferedImage original;
public static ImageIcon icon;
public static Polygon poly;
public static JLabel label;
public BottomLeftPanel() throws IOException {
super();
this.setBackground(new Color(255, 255, 255, 0));
original = Methods2.loadImage("bowser jr.png");
original = Methods2.toFourChannel(original);
poly = null;
icon = new ImageIcon(original);
label = new JLabel(icon);
this.add(new JLabel(icon));
this.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mousePressed(MouseEvent me) {
Point2D P = me.getPoint();
if(poly == null) {
poly = new Polygon(new int[]{(int) P.getX()}, new int[]{(int) P.getY()}, 1);
return;
}
int[] B = poly.xpoints;
int[] C = poly.ypoints;
int[] X = new int[poly.npoints + 1];
int[] Y = new int[poly.npoints + 1];
System.arraycopy(B, 0, X, 0, B.length);
System.arraycopy(C, 0, Y, 0, C.length);
X[B.length] = (int) P.getX();
Y[C.length] = (int) P.getY();
poly = new Polygon(X, Y, poly.npoints + 1);
System.out.println(poly.toString());
BLP.getGraphics().clearRect(0, 0, BLP.getHeight(), BLP.getWidth());
BLP.repaint(BLP.getGraphics());
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
});
BLP = this;
}
public void repaint(Graphics g) {
g.setColor(Color.black);
g.drawPolygon(poly);
icon = new ImageIcon(original);
label.setIcon(icon);
}
}
In the method mousePressed, polygon poly is updated, and the updated version is shown. However, after a few clicks, the ImageIcon which was part of the JLabel which was loaded onto the screen is no longer visible. How do I fix this while keeping the clearRect method in place (I need the clearRect method in order to remove the already drawn polygon and draw the new polygon)?

I was able to solve the problem. I first converted BottomLeftPanel to BottomLeftLabel and put it in a panel of its own. Then I did the painting in the paint(Graphics g) method. In the paint method, I used super.paint(Graphics g), but this is not important because the JLabel (BottomLeftLabel) would not clear the ImageIcon it held no matter what was painted. I do not mind using a static reference, since if I did not use a static reference, I would either have to make the class implement MouseListener, or create a seperate class which implements MouseListener, and since I am only running 1 GUI at a time, it does not make sense to do that (the static reference would not cause any problems here). Here is the code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BottomLeftLabel extends JLabel {
public static BottomLeftLabel BLP;
public static BufferedImage original;
public static ImageIcon icon;
public static Polygon poly;
// public static JLabel label;
public BottomLeftLabel() throws IOException {
super();
// this.setBackground(new Color(255, 255, 255, 0));
original = Methods2.loadImage("crash bandicoot picture.jpg");
// original = Methods2.loadImage("bowser jr.png");
// original = Methods2.loadImage("devil's tooth.jpg");
original = Methods2.toFourChannel(original);
// int[][] p = Methods.toIntegerArray(original);
// p = Methods.adjustTransparency(p, (float) 1.0);
// original = Methods.toBufferedImage(p);
// this.setSize(new Dimension(original.getWidth(), original.getHeight()));
// Graphics g = this.getGraphics();
poly = null;
icon = new ImageIcon(original);
// label = new JLabel(icon);
this.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mousePressed(MouseEvent me) {
Point2D P = me.getPoint();
if(poly == null) {
poly = new Polygon(new int[]{(int) P.getX()}, new int[]{(int) P.getY()}, 1);
return;
}
int[] B = poly.xpoints;
int[] C = poly.ypoints;
int[] X = new int[poly.npoints + 1];
int[] Y = new int[poly.npoints + 1];
System.arraycopy(B, 0, X, 0, B.length);
System.arraycopy(C, 0, Y, 0, C.length);
X[B.length] = (int) P.getX();
Y[C.length] = (int) P.getY();
poly = new Polygon(X, Y, poly.npoints + 1);
System.out.println(poly.toString());
// BLP.getGraphics().clearRect(0, 0, BLP.getHeight(), BLP.getWidth());
// BLP.removeAll();
// icon = new ImageIcon(original);
// BLP.add(new JLabel(icon));
BLP.paint(BLP.getGraphics());
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
});
this.setIcon(icon);
BLP = this;
// repaint(this.getGraphics());
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.clearRect(0, 0, WIDTH, HEIGHT);
if(poly != null) {
g.drawPolygon(poly);
}
}
// /**
// *
// * #param g
// */
// public void repaint(Graphics g) {
//// g.clearRect(0, 0, WIDTH, HEIGHT);
//
// g.setColor(Color.black);
// g.drawPolygon(poly);
// this.removeAll();
// icon = new ImageIcon(original);
// this.add(new JLabel(icon));
// }
// public void repaint(Graphics g) {
//
// }
}

Related

Removing a rectangle with color on mouse release

I am developing a game and in some part of my game I want the rectangle to disappear on mouse release. I have placed 26 rectangles in an arrayList and remove the particular rectangle clicked as the mouse is released. So if I remove the fill methods, the rectangle disappears successfully but if the fill methods are there, it does not work anymore.
Here is my paint method:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.draw(s);
}
g2.setColor(bColor);
g2.fill(box1);
g2.fill(box2);
g2.fill(box3);
g2.fill(box4);
g2.fill(box5);
g2.fill(box6);
g2.fill(box7);
g2.fill(box8);
g2.fill(box9);
g2.fill(box10);
g2.fill(box11);
g2.fill(box12);
g2.fill(box25);
g2.setColor(wColor);
g2.fill(box13);
g2.fill(box14);
g2.fill(box15);
g2.fill(box16);
g2.fill(box17);
g2.fill(box18);
g2.fill(box19);
g2.fill(box20);
g2.fill(box21);
g2.fill(box22);
g2.fill(box23);
g2.fill(box24);
g2.fill(box26);
}
Here is how I did the removing of the rectangle (Just an excerpt):
if (box1.getBounds().contains(x, y)) {
pickedPanelNum = 0;
rectanglesList.remove(box1);
panelsPane.repaint();
}
Here are the values of the bColor and wColor:
Color bColor = Color.BLACK;
Color wColor = Color.WHITE;
NOTE:
The pickedPanelNum is just for assigning an int value and has no connection to the problem.
I think it is because when I repaint, the fill methods are still there. However I have no idea for an alternate way of painting the rectangles.
I hope my problem is stated clearly. If you have ideas how I could solve this, please tell me. Thank you!
UPDATE:
Here is a shorter, runnable version of my program. (Background image isn't included though):
import java.awt.*;
import java.awt.Color.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.geom.Rectangle2D;
public class Rec extends JComponent
{
public ArrayList<Rectangle> rectanglesList = new ArrayList<Rectangle>();
public int arrx[] = new int[120];
public int arry[] = new int[120];
JFrame frame = new JFrame();
public int xSize = 2000;
public int ySize = 1000;
public int x;
public int y;
public int pickedPanelNum = 0;
public String pickedPanelDash = "";
public String pickedPanelColor = "";
Color bColor = Color.BLACK;
Color wColor = Color.WHITE;
boolean removedPanel = false;
public void launchFrame()
{
Random rand = new Random();
for(int x = 0;x<120;x++)
{
arrx[x] = rand.nextInt(640);
arry[x] = rand.nextInt(590);
}
Rectangle box1 = new Rectangle(arrx[103],arry[59],80,90);
Rectangle box2 = new Rectangle(arrx[105],arry[3],80,90);
rectanglesList.add(box1);
rectanglesList.add(box2);
JPanel mainPanel = new JPanel();
JPanel panelsPane = new JPanel()
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.draw(s);
}
g2.setColor(bColor);
g2.fill(box1);
g2.setColor(wColor);
g2.fill(box2);
}
};
JPanel rightPane = new JPanel();
panelsPane.addMouseListener (new MouseAdapter ()
{
public void mousePressed(MouseEvent event)
{
x = event.getX();
y = event.getY();
}
public void mouseReleased(MouseEvent event)
{
if (box1.getBounds().contains(x, y)) {
pickedPanelNum = 0;
rectanglesList.remove(box1);
panelsPane.repaint();
}
if (box2.getBounds().contains(x, y)) {
pickedPanelNum = 1;
rectanglesList.remove(box2);
panelsPane.repaint();
}
}
});
panelsPane.addMouseMotionListener (new MouseAdapter ()
{
public void mouseDragged(MouseEvent event)
{
Rec obj = new Rec();
int dx = event.getX() - x;
int dy = event.getY() - y;
if (box1.getBounds().contains(x, y)) {
box1.x += dx;
box1.y += dy;
panelsPane.repaint();
}
if (box2.getBounds().contains(x, y)) {
box2.x += dx;
box2.y += dy;
panelsPane.repaint();
}
x += dx;
y += dy;
}
public void mouseReleased(MouseEvent event) {}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
});
panelsPane.setPreferredSize(new Dimension (800, ySize-315));
rightPane.setPreferredSize(new Dimension (530, ySize-315));
mainPanel.setPreferredSize(new Dimension (xSize, ySize));
frame.setPreferredSize(new Dimension (xSize, ySize));
rightPane.setBackground(Color.gray);
mainPanel.add(panelsPane);
mainPanel.add(rightPane);
frame.add(mainPanel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
}
public static void main(String args[])
{
Rec obj = new Rec();
obj.launchFrame();
}
}
Even if you remove box1 from the List, there is nothing stopping it from getting filled in your paintComponent method, the for-loop is only drawing the outline of the rectangles within the list, but you code implicitly fills them anyway.
So, first, get rid of all the box{n} variables. Next change the paintComponent method...
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
//g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.setColor(bColor);
g2.fill(s);
g2.setColor(wColor);
g2.draw(s);
}
}
So, this just uses the rectanglesList to first draw the rectangles and the fill them
Then, lets update the mouseReleased...
public void mouseReleased(MouseEvent event) {
// Because the rectangles are painted in order, the later
// rectangles are painted over the eailer ones, so, we reverse
// the list so we can check for the higher positioned
// rectangles
List<Rectangle> copy = new ArrayList<>(rectanglesList);
Collections.reverse(copy);
for (Rectangle r : copy) {
if (r.contains(event.getPoint())) {
rectanglesList.remove(r);
break;
}
}
event.getComponent().repaint();
}
Okay, this is little more funky, but basically, we reverse the list of rectangles (because those rectangles that appear later in the list are painted over those that appear before them) and checks to see if the mouse was clicked within any one of them. The moment we find a match, we break out of the loop and repaint the component which generated the event
And, because it's nice to see this stuff running, a complete example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Rec extends JComponent {
public ArrayList<Rectangle> rectanglesList = new ArrayList<Rectangle>();
public int arrx[] = new int[120];
public int arry[] = new int[120];
JFrame frame = new JFrame();
public int xSize = 2000;
public int ySize = 1000;
public int x;
public int y;
public int pickedPanelNum = 0;
public String pickedPanelDash = "";
public String pickedPanelColor = "";
Color bColor = Color.BLACK;
Color wColor = Color.WHITE;
boolean removedPanel = false;
public void launchFrame() {
Random rand = new Random();
for (int x = 0; x < 10; x++) {
arrx[x] = rand.nextInt(640);
arry[x] = rand.nextInt(590);
rectanglesList.add(new Rectangle(arrx[x], arry[x], 80, 90));
}
JPanel mainPanel = new JPanel();
JPanel panelsPane = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Image img = Toolkit.getDefaultToolkit().getImage(Rectangles2.class.getResource("background.jpg"));
// g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle s : rectanglesList) {
g2.setColor(bColor);
g2.fill(s);
g2.setColor(wColor);
g2.draw(s);
}
}
};
JPanel rightPane = new JPanel();
panelsPane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
x = event.getX();
y = event.getY();
}
public void mouseReleased(MouseEvent event) {
// Because the rectangles are painted in order, the later
// rectangles are painted over the eailer ones, so, we reverse
// the list so we can check for the higher positioned
// rectangles
List<Rectangle> copy = new ArrayList<>(rectanglesList);
Collections.reverse(copy);
for (Rectangle r : copy) {
if (r.contains(event.getPoint())) {
rectanglesList.remove(r);
break;
}
}
event.getComponent().repaint();
}
});
panelsPane.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent event) {
}
public void mouseReleased(MouseEvent event) {
}
public void mouseClicked(MouseEvent event) {
}
public void mouseEntered(MouseEvent event) {
}
public void mouseExited(MouseEvent event) {
}
});
panelsPane.setPreferredSize(new Dimension(800, ySize - 315));
rightPane.setPreferredSize(new Dimension(530, ySize - 315));
mainPanel.setPreferredSize(new Dimension(xSize, ySize));
frame.setPreferredSize(new Dimension(xSize, ySize));
rightPane.setBackground(Color.gray);
mainPanel.add(panelsPane);
mainPanel.add(rightPane);
frame.add(mainPanel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Rec obj = new Rec();
obj.launchFrame();
}
});
}
}

Java JApplet render issues

I have a problem with JApplet. The code was working just fine, but when I converted it from JFrame to JApplet, the render part stopped working properly. Basicly what I'm trying to do is simplistic draw app. When launching applet, half of time repaint() is not working (There is no gray background; you have to put mouse over button for it to update its color etc), furtheremore the pixel rendering part is not shown up at all. Here's the code:
The Frame class (JApplet)
package painter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Frame extends JApplet {
public JPanel panel;
private JButton plus, minus, buttonColor;
private int scaleSize;
private JLabel labelScale;
private final Timer updateTimer;
private static boolean painting = false;
public static Color currentColor;
public static int mode = 0;
// 0 = draw; 1 = setcolor; 2 = erase
private ArrayList<Pixel> pixelArray;
public Frame() {
pixelArray = new ArrayList<>();
for (int i = 1; i <= 8; i++) {
for (int j = 1; j <= 8; j++) {
pixelArray.add(new Pixel(i, j));
}
}
setLayout(new BorderLayout());
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//g.fillRect(10, 10, 100, 100); <- test if fillRect works at all. Yus it does.
for (int i = 0; i < pixelArray.size(); i++) {
pixelArray.get(i).render(g);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
};
//panel.setBounds(0, 0, 800, 800);
//add(panel);
getContentPane().add(panel);
//panel.setLayout(null);
//panel.setOpaque(true);
//panel.setDoubleBuffered(true);
currentColor = Color.yellow;
buttonColor = new JButton("Choose color");
buttonColor.setBounds(10, 10, 128, 64);
buttonColor.setBackground(currentColor);
buttonColor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
currentColor = JColorChooser.showDialog(null, "JColorChooser Sample", Color.gray);
}
});
updateTimer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
buttonColor.setBackground(currentColor);
repaint();
}
});
updateTimer.start();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
painting = true;
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
painting = false;
}
});
panel.add(buttonColor);
repaint();
}
public static boolean getPaint() {
return painting;
}
public static void main(String[] args) {
new Frame();
}
}
And here is the Pixel class:
package painter;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
public class Pixel {
private Color color;
private int size;
private int x, y, relativex, relativey;
public Pixel(int relx, int rely) {
color = new Color(0x999999, false);
size = 32;
x = relx * size + 64;
y = rely * size + 64;
}
public boolean mouseOver() {
Point pos, mousepos;
pos = new Point(x, y);
mousepos = MouseInfo.getPointerInfo().getLocation();
if ((mousepos.x > pos.x)
&& (mousepos.x < pos.x + size)
&& (mousepos.y > pos.y)
&& (mousepos.y < pos.y + size)) {
return true;
} else {
return false;
}
}
public void render(Graphics g) {
g.setColor(color);
if (mouseOver() && Frame.getPaint()) {
if (Frame.mode == 0) {
color = Frame.currentColor;
}
if (Frame.mode == 1) {
Frame.currentColor = color;
}
if (Frame.mode == 2) {
color = new Color(0xffffffff, true);
}
}
g.fillRect(x, y, size, size);
if (mouseOver()) {
g.setColor(Color.black);
g.drawRect(x, y, size - 1, size - 1);
g.setColor(Color.yellow);
g.drawRect(x + 1, y + 1, size - 3, size - 3);
}
//g.fillRect(10, 10, 250, 250);
}
}
As a stab in the dark, don't call Graphics#dipose on a Graphics context you did not create yourself explicitly
Apart from the fact the the Graphics context is a shared resource, used by all the components that might need to be painted within a given paint cycle, it can also prevent what ever was painted to it to be displayed on some platforms
In 15 years of professional development, I've never had reason to call Toolkit.getDefaultToolkit().sync();. I doubt it'll make that big a difference, I'm just saying
Java applets provide us with these methods
[here] http://docs.oracle.com/javase/tutorial/deployment/applet/appletMethods.html
the method
public void paint(Graphics g){}
is used as alternative of
public void paintComponent(Graphics g){}
of swing.
Check out http://docs.oracle.com/javase/tutorial/uiswing/painting/index.html for the recommended way to perform custom painting of swing components

How to name the coordinates (points) in Java Swing

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);

Java Swing - How to create custom components with auto size adjustment to the parent

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;
}
}

Changing JPanel Graphics g color drawing line

i have a program similar to paint. and that i am trying to implement a change pen color however when i change the color, everything currently drawn is changed to the color RED for example in my program,how can i make it such that it will not repaint everything currently drawn to the currently changed color?Below code will compile and run
Class for the JPanel drawing area
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
//refer to http://jkost.ergoway.gr/jnkjavaconnection/freedraw.html for the algorithm.
public class STDrawingArea extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
ArrayList<Rectangle> dPoint = new ArrayList<Rectangle>();
Point point = new Point(-1,-1);
private Color currentColor;
public STDrawingArea()
{
setBorder(BorderFactory.createLineBorder(Color.black));
setBackground(Color.WHITE);
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e)
{
dPoint.add(new Rectangle(point.x,point.y,e.getX(),e.getY()));
point.x = e.getX();
point.y = e.getY();
repaint();
}
});
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e)
{
System.out.println("mousePressed X: "+e.getX()+"mousePressed Y: "+e.getY());
dPoint.add(new Rectangle(e.getX(),e.getY(),-1,-1));
point.x = e.getX();
point.y = e.getY();
}
});
addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e)
{
System.out.println("mouseReleased X: "+e.getX()+"mouseReleased Y: "+e.getY());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(700,500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getCurrentColor());
for (int i=0; i < dPoint.size(); i++) {
Rectangle r = dPoint.get(i);
if (r.width != -1)
{
g.drawLine(r.x, r.y, r.width, r.height);
}
}
/* Draw current point.*/
g.drawLine(point.x, point.y, point.x, point.y);
}
//set current drawing color
public void changePenColor(Color color)
{
if (color == null)
setCurrentColor(Color.BLACK);
else
setCurrentColor(color);
}
//clear drawings method
public void clearDrawings()
{
if(!(dPoint==null))
{
dPoint.clear();
repaint();
}
}
private void setCurrentColor(Color currentColor) {
this.currentColor = currentColor;
}
private Color getCurrentColor() {
return currentColor;
}
}
Test main class.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class STTestMain extends JFrame {
STDrawingArea drawingArea = new STDrawingArea();
public STTestMain()
{
//JFrame settings
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Spelling Trainer");
setResizable(false);
setVisible(true);
//Panel of buttons
JPanel buttonContainer = new JPanel();
JButton btnPenColor = new JButton("Red Pen");
buttonContainer.add(btnPenColor);
//Drawing Area instantiation
//Adding things to JFrame
getContentPane().add(drawingArea);
getContentPane().add(buttonContainer,BorderLayout.PAGE_END);
pack();
//button listener
btnPenColor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.changePenColor(Color.RED);
}
});
}
public static void main(String args[])
{
STTestMain test = new STTestMain();
}
}
One way:
Use your ArrayList to draw the current curve as it is being drawn, but
Use a BufferedImage to draw your completed curves
You would do this on mouseReleased and would draw the current curve to the BufferedImage using the current color.
You'll also need to re-initialize your ArrayList of points after drawing to the BufferedImage.
Don't forget to dispose of the BufferedImage's Graphics object after you're done using it.
Draw the BufferedImage in your paintComponent method after super.paintComponent but before drawing your current curve.
This way when you change the color of your drawing, only the current curve is effected.
EDIT
You've mentioned in a comment that you're not familiar with BufferedImage, and are looking for another way. I suppose you could create a class that holds an ArrayList of Points together with a Color, and then on each mouseReleased create an object of this class and add it to an ArrayList in your drawing panel. Then your paintComponent method could iterate through that ArrayList, drawing the list of Points with their associated color, but my gut tells me that you're an intelligent guy and that you'd pick up on how to use a BufferedImage in no time. I really think it's the best solution. And if you try it and it flops, show us your code, and we'll likely be able to help you.
EDIT 2
The BufferedImage constructor will need the image width, height and an image type -- something I'm not 100% familiar with. I usually use BufferedImage.TYPE_INT_RGB for general purpose drawing, and BufferedImage.TYPE_INT_ARGB for general purpose that needs an alpha too. Then you'll extract a Graphics object out of the BufferedImage, say getGraphics() if all you need is a Graphics object and not a Graphics2D object. Then when you initialize the BufferedImage in your constructor, fill it with a Color.white, just as you for your JPanel. Then dispose the Graphics object. Then each time you want to draw, you getGraphics, draw with it, just like you do in the paintComponent method, dispose of the Graphics when done, and finally draw the BufferedImage in the paintComponent via the drawImage method.
EDIT 3
Example program that doesn't do quite what you are trying to do but does illustrate use of a BufferedImage with drawing. This program changes the color each time a new path or curve is drawn.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.*;
public class STTestSimple {
private static void createAndShowUI() {
STDrawPanel drawPanel = new STDrawPanel();
STMouseAdapter mAdapter = new STMouseAdapter(drawPanel);
drawPanel.addMouseListener(mAdapter);
drawPanel.addMouseMotionListener(mAdapter);
JFrame frame = new JFrame("Drawing");
frame.getContentPane().add(drawPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
#SuppressWarnings("serial")
class STDrawPanel extends JPanel {
private static final int ST_WIDTH = 700;
private static final int ST_HEIGHT = 500;
private static final Color BACKGROUND_COLOR = Color.white;
private static final float STROKE_WIDTH = 6f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
private static final Color[] colors = {Color.black, Color.blue, Color.red,
Color.green, Color.orange, Color.MAGENTA};
private BufferedImage bImage = new BufferedImage(ST_WIDTH, ST_HEIGHT,
BufferedImage.TYPE_INT_RGB);
private Color color = Color.black;
private ArrayList<Point> points = new ArrayList<Point>();
private int colorIndex = 0;
public STDrawPanel() {
Graphics g = bImage.getGraphics();
g.setColor(BACKGROUND_COLOR);
g.fillRect(0, 0, ST_WIDTH, ST_HEIGHT);
g.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bImage, 0, 0, null);
Graphics2D g2 = (Graphics2D) g;
drawCurve(g2);
}
private void addCurveToBufferedImage() {
Graphics2D g2 = bImage.createGraphics();
drawCurve(g2);
g2.dispose();
}
private void drawCurve(Graphics2D g2) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(STROKE);
g2.setColor(color);
if (points != null && points.size() > 1) {
for (int i = 0; i < points.size() - 1; i++) {
int x1 = points.get(i).x;
int y1 = points.get(i).y;
int x2 = points.get(i + 1).x;
int y2 = points.get(i + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(ST_WIDTH, ST_HEIGHT);
}
public void curveStart(Point point) {
points.clear();
points.add(point);
}
public void curveEnd(Point point) {
points.add(point);
addCurveToBufferedImage();
points.clear();
repaint();
colorIndex++;
colorIndex %= colors.length;
setColor(colors[colorIndex]);
}
public void curveAdd(Point point) {
points.add(point);
repaint();
}
public void setColor(Color color) {
this.color = color;
}
}
class STMouseAdapter extends MouseAdapter {
private STDrawPanel drawPanel;
public STMouseAdapter(STDrawPanel drawPanel) {
this.drawPanel = drawPanel;
}
#Override
public void mousePressed(MouseEvent e) {
drawPanel.curveStart(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
drawPanel.curveEnd(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
drawPanel.curveAdd(e.getPoint());
}
}
Custom Painting Approaches gives two ideas on how you might do this.
Thanks hovercraft, i've done it looking at your code and fiddling around lol.
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.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class STDrawingArea extends JPanel {
/**
*
*/
private static final int DA_WIDTH = 700;
private static final int DA_HEIGHT = 500;
private static final Color DA_BGCOLOR = Color.WHITE;
private static final long serialVersionUID = 1L;
ArrayList<Point> points = new ArrayList<Point>();
private Color currentColor;
BufferedImage bImage = new BufferedImage(DA_WIDTH, DA_HEIGHT, BufferedImage.TYPE_INT_RGB);
public STDrawingArea()
{
setBorder(BorderFactory.createLineBorder(Color.black));
//Basic Settings for bImage
Graphics g2d = bImage.getGraphics();
g2d.setColor(DA_BGCOLOR);
g2d.fillRect(0, 0, DA_WIDTH, DA_HEIGHT);
g2d.dispose();
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e)
{
points.clear();
points.add(e.getPoint());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e)
{
points.add(e.getPoint());
repaint();
}
});
addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e)
{
points.add(e.getPoint());
points.clear();
System.out.println("mouseReleased X: "+e.getX()+"mouseReleased Y: "+e.getY());
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(DA_WIDTH,DA_HEIGHT);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawIntoBufferedImage();
g.drawImage(bImage,0,0,null);
freehandLines(g);
}
public void drawIntoBufferedImage()
{
Graphics g = bImage.getGraphics();
freehandLines(g);
g.dispose();
}
public void freehandLines(Graphics g)
{
if(points != null && points.size() > 1)
{
g.setColor(getCurrentColor());
for(int i = 0; i < points.size()-1;i++)
{
int x1 = points.get(i).x;
int y1 = points.get(i).y;
int x2 = points.get(i+1).x;
int y2 = points.get(i+1).y;
g.drawLine(x1, y1, x2, y2);
}
}
}
//clear drawings method
public void clearDrawings()
{
if(points!=null)
{
points.clear();
Graphics g = bImage.getGraphics();
g.setColor(DA_BGCOLOR);
g.fillRect(0, 0, DA_WIDTH, DA_WIDTH);
g.dispose();
repaint();
}
}
public void setCurrentColor(Color currentColor) {
if(currentColor == null)
{
currentColor = Color.BLACK;
}else{
this.currentColor = currentColor;
}
}
public Color getCurrentColor() {
if (currentColor == null)
return Color.BLACK;
else
return currentColor;
}
}
main class
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class STTestMain extends JFrame {
STDrawingArea drawingArea = new STDrawingArea();
public STTestMain()
{
//JFrame settings
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Spelling Trainer");
setResizable(false);
setVisible(true);
//Panel of buttons
JPanel buttonContainer = new JPanel();
JButton btnRedPen = new JButton("Red Pen");
JButton btnGreenPen = new JButton("Green Pen");
JButton btnClear = new JButton("Clear");
buttonContainer.add(btnRedPen);
buttonContainer.add(btnGreenPen);
buttonContainer.add(btnClear);
//Drawing Area instantiation
//Adding things to JFrame
getContentPane().add(drawingArea);
getContentPane().add(buttonContainer,BorderLayout.PAGE_END);
pack();
//button listener
btnRedPen.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.setCurrentColor(Color.RED);
}
});
btnGreenPen.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.setCurrentColor(Color.GREEN);
}
});
btnClear.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
drawingArea.clearDrawings();
}
});
}
public static void main(String args[])
{
STTestMain test = new STTestMain();
}
}

Categories