How to set repeating background image to a JPanel? - java

I want to set an image which repeats throughout the full width of the JPanel like we apply Background image to a DIV in CSS. How do I obtain that in swing for a JPanel?

Swing doesn't provide this functionality out of the box, so you will need to do it yourself...
The overall process is relative simple,
for (y = 0 to containerHeight) do
for (x = 0 to containerWidth) do
drawImage(tile, x, y)
The fun part is knowing where and how to apply it. Take a look at:
Performing Custom Painting
2D Graphics
Reading/Loading an Image
For details about the various parts you will need to know.
Example
So using this as the tile...
I was able to produce this...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PaintTitle {
public static void main(String[] args) {
new PaintTitle();
}
public PaintTitle() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage tile;
public TestPane() {
try {
tile = ImageIO.read(getClass().getResource("/tile.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int tileWidth = tile.getWidth();
int tileHeight = tile.getHeight();
for (int y = 0; y < getHeight(); y += tileHeight) {
for (int x = 0; x < getWidth(); x += tileWidth) {
g2d.drawImage(tile, x, y, this);
}
}
g2d.dispose();
}
}
}

Related

Java anti fillRect (fill everything outside of said rectangle)

In Java, there is the Graphics2D.fillRect(x, y, width, height) function. In my program, I am looking for something similar, yet completely opposite.
I need to fill everything on the screen except this certain x, y, width, height, sort of like an anti-fillRect. Is there a built in function that I am overlooking, or can you point me in the right direction to create one?
Not required, but it would be a nice bonus if it could work with other Java 2D shapes.
There are a few ways that might be achieved, the easiest might be to use
java.awt.geom.Area which is a highly versatile Shape implementation, which allows you to add and subtract Areas from it, for example...
I've left the fill color slightly translucent to prove the point ;)
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.geom.Area;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CutExample {
public static void main(String[] args) {
new CutExample();
}
public CutExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
public TestPane() {
try {
img = ImageIO.read(...);
} catch (IOException ex) {
Logger.getLogger(CutExample.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getWidth()) / 2;
g2d.drawImage(img, x, y, this);
Area outter = new Area(new Rectangle(0, 0, getWidth(), getHeight()));
x = (getWidth() / 2) - 100;
y = (getHeight() / 2) - 100;
Rectangle inner = new Rectangle(x, y, 200, 200);
outter.subtract(new Area(inner));
g2d.setColor(new Color(0, 0, 0, 192));
g2d.fill(outter);
}
g2d.dispose();
}
}
}
I should also mention that you can use any other Shape you want...

Layering text over JLabel

This is how I want my app to look like.
Trouble is, if I drag the JLabel with the "Hello, I'm Myra" over another JLabel (whose icon is the speech bubble), rather than superimposing or layering, NetBeans shifts the JLabels to be adjacent.
How do I superimpose ie. place the text JLabel on top of another JLabel?
Do note, I'm using NetBeans. It doesn't allow me to edit much of the JFrame or JLabel code.
Netbeans won't let you add components to a JLabel, it doesn't see them as a valid Container.
This won't be easily achieved using component labels, as the icon placement is outside of your control. A better solution might be to use a custom component, such as a JPanel and manually draw the speech bubble image yourself, then using a combination of Border and LayoutManager it would allow you to add other components to it
This is a very basic example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class SpeechBubble {
public static void main(String[] args) {
new SpeechBubble();
}
public SpeechBubble() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
SpeechBubblePane bubble = new SpeechBubblePane();
JLabel hello = new JLabel("Hello, I'm Myra");
hello.setFont(hello.getFont().deriveFont(28f));
hello.setForeground(Color.CYAN);
JLabel message = new JLabel("<html>What would you like to know today?</html>");
message.setFont(message.getFont().deriveFont(22f));
message.setForeground(Color.WHITE);
bubble.setLayout(new GridLayout(2, 1));
bubble.add(hello);
bubble.add(message);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.BLACK);
frame.add(bubble);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SpeechBubblePane extends JPanel {
private BufferedImage background;
public SpeechBubblePane() {
setOpaque(false);
try {
background = ImageIO.read(getClass().getResource("/speechbubble.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
setBorder(new EmptyBorder(19, 19, 66, 19));
}
#Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
if (background != null) {
size = new Dimension(background.getWidth(), background.getHeight());
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight()- background.getHeight()) / 2;
g2d.drawImage(background, x, y, this);
g2d.dispose();
}
}
}
}
If I was doing this, I would consider developing up a "9-path" which would allow you to break the image down into 9 parts and scale the outer sections based on what the content requires, for example...
It sounds like you just want to add a z-order. If so, you need a LayeredPane:
http://docs.oracle.com/javase/7/docs/api/index.html
http://docs.oracle.com/javase/7/docs/api/javax/swing/JLayeredPane.html

getting the right image observer for rotating an image

So Im drawing a BufferedImage 'bird' but I want to rotate it according to the angle that it is falling. I have a bird object which contains the BufferedImage and a render() method which draw it rotated.
public void render(Graphics2D g, ImageObserver io) {
double theta = Math.tan((height - pastHeight) / .875);
System.out.println(theta);
Graphics2D g2 = (Graphics2D) bird.getGraphics();
g2.drawImage(bird, 100, (int) height, null);
g2.rotate(theta);
g2.drawImage(bird, 100, (int) height, io);
}
I call this as such
bird.render(g2, ???);
in my paintcomponent method in my jcomponent.
only problem is I dont know what to use as my ImageObserver... I've tried passing in my JFrame and my JComponent but the image no longer appears when I do that... what would I pass in for the image to appear in my window and/or how else would I achieve this rotation?
Assuming that you are doing this in something that extends JComponent, you should use
bird.render(g2, this);
As JComponent implements ImageObserver
The problem with the image disappearing isn't an issue with the ImageObserver but the point around which the rotation is occurring, which I believe is the top/left corner of the Graphics context.
Try using Graphics2D#rotate(double, int, int) which will allow you to specify the origin points of the rotation (pivot point).
Don't forget to reset your translations, as they will effect everything that is painted after your supply them and may be re-used in subsequent paint cycles.
Updated with simple example
This is a basic example that demonstrates the different uses of rotate.
First, I simply used Graphics#rotate(double)
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RotateImage {
public static void main(String[] args) {
new RotateImage();
}
public RotateImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private double angel = 0d;
public TestPane() {
try {
img = ImageIO.read(...);
} catch (IOException ex) {
ex.printStackTrace();
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angel += 5;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.rotate(Math.toRadians(angel));
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
}
Then I replaced g2d.rotate(Math.toRadians(angel)); with g2d.rotate(Math.toRadians(angel), getWidth() / 2, getHeight() / 2);, which used the center position of the component (or the Graphics context) as the anchor point around which the rotation would occur...
Now, because you only want to rotate your image, you're going to need to calculate the anchor point around the current position of the image's center position (assuming you want it to rotate around the middle)

zoom using mouse and graphics

I draw in my JComponent some curves, etc .. with Graphics G ( not 2D ).
Now I want to use the scroll wheel of my mouse to zoom in and out.
Any tracks ?
I heard talk about a BuferredImage ?
There are a few considerations you need to take into account...
The end result will depend on what you want to achieve. If you are drawing curves using the Graphics2D API, it might be simpler to simply scale the coordinates each time the component is rendered. You will need to make sure that any changes in the scale are reflected in the preferred size of the component itself.
You could also render the "default" output to a BufferedImage and simply use an AffineTransform to change the scaling the is used to render the result, for example.
This simple uses a BufferedImage and loads a picture from disk, but the basic concept is the same.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomPane {
public static void main(String[] args) {
new ZoomPane();
}
public ZoomPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private float scale = 1;
public TestPane() {
try {
img = ImageIO.read(new File("/path/to/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseWheelListener(new MouseAdapter() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
double delta = 0.05f * e.getPreciseWheelRotation();
scale += delta;
revalidate();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
if (img != null) {
size.width = Math.round(img.getWidth() * scale);
size.height = Math.round(img.getHeight() * scale);
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.scale(scale, scale);
g2d.drawImage(img, at, this);
g2d.dispose();
}
}
}
}
You could also scale the Graphics context passed to your paintComponent method directly.
The important thing here is to remember to reset the AffineTransform after you have completed, otherwise it will be passed to other components when they are rendered, which won't generate the expected output...
This example basically creates a copy of the Graphics context which we can manipulate and dispose of without effecting the original, making it simpler to mess with
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomPane {
public static void main(String[] args) {
new ZoomPane();
}
public ZoomPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private float scale = 1;
public TestPane() {
addMouseWheelListener(new MouseAdapter() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
double delta = 0.05f * e.getPreciseWheelRotation();
scale += delta;
revalidate();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(200, 200);
size.width = Math.round(size.width * scale);
size.height = Math.round(size.height * scale);
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.scale(scale, scale);
g2d.setTransform(at);
g2d.setColor(Color.RED);
// This is for demonstration purposes only
// I prefer to use getWidth and getHeight
int width = 200;
int height = 200;
Path2D.Float path = new Path2D.Float();
int seg = width / 3;
path.moveTo(0, height / 2);
path.curveTo(0, 0, seg, 0, seg, height / 2);
path.curveTo(
seg, height,
seg * 2, height,
seg * 2, height / 2);
path.curveTo(
seg * 2, 0,
seg * 3, 0,
seg * 3, height / 2);
g2d.draw(path);
g2d.dispose();
}
}
}
Take a look at Transforming Shapes, Text and Images for more details
Try JFreeChart; the setMouseWheelEnabled() method, used to control zooming in ChartPanel, is illustrated in examples cited here.
I put this simple code to show you how to use mouse wheel mouving by adding a MouseWheelListener to a JPanel:
myJpanel.addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent mwe) {
jPanelMouseWheelMoved(mwe);
}
});
To implement the mouse wheel listener:
private void jPaneMouseWheelMoved(MouseWheelEvent mwe) {
if(Event.ALT_MASK != 0) {
if(mwe.getWheelRotation() > 0) {
//here you put your code to scrool douwn or to minimize.
System.out.println(" minimize by "+(-1*mwe.getWheelRotation()));
}
else if(mwe.getWheelRotation() < 0) {
//here you put your code to scrool up or to maximize.
System.out.println(" maximaze by "+(-1*mwe.getWheelRotation()));
}
}
}
You can adapt this exemple to zoom or to scrool what you want.

How do I get the X and Y location of an image in a JScrollPane

I am trying to make a Map Editor for a 2D RPG, and what I currently am trying to do (to place tiles on the ground) is to have a JScrollPane with a JLabel (that has an image in it) and a Mouse Listener attached to the JScrollPane to determine the X and Y location of the image. The problem I run into is that it doesn't get the Images X and Y location but the JScrollPanes X and Y location.
So I have a JScrollPane attached to an Image that is 512x4928, I attached a mouse listener to it. the problem resides when I try to get the Y location, since JScrollPane is a separate object it gets the X and Y of the size of the JScrollPane
JScrollPanes size is 512x600
no matter where the image is at, it will never return a value greater than 600.
Any way I can make this work?
Heres the the Code
public void loadMapTileImage(){
try {
image = ImageIO.read(getClass().getResource("data/misc/tiledata.png"));
image = image.getSubimage(0, 0, 512, 4928);
} catch (IOException e) {
e.printStackTrace();
}
ImageIcon i = new ImageIcon(image);
MapEditorGlobalObjects.mapTileScroll = new JScrollPane(new JLabel(i));
}
mapTileScroller.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent arg0) {
MapEditorGlobalObjects.checkIfDebugging("Mouse Released Location X = "+arg0.getX());
MapEditorGlobalObjects.checkIfDebugging("Mouse Released Location Y = "+arg0.getY());
}
#Override
public void mousePressed(MouseEvent arg0) {
MapEditorGlobalObjects.checkIfDebugging("Mouse Clicked Location X = "+arg0.getX());
MapEditorGlobalObjects.checkIfDebugging("Mouse Clicked Location Y = "+arg0.getY());
}
Instead of adding the MouseListener to the scrollpane, try adding it to the scroll pane's view component (ie, the thing that the scroll pane is displaying)
The image in this example is 2560x1600
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
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.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestScrollPanePos {
public static void main(String[] args) {
new TestScrollPanePos();
}
public TestScrollPanePos() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(new TestPane()));
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage bg;
private Point point;
public TestPane() {
try {
bg = ImageIO.read(new File("/path/to/image));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
System.out.println(e.getPoint());
point = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return bg == null ? new Dimension(200, 200) : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - bg.getWidth()) / 2;
int y = (getHeight()- bg.getHeight()) / 2;
g2d.drawImage(bg, x, y, this);
if (point != null) {
FontMetrics fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(point.x + "x" + point.y, point.x, point.y - fm.getHeight() + fm.getAscent());
}
g2d.dispose();
}
}
}
}
If you use JScrollPane for this, get the value of the vertical scrollbar, and add it to the Y value from the mouse listener and you will have the correct value

Categories

Resources