I have a JFrame which has 4 different Panels. The Black box on right in the image below is the Image Panel. I am trying to write a Class that will allow me to load an image into any Panel within any other class in my program.
http://sdrv.ms/14TEq2T
LoadImage.java
package sf;
import java.awt.*;
import java.awt.image.*;
import javax.swing.ImageIcon;
public class LoadImage extends Component {
BufferedImage img;
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
}
public LoadImage(String filename) {
try {
System.out.println(filename);
img = new ImgUtils().scaleImage(380, 360, filename);
} catch (Exception e) {
System.out.println("File not found");
}
}
class ImgUtils {
public BufferedImage scaleImage(int WIDTH, int HEIGHT, String filename) {
BufferedImage bi = null;
try {
ImageIcon ii = new ImageIcon(filename);
bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(ii.getImage(), 0, 0, WIDTH, HEIGHT, null);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return bi;
}
}
}
Code that I use to load in the Image in my other Classes.
private void getProductImage() {
try {
String path = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
String newPath = decodedPath.replace("build/classes/", "src/productImages/");
productImagePanel.add(new LoadImage(newPath + imageCode + ".jpg"));
revalidate();
pack();
} catch (Exception e) {
e.printStackTrace();
}
}
The 'imageCode' is the code that is retrieved from database once the Window is visible and I have checked the Path to images several times.
The LoadImage.java works on its own and load the images if a 'main runnable' method is added to it, however I can't seem to display the image in the panel I want. Please advice on how to fix my problem, any help is appreciated!
Your problem could very well be you're trying to load the image as a component to the JPanel. Problems include:
the preferredSize of the Component could well be [0, 0], and so it can be trying it's little heart out to display an image but just be too small to do so.
There could be other components already added to the JPanel
The JPanel's layout may not play nice with newly added components.
You shouldn't mix heavy weight (Component) with light weight (most all other non-top level Window Swing components) without a definite need.
I suggest:
Add a JLabel to your image displaying JPanel just once on JPanel creation.
Give your productImagePanel a method that accepts an Image or an ImageIcon and then either creates the ImageIcon from the Image or uses the ImageIcon provided to set the Icon of the JLabel.
Be sure that the JPanel uses a layout that allows the JLabel to display itself fully. The layout manager tutorials can help with this.
Either that or all the image displaying JPanel is for is to show the image and nothing else, get rid of it and instead use a JLabel by itself, and add your Icons directly to it.
Also as an aside: you should be disposing any Graphics and Graphics2D objects that you create (but not any given to you by the JVM). That means that when you're done drawing with g2d in your ImageUtilities, dispose of it.
Related
I am writing a program that consists of three different panels.
This is part of my bottom panel. I display an image using BufferedImage, and I would like to create some text that will appear around 350px into the image, and 15px down. I cannot manage to get this to work and overlay over the bufferedImage.
My current code is as follows (For the bottom panel):
public class BtmPanel extends JPanel {
BtmPanel(){
try {
JLabel imgLabel = new JLabel();
final BufferedImage img = ImageIO.read(new File("image.png"));
ImageIcon icon = new ImageIcon(img);
imgLabel.setIcon(icon);
this.add(imgLabel);
}
catch(IOException ie){
System.out.println("image does not exist");
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("Y: " + MiddlePanel.y ,350,15);
}
}
There are a couple of ways you might achieve this, depending on your needs and desires.
For example, rather than using a JLabel to display the image, you could paint it directly yourself, for example...
public class BtmPanel extends JPanel {
private BufferedImage image;
BtmPanel(){
try {
image = ImageIO.read(new File("image.png"));
}
catch(IOException ie){
System.out.println("image does not exist");
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(0, 0, image, this);
}
g.drawString("Y: " + MiddlePanel.y ,350,15);
}
}
The reason for doing it this way is you don't (really) control the placement of the image within a JLabel (lots of things can affect it's positioning).
Another solution would be to draw the text directly onto the BufferedImage itself. Which you would use would depend on how dynamic the text might be and a bunch of other factors
A way to do this is doing the exact inverse of your example, overriding the JPanel's paint method painting a BufferedImage (creating a background with your image), and then you can normally add the JLabel with text on your JPanel extension.
Please note that if JPanel is resized and you don't want to have a bad quality background, you'll have to manually create a resized version to adapt the container, or, at least, resize your buffered image with a little logic to keep Width/Height ratio... not that easy!
For the basic version you can try something like the following (taken from a working example) paintComponent overridden function:
#Override
protected void paintComponent(Graphics g) {
Image background = backgroundImage.getScaledInstance(this.getWidth(), this.getHeight(), Image.SCALE_DEFAULT);
super.paintComponent(g);
if (backgroundImage != null) {
g.drawImage(background, 0, 0, null);
}
}
Hope this helps ;)
I’ve been reading the API for Graphics2D and have seen examples of all the available composite modes (that are similar to photoshop blend modes) but I can’t see a way to draw a source image to a target buffered image In a colour that I have specified, for example my source image is a white opaque circle on a fully transparent background, how do I draw using this to a buffer so a coloured circle is drawn.
I would prefer not to construct an intermediate image for performance reasons, is this possible with the api?
EDIT: I have added an image that hopefully helps to show the operation I am trying to describe. This is a common way to draw sprites in open GL etc and I am just wondering how to use the Graphics2D API to do the same thing.
Is is possible using the API but you have to write your own ImageProducer subclass similar to FilteredImageSource but with two input images instead of one. But because of that the end result will require more lines of code than a manual implementation and won't be any more efficient. Alternatively you can use the existing FilteredImageSource and write an ImageFilter subclass that wraps the 2nd image and does the hard work.
Poke me if you decide you want to go with any of these routes.
Specify the location of your image in the imageName below.
public class ColoredCircle extends JPanel {
JFrame frame = new JFrame();
BufferedImage buf;
String imageName = "F://ngc_1300_spiral.jpg";
public static void main(String[] args) {
new ColoredCircle().start();
}
int scale = 10;
public void start() {
try {
buf = ImageIO.read(new File(imageName));
}
catch (IOException ioe) {
ioe.printStackTrace();
}
setPreferredSize(
new Dimension(buf.getWidth() / scale, buf.getHeight() / scale));
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(buf,
0,
0,
buf.getWidth() / scale,
buf.getHeight() / scale,
null);
g2d.dispose();
}
}
I am trying to draw an image to a JPanel which in turn is added to a JFrame, see here:
JFrame screen;
public void welcome(){
screen = new JFrame("Welcome");
screen.setVisible(true);
screen.pack();
screen.setBackground(Color.darkGray);
screen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
// in the original code there is series of methods here that eventually calls the drawBoard() method
public void drawBoard(){
try {
final BufferedImage gboard = ImageIO.read(new File("cutsomGameBoard.jpg"));
final BufferedImage featPanel = ImageIO.read(new File("extraPanel.png"));
board = new JPanel(){
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(gboard, 0, 0, this);
}
};
extra = new JPanel(){
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(featPanel, 0, 0, this);
}
};
board.setSize(480, 480);
extra.setSize(480, 320);
}
catch (IOException e) {
e.printStackTrace();
}
}
gameScreen.add(toolbar, BorderLayout.PAGE_START);
gameScreen.add(board, BorderLayout.EAST);
gameScreen.add(extra, BorderLayout.WEST);
gameScreen.setVisible(true);
screen.add(gameScreen);
}
My problem is that when running the code, only a small corner of the buffered image is visible and I am not sure if it is a problem with the frame layout, the panel size or the drawImage method arguments, ideas?
P.S. The output: screenshot of java window
You didn't override the getPreferredSize() method of your custom component so the default size is basically (10, 10) which is the size of a panel using a FlowLayout with no added components.
Don't use a JPanel to display an image. Or if you do want to use a JPanel then you need to implement the getPreferredSize() method to return the size of your image.
The easiest solution is to just use a JLabel with an ImageIcon.
Read the section from the Swing tutorial on How to Use Icons for more information and working examples.
I want go full screen and keep everything inside in order.
How should i put the JFrame into full screen AND rescale everything inside: images, generated drawings etc.(sth like zooming it up so the content will fit the screen).
The problem is I am making full screen app, but I don't know on what screen it will be displayed.
This will put the frame into fullscreen, but the content will not be rescaled
frame.dispose();
frame.setUndecorated(true);
frame.setLocation(0, 0);
frame.setSize(java.awt.Toolkit.getDefaultToolkit().getScreenSize());
frame.setVisible(true);
frame.repaint();
Depends on what it is that you want to scale.
If its graphics you draw using Java2D, just figure out how much the stuff needs to be scaled up and use Graphics2D.scale() to scale the gfx appropiately.
If its something with a Swing layout, use a Layout manager to make an adaptive layout.
If its something else, elaborate on your problem
If this really is what you want to do (see warnings from other answers), it's not too hard to do (but takes a little time to figure out). Basically, it involves extending JPanel, and then overwriting the paint method.
Here's a sample that I came up with:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class CustomPanel extends JPanel{
Component myComponent;
public CustomPanel(){
super();
setLayout(null);
}
/**
* Only allows one component to be added
*/
#Override
public Component add(Component c){
super.add(c);
c.setLocation(0, 0);
c.setSize(c.getPreferredSize());
myComponent = c;
return c;
}
#Override
public void paint(final Graphics g){
Dimension d = this.getSize();
Dimension p = myComponent.getPreferredSize();
// Paints the child component to a image
BufferedImage newImg = new BufferedImage(p.width, p.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = newImg.createGraphics();
super.paint(g2d);
// Resizes the image if necessary
Image img;
if(d.height > p.height && d.width > p.width){
System.out.println("Scaled");
float changePercentage = 0;
if(d.height/p.height > d.width/p.width){
changePercentage = (float)d.width/(float)p.width;
} else{
changePercentage = (float)d.height/(float)p.height;
}
System.out.println(changePercentage);
int newHeight = ((Float)(p.height * changePercentage)).intValue();
int newWidth = ((Float)(p.width * changePercentage)).intValue();
img = newImg.getScaledInstance(newWidth, newHeight, 0);
} else{
System.out.println("Not Scaled");
img = newImg;
}
// Paints the image of the child component to the screen.
g.drawImage(img, 0, 0, null);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable(){public void run(){
JFrame frame = new JFrame("Zoom Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
CustomPanel buffer = new CustomPanel();
JPanel content = new JPanel();
content.add(new JLabel("Bogus"));
content.setBackground(Color.red);
buffer.add(content);
frame.setContentPane(buffer);
frame.setVisible(true);
new CustomPanel();
}});
}
}
few days back I just worked with an java full screen app. Have a look at the following link. if that was your requirement I can help you to some extent.
https://docs.google.com/open?id=0B9U-BwYu62ZaeDM3SWZhaTdSYzQ
How to display an image to JPanel or to JLabel using the BufferedImage?
I load an Image using FileChooser and I need to display what I've loaded.
I don't extend my class to any container.
Override paintComponents(g) paintComponent(g) method of JPanel or JLabel and draw image in it. Something like follow:
JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g) {
BufferedImage image = null; // get your buffered image.
Graphics2D graphics2d = (Graphics2D) g;
graphics2d.drawImage(image, 0, 0, null);
super.paintComponents(g);
}
};
Same thing for JLabel. Or in another way:
BufferedImage image = null; // get your buffered image.
ImageIcon icon = new ImageIcon((Image)image);
JLabel label = new JLabel();
label.setIcon(icon);
As you are saying that you are loading image from FileChooser it can be done in following
way:
ImageIcon icon = new ImageIcon(
fileChooser.getCurrentDirectory().toString()
+"/"+fileChooser.getSelectedFile().getName());
Now you can use ImageIcon in JLabel or add it in JPanel.
Above code is sample code and not tested so not necessary to run without error. You might need to change it as per your need.