Paint an image on parent component - java

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.

Related

Highlight Part of Image Icon on JLabel in Java

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.

Java (re)painting mechanism [duplicate]

In java awt or swing when you want to change painting of some component you usually have to override the method paint(Graphics g) (in awt) or paintComponent(Graphics g) (in swing).
This is usually (maybe allways - I'm not sure) done when you are creating the component for example:
JPanel jPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//... my implementation of paint, some transfromations, rotation, etc
}
};
Imagine that you have container of components which could for example consists of some JLabels, some JTextFields, some image. Which will be all put on one component.
By container I mean you have some list or map with ids or some similar structure in which are all components you will put on one JFrame.
The question is if I can change the painting method after creating with all of the components which are in this list in the moment when all of them are already created. For example I want do the rotation action (rotate), which is defined in Graphisc2D, with all of them.
So basicaly what I want is that I throught the list of componets I have and say:
"All of you (components) which are in the list will be rotated by some angle". Is that possible? If yes how?
Edit:
This is my not correctly working solution:
graphicalDisplayPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.rotate(Math.PI, anchorx, anchory);
}
#Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.rotate(Math.PI, anchorx, anchory);
}
};
JFrame jFrame = JFrame();
// ... setting dimension, position, visible etc for JFrame, it works correctly nonrotated
jFrame.setContentPane(graphicalDisplayPanel);
I have not tested this, but it seems like it would work. A JComponent's paint() method calls:
paintComponent(co);
paintBorder(co);
paintChildren(co);
where co is a Graphics object. In theory you create an image, retrieve the graphics object and then pass that into paintChildren(). you will have to call paintComponent() and paintBorder() yourself, if you do this. Then, just rotate the image and draw it into your component. You may have to crop the image or resize your component accordingly for this to work. It might look something like this:
BufferedImage myImage;
#Override
public void paint(Graphics g){
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
//using a transparent BufferedImage might not be efficient in your case
Graphics myGraphics = myImage.getGraphics();
super.paintComponent(g);
super.paintBorder(g);
super.paintChildren(myGraphics);
//rotation code here
// ...
//draw children onto your component
g.drawImage(myImage, 0, 0,getWidth(), getHeight(), null);
}
I hope I didn't make any mistakes, please let me know if this works.
So basicaly what I want is that I throught the list of componets I have and say: "All of you (components) which are in the list will be rotated by some angle".
If you want to rotate panel and therefore all the components on the panel as a single using then you need to do the custom painting in the paintComponent() method.
If you want to rotate, for example, individual images that each have a different angle of rotation then you can again do this in the paintComponent(...) method and change the angle for each component.
Or, in this second case you can use the Rotated Icon class. In this case the Icon is just added to a JLabel. Then you can change the degrees of rotation and repaint the label, so there is no custom painting (except in the Icon itself).

JPanel inside JScrollPane scrollbars not showing up

I am currently trying to make it possible for a JPanel to be zoomed in. My idea is pretty much as follows :
I have a JPanel (custom with overriden paintComponent etc.) that I place inside my JScrollPane.
What I do to zoom in is to scale up my JPanel using the following code (overriding the paint method)
#Override
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
if (m_hasBeenScaled)
{
m_transform.scale(m_zoomValue, m_zoomValue);
g2.setTransform(m_transform);
m_transform = new AffineTransform();
}
super.paint(g);
}
This works well, however my JScrollPane doesn't display scrollbars as I scale to bigger dimensions. How do I make the JScrollPane respond to this scale up of my JPanel ?
Here's the code I use to create both my JPanel and JScrollPan (Grid is my class extending JPanel):
m_gridPanel = new Grid();
m_gridContainer = new JScrollPane(m_gridPanel);
m_gridContainer.setPreferredSize(new Dimension(605, 605));
The size of the component will be affected by the zoom factor as well, to that end, setting the preferredSize to a "static" value makes no sense, instead, you should be overriding the getPreferredSize and adjusting the size returned by applying the zoom factor to it as well.
Zooming a component is much more complex than changing the transform, you should be translating the mouse events as well, see How to add MouseListener to item on Java Swing Canvas for example.

JPanel image and components

I would like to have image on my JPanels an also have components such as JSlider and JRadioButton on my JPanel. I derived a class from JPanel and overrided method paintComponent as you see. This is a good way to have image on JPanel.
public void paintComponent(Graphics g)
{
/*create image icon to get image*/
ImageIcon imageicon = new ImageIcon(imageFile); //getClass().getResource(imageFile)
Image image = imageicon.getImage();
/*Draw image on the panel*/
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
However I have some problems. When I add components such as JSlider, JRadioButton or another JPanel on my ImagePanel; this component's background remains as default and not background picture. I don't know how to set this image as background of this components.
please guide me.
regards
you must set opaque properties of other component to false.
jRadioButton.setOpaque(false);
for example :
jRadioButton.setOpaque(false);
Will work for many look-and-feels, but if you want it to work with Nimbus you should also set the background color to be transparent:
jRadioButton.setBackground(new Color(0,0,0,0));
See this question for more details.
Doesn't setOpaque(false) for all the other components help?

JOptionPane background Image

How to set background Image of JOptionPane? I want to show a different image on background of an JOptionPane.
You could extend the JOptionPane class and override the paint method.
Edit:
Depending on the image resolution and quality you might be able to stretch it with an AffineTransform during the WindowResize events without to much distortion. This would let you handle the JOptionPane and image size discrepancies mentioned below.
class ImageBackgroundPane extends JOptionPane
{
private BufferedImage img;
public ImageBackgroundPane (BufferedImage image)
{
this.img = image;
}
#Override
public void paint(Graphics g)
{
//Pick one of the two painting methods below.
//Option 1:
//Define the bounding region to paint based on image size.
//Be careful, if the image is smaller than the JOptionPane size you
//will see a solid white background where the image does not reach.
g.drawImage(img, 0, 0, img.getWidth(), img.getHeight());
//Option 2:
//If the image can be guaranteed to be larger than the JOptionPane's size
Dimension curSize = this.getSize();
g.drawImage(img, 0, 0, curSize.width, curSize.height, null);
//Make sure to paint all the other properties of Swing components.
super.paint(g);
}
}

Categories