I have an image of a map. When the user clicks a button, I want to put a red square box as a highlight on a certain location of the map like this:
How do I highlight a portion like this?
Currently, I am achieving this by creating a new image which has this area highlight and loading that image when the user clicks on the button. However in this case I'll have to develop 66 images and load one for each button.
Extend the JLabel to do custom painting.
You would keep an ArrayList of Rectangles that you want to paint. When you click a button you add a Rectangle to the ArrayList. Then in the paintComponent(...) method you iterate through the ArrayList to paint each Rectangle.
So the basic changes to the extend the JLabel would be:
private ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();
...
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (Rectangle r: rectangles)
{
g.setColor( Color.RED );
g.drawRect(...);
}
}
public void addRectangle(Rectangle r)
{
rectangles.add( r );
}
For a working example of this approach check out the DrawOnComponent example found in Custom Painting Approaches.
Another option might be to use a JLayer to paint the Rectangles on the JLabel. Read the section from the Swing tutorial on How to Decorate Component With the JLayer Class for some working examples.
Either way you need to do custom painting. Try both approaches to see which you prefer.
Related
I'm trying to make a simple application to draw shapes to a panel in a jFrame. The GUI is a NetBeans generated jFrame. The application has three panels. the first two hold button groups to select the shape and a color. There's a button to draw the shape to the third panel once the selections are made.
What the GUI looks like
Unfortunately I'm having no love and can't make it work. For now I just want to get the button to draw a shape then I'll add the button functionality. Here's the code I have so far.
private void btnDrawShapeActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
Draw shape = new Draw();
pnlDrawPad.add(shape); //pnlDrawPad is the name of the jPanel
shape.drawing();
}
import javax.swing.*;
import java.awt.*;
public class Draw extends JPanel{
public Draw(){
super();
}
public void drawing(){
repaint();
}
//#Override <-- gives error "method does not override or implement a method from a supertype"
public void paintCompnent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.drawString("Hello World!",40,30);
}
}
When I click the "Draw Shape" button nothing happens. I've been searching for a couple days now and am not finding the answer. Actually, its making me more confused as to what to do.
How to deal with this?
Don't keep creating new panels for each shape.
Instead you need a single panel with an ArrayList of objects you want to paint. Then you customize the paintComponent(...) method of the panel to iterate through all the objects in the panel and paint them.
So you button will just add another object to the ArrayList and then invoke repaint() on the panel.
Check out Custom Painting Approaches. The DrawOnComponent example shows how to paint a Rectangle objects from an ArrayList to get you started.
I found that with NetBeans you don't need to Override the paintComponents() method. Since all the GUI stuff is done when you design it, you merely need to add the drawings to the panel or what ever you need to do. I found you that by declaring and instantiating a 2D graphics object then drawing it to the place you want.
private void btnDrawShapeActionPerformed(java.awt.event.ActionEvent evt) {
int centerX;
int centerY;
Graphics2D drawFx = (Graphics2D)pnlDrawPad.getGraphics();
drawFx.setColor(Color.ORANGE);
centerX = (int)(458*Math.random());
centerY = (int)(440*Math.random());
drawFx.fillOval(centerX-50, centerY-50, 100, 100);
drawFx.dispose();
}
Worked like a charm so now every time I push the draw shape button it draws a shape to the panel in a different location every time. I've since put in the radio button functionality to change shape color and fill and added a button to clear the screen.
Not sure if this is the ideal way to do it but for this stupid simple little program it works well enough and I'm done stressing over it.
I'm developing an application that has to draw a map.
I have a JPanel grid that contains a 2D array of JPanel cells.
I'm using this:
public class myCell extends JPanel {
...
#Override
public void paint(Graphics g){
super.paint(g);
if (imageForeground != null) {
g.drawImage(imageForeground, 0, 0, this);
}
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(imageBackground, 0, 0, this);
}
}
This draws my background image, and my foreground image on top of it.
I want to draw an image in a cell, that will be displayed on TOP of the OTHER cells, ie, draw an image bigger than the cell, FROM the cell, something like:
#Override
public void paint(Graphics g){
super.paint(g);
super.drawImage(imageForeground, 0, 0, this);
or
g.drawImage(imageForeground, 0, 0, this, overflowFromPanel == true);
}
or if it's possible, tell the image that it CAN be bigger than my Cell.
For more informations:
The background cells are all 1*1 in size. The foreground image must be drawn over ALL the background images it spread over.
For example, if I draw a 3*3 hours at the [1,1] square, it must be over the [1,1], [1,2], [1,3], [2,1], etc...
Custom painting is done by overriding the paintComponent() method, not paint().
I'm developing an application that has to draw a map.
So the background image is the map and covers the entire panel. The house would then be painted on top of the map.
So in the parent component you override paintComponent() and paint the background image
Then in the CellPanel, you override paintComponent() and paint the foreground image. Although, why don't you just use a JLabel with an ImageIcon so you don't need to do custom painting?
if I draw a 3*3 hours at the [1,1] square,
Then you need to add your house image to 9 cells .
The other option is to forget about defining your map into cells. Instead you create a custom object with two properties:
Point - a point on the background map
Image - the image to paint at that point.
Then you add this custom Object to an ArrayList. Then in the paintCompont() method of the main panel you iterate through this ArrayList and paint each image at its specified location.
#Overide
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(...); // paint the background
for (each item in the ArrayList)
{
Point p = item.getPoint();
Image image = item.getImage();
g.drawImage(...);
}
}
Edit:
On a side note: the background is a different image for every cell.
Why are you using cells? It sounds like you have a fixed size grid. So you can just paint the individual cell images to a larger BufferedImage that makes a single background image for all the cells. Then you can just paint houses over top of the background.
Another option is to use the OverlayLayout. It allows you to stack two panels on top of one another.
So the logic would be something like:
JPanel panel = new JPanel();
panel.setLayout( new OverlayLayout(panel) );
panel.add( foregroundPanel );
panel.add( backgroundPanel );
You would need to:
Set the "foregroundPanel" transparent.
Both panels would override the paintComponent(...) method to do the custom painting.
Set the size of both panels to be the same.
Or you could use a JLayeredPane.
I have a little issue with my GUI in NetBeans. I draw images (dots) when a user clics in a JPanel at the mouse clic location. This part works just fine. I store each image locations in two different ArrayList that contains the X location and Y location. Now what I want to do is to delete the latest image drawn in the Panel after a button is clicked. So what I did is remove the last index of both ArrayList, and then call repaint() to draw all the images from the locations in both X and Y ArrayList (code below).
What is weird is that I need to resize the GUI (put it in full screen or just change its' size) in order for the drawn images to show up again in the JPanel otherwise, the panel remains empty.
Here's the parts of code that are affected :
public void paint(Graphics g) {
super.paint(g);
for(int i=0;i<=listePointsX.size()-1;i++) {
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/myimage.png"));
Graphics graphe = jPanel1.getGraphics();
graphe.setColor(Color.BLACK);
graphe.drawImage(icon, this.listePointsX.get(i),this.listePointsY.get(i), rootPane);
}catch(Exception e1){
}
}
private void jButtonUndoActionPerformed(java.awt.event.ActionEvent evt) {
if(listePointsX.size()>0){
int lastObject= listePointsX.size();
listePointsX.remove(lastObject-1);
listePointsY.remove(lastObject-1);
jPanel1.repaint();
}
else{
}
}
Any idea what I need to do to some kind of "refresh" the whole thing? Am I doing something wrong? Tried searching about that but did not find anyting...
Graphics graphe = jPanel1.getGraphics(); is NOT how painting should work, instead, you should have overriden the panel's paintComponent method and painted the points within in.
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
Instead, your panel should be doing ALL the work, managing the points in the ArrayList and painting them. You parent component "might" have the ability to add or remove points if that meets your design requirements, but the core responsibility remains with the panel.
Avoid performing any long running or block operations within the paint methods, they should run as fast as possible. Since the image never changes, you should simply load once (either when the class is constructed or when you first need the image) and keep using the same reference.
Alright it worked just fine now. I had to do it the way you told me up here. I created a new class that extends jPanel (below). Then in my main Form, had to create an object of this class. Whenever a user makes a click, it will call this Drawing class object and add an item to the ArrayList (this object manages everything regarding created points... It looks like this :
public class MyDrawingClass extends JPanel {
ArrayList<Integer> arrayListPointX = new ArrayList<>();
ArrayList<Integer> arrayListPointY = new ArrayList<>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/images/dot.png"));
g.setColor(Color.BLACK);
if(arrayListPointX.size()<=0){
...
}
else{
for(int i=0;i<listePointsX.size();i++){
g.setColor(Color.BLACK);
g.drawImage(icon, listePointsX.get(i), listePointsY.get(i), rootPane);
}
}
}catch(Exception e){
...
}
}
So if I want to "undo", let's say my object of "MyDrawingClass" is called "draw". I can do : draw.arrayListPointX.remove(draw.arrayListPointX.size()-1); and call repaint(); to display remaining points.
Thanks for your tips appreciate it ! :)
I'm a java beginner, and my java skills suck on this. In my jframe, i have this jpanel(below) which draws the image. I want the image changed whenever a radiobutton(in another frame) fires an ItemEvent and click something like a save button that'll fire an ActionEvent. i intend this to be of use for a character-selecting interface, as in MMORPGs, etc. Image panel below is intended for weapon-selecting interface in my game.
class Weapons extends JPanel {
private Image weaponimage = weapon2.getImage();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(weaponimage, 0, 0, this);
}
}
weapon2 is an ImageIcon. thanks in advance.
The simplest approach is not to have a custom panel at all, but use JLabel as the image container. Then you can change the image with:
label.setIcon(new ImageIcon(theNewWeaponImage));
Edit: since it looks like you already have Icons, you can use those directly:
label.setIcon(theNewWeaponIcon);
I need to make an image map using Swing that displays a background image, and then when the mouse hovers over (or clicks) specific hotspots, I need to pop up a 'zoomed-in' image and have it display.
I was thinking of extending JPanel to include an image reference and have that drawn thru the paintComponent(g) method. This part I have done so far, and here's the code:
public class ImagePanel extends JPanel
{
private static final long serialVersionUID = 1L;
private Image image;
public ImagePanel(Image image)
{
setImage(image);
}
public void setImage(Image newImage)
{
image = newImage;
}
#Override
public void paintComponent(Graphics g)
{
Dimension size = getSize();
g.drawImage(image, 0, 0, size.width, size.height, this);
}
Could anyone recommend how I might listen for / respond to mouse clicks over defined hot-spots? Could someone additionally recommend a method for displaying the pop-ups? My gut reaction was to extend JPopupMenu to have it display an image, similar to the above code.
Thanks for any help!
To listen to the mouse clicks implement the MouseListener interface, and add it to your panel. Then when the click is recieved you can use a JPopupMenu as you suggested, or you could even use a glass pane to show the zoomed in image.
I'm guessing you want to achieve something similar to this post by Joshua Marinacci, he has also posted the source here, I would take a look at that.
I would probably:
create some instance of Shape that represents each of your hotspots (could be a plain boring old Rectangle, or see GeneralPath if you need to create fancy shapes)
register a MouseListener which iterates through each of the Shapes and calls its contains() method to see if the clicked coordinate is inside the hotspot in question