Calling Graphics.drawImage in the contructor of a JFrame Java [duplicate] - java

I'm new on working with Java and Netbeans. In many others languages, it's a simple stuff to do. But after broke my brain thinking, I couldn't. My doubt is simple to explain.
How can I show bitmaps (stored on Hard Drive) in runtime, in a commom JFrame, using java2D? What I need to edit, and or create? Is it simple to do?
Thanks in advance...

The basic process is use Graphics#drawImage to render an image you have previously loaded.
There are a number of things you need in order to achieve this...
An image to paint
A surface to paint on
Luckily, both these are relatively easy to achieve in Swing
See ImageIO for reading images, Reading/Loading an Image
See Performing Custom Painting for more details about how to perform painting in Swing...
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.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 ShowMyImage {
public static void main(String[] args) {
new ShowMyImage();
}
public ShowMyImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
ImagePane pane = new ImagePane();
try {
pane.setImg(ImageIO.read(new File("C:\\hold\\thumbnails\\_MTCGAC__Pulling_Cords_by_Dispozition.png")));
} catch (IOException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ImagePane extends JPanel {
private BufferedImage img;
public ImagePane() {
}
public void setImg(BufferedImage value) {
if (img != value) {
img = value;
repaint();
}
}
public BufferedImage getImg() {
return img;
}
#Override
public Dimension getPreferredSize() {
BufferedImage img = getImg();
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();
BufferedImage img = getImg();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight()- img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
}
g2d.dispose();
}
}
}

You need, as was told below to extend JPanel class and override paintComponent method in it.
public class DrawImageClass extends JPanel {
private static final long serialVersionUID = 1L;
private Image image;
public DrawImageClass(Image image) throws HeadlessException {
super();
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(image, null, null);
}
}
And then create JFrame and add this class to it.
public class App {
private static final int WIDTH=480, HEIGHT = 640;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(new Dimension(HEIGHT, WIDTH));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
DrawImageClass panel = new DrawImageClass(ImageIO.read(new File(App.class.getResource("/1.png").getPath())));
panel.setPreferredSize(new Dimension(HEIGHT, WIDTH));
frame.add(panel);
frame.setVisible(true);
} catch (Exception e) {
System.out.println("wrong path or smth other");
}
}
}
Example for picture which is in resource folder in project

You can do this with the basic AWT package in java. You will need to extend the JFrame class and override its paintComponent method to display an image there. i.e.
public class MyFrame extends JFrame {
private java.awt.Image bitmap = ImageIO.read(new File("myBitmap.bmp"));
#Override
public void paintComponent(java.awt.Graphics graphics) {
int x = 0;
int y = 0;
int w = bitmap.getWidth(null);
int h = bitmap.getHeight(null);
graphics.drawImage(bitmap, x, y, w, h, this);
}
}
You can simply instantiate it then
MyFrame myFrame = new MyFrame();
myFrame.setPreferredSize(new Dimension(100, 100));
myFrame.setVisible(true);
This is a basic example of course.

Related

Placing JButton on image

Aim: to place JButton on a top of an image that is loaded from a different class.
Problem: only JButton or image can be displayed
//main class
JPanel mPanel.add(new JButton("ddd") );
mPanel.add(drawbg);
class DrawBg extends JPanel {
public Dimension getPreferredSize() {
return new Dimension(1280, 720);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// background
Image img = new ImageIcon(getClass().getResource("/images/test_bg.jpg")).getImage();
int imgX = img.getWidth(null);
int imgY = img.getHeight(null);
g.drawImage(img, (getWidth() - imgX), (getHeight() - imgY), imgX, imgY, null);
}
Edit Ah yes, as ControlAltDel points out, you're not adding your JButton to your drawing JPanel instance. Just do that, and your problem is solved.
I don't see the bug in your code, so it might lie in code not shown. I do see a problem in that you're reading the image in, inside of paintComponent, something that should never be done as it will slow down painting and thus slow down the perceived responsiveness of your program. Also, why re-read in the image with each paint. Instead read it in once.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ButtonOnImg extends JPanel {
public static final String IMG_PATH = "https://duke.kenai.com/gun/Gun.jpg";
private BufferedImage img;
public ButtonOnImg() throws IOException {
URL url = new URL(IMG_PATH);
img = ImageIO.read(url);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, null);
}
}
#Override
public Dimension getPreferredSize() {
if (img == null) {
return super.getPreferredSize();
} else {
int w = img.getWidth();
int h = img.getHeight();
return new Dimension(w, h);
}
}
private static void createAndShowGui() {
try {
ButtonOnImg mainPanel = new ButtonOnImg();
mainPanel.add(new JButton("Button!"));
JFrame frame = new JFrame("ButtonOnImg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which displays as:

Graphics2D setfont() heavily slows down the start up of java application

I am making a game by java and it refreshes itself 60 times per second. Every time it executes a loop and I use g2d to draw images and strings. Things work fine if I do g2d.setFont(new Font("Arial", Font.PLAIN, 8)); and drawstring and it would be normal, but if I set the font to some "unfamiliar" fonts and do the same thing, the swing would show white screen in the first second of start up then paint everything correctly and it's apparently too slow (2 secs).
I put a jpanel in a jframe and override the paint() method of jpanel to draw everything I need. I've already used SwingUtilities.invokeLater in my code.
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame{
public Window(){
add(new Board());
setSize(800,600);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
private class Board extends JPanel {
Font font = new Font("Bitmap", Font.PLAIN, 64);
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setFont(font);
g2d.drawString("This is slow", 220,200);
Toolkit.getDefaultToolkit().sync();
g2d.dispose();
g.dispose();
}
}
}
This is not in a loop but it's very laggy.
http://fontsov.com/download-fonts/bitmap1159.html
This is the cutie font that slows our application down. "Arial" will load blazingly fast. How can I make this less laggy?
First and foremost, for best help, create and post your minimal code example program for us to review, test, and possibly fix. Without this, it will be hard for us to fully understand your problem.
Consider:
Overriding paintComponent not paint to get the advantage of double buffering.
Avoid using invokeLater unless you're sure that the code is being called off of the Swing event thread and you are making calls that need to be on the event thread.
Put slow running code in a background thread such as that which can be found using a SwingWorker.
Putting your text in a JLabel, not drawn on a component.
Draw all static images to a BufferedImage, and displaying that in paintComponent. Then draw all changing images, such as your moving sprites, directly in the paintComponent method.
Don't forget to call your super.paintCompmonent(g) within your paintComponent(Graphics g) method override.
Edit
A BufferedImage solution could look like,....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); //do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
paintGame(g2d);
// Toolkit.getDefaultToolkit().sync();
// g2d.dispose();
// g.dispose();
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
mainImage = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = mainImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
}
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Edit 2
Or with a SwingWorker background thread....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); // do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
paintGame(g2d);
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
imgWorker.addPropertyChangeListener(new ImgWorkerListener());
imgWorker.execute();
}
private class ImgWorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
mainImage = imgWorker.get();
// repaint() here if you don't have a game loop running
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
SwingWorker<BufferedImage, Void> imgWorker = new SwingWorker<BufferedImage, Void>() {
#Override
protected BufferedImage doInBackground() throws Exception {
BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
return img;
}
};
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
it's a bit uneconomic to create a new Font each time paint() is called (which happens a lot), you could move that to your constructor.
and the font should be changed to some orthodox fonts (Arial,Calibri etc)

Having trouble with dynamically updating a BufferedImage

I'm trying to render a dynamically changing image on a JPanel. I have tried many things and I simply do not get how to do it or what I'm doing wrong and I'm at the point of going insane. I'm new to swing and this is a small but essential part of my program which enables me to see what I'm doing.
The simple requirement is the picture rendered initially in the JPanel in the code mentioned below should update at each tick with random colors. I cannot get the image to update. Instead I get another square appearing in the middle of the image I'm trying to update and that small square dynamically changes. I do not know what I'm doing wrong. Please let me know how to rectify the code below so I could get the whole image to update.
Thank you.
The code is as follows
(MainTest.java)
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
public class MainTest extends JFrame {
static ImageEditor img ;
JPanel panel;
Timer to;
public MainTest()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(265, 329);
getContentPane().setLayout(null);
img = new ImageEditor();
panel = new ImageEditor();
panel.setBounds(10, 11, 152, 151);
panel.add(img);
getContentPane().add(panel);
JButton btnIterate = new JButton("Iterate");
btnIterate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ThirdClass t = new ThirdClass(img);
to = new Timer(10,t);
to.start();
}
});
btnIterate.setBounds(10, 230, 89, 23);
getContentPane().add(btnIterate);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
MainTest frame = new MainTest();
//frame.getContentPane().add(imgx);
frame.setVisible(true);
}
});
}
}
(ImageEditor.java)
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
#SuppressWarnings("serial")
public class ImageEditor extends JPanel {
private static BufferedImage img = new BufferedImage(100, 100, 1);
public ImageEditor() {
render();
}
public void paintComponent(Graphics g) {
if (img == null)
super.paintComponents(g);
else
g.drawImage(img, 0, 0, this);
}
public void render() {
float cellWidth = 10;
float cellHeight = 10;
int imgW = img.getWidth();
int imgH = img.getHeight();
float r, g, b;
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.black);
g2.clearRect(0,0,imgW,imgH);
for (int x=0; x<100; x++) {
for (int y=0; y<100; y++) {
r = (float)Math.random();
g = (float)Math.random();
b = (float)Math.random();
g2.setColor(new Color(r,g,b));
g2.fillRect((int)(x*cellWidth), (int)(y*cellHeight),
(int)cellWidth+1, (int)cellHeight+1);
}
}
g2.setColor(Color.black);
g2.dispose();
repaint();
}
public BufferedImage getImage() {
if (img == null)
img = (BufferedImage)createImage(100, 100);
return img;
}
public void setImage(BufferedImage bimg) {
img = bimg;
}
}
(ThirdClass.java)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ThirdClass implements ActionListener {
static ImageEditor mock;
public ThirdClass(ImageEditor img)
{
mock = img;
Train();
}
public void Train()
{
mock.render();
}
#Override
public void actionPerformed(ActionEvent arg0) {
Train();
}
}
From the code:
img = new ImageEditor();
panel = new ImageEditor();
panel.setBounds(10, 11, 152, 151);
panel.add(img);
getContentPane().add(panel);
You are defining img as an ImageEditor, but you probably meant for it to be a BufferedImage. You are then adding it to panel, which is another ImageEditor - but it is being added through the superclass method JPanel.add, when you probably meant to use the method you wrote, ImageEditor.setImage().
EDIT: To summarize:
The tiny block of updating pixels you described is the BufferedImage (img.img), inside of your ImageEditor img, which is in turn inside of the ImageEditor panel, which is itself inside the applet's content pane.
replace static ImageEditor img in the MainTest class with BufferedImage img
replace img = new ImageEditor in MainTest's no-args constructor with img = new BufferedImage()
replace panel.add(img) in MainTest's no-args constructor with panel.setImage(img)
replace static ImageEditor mock in the ThirdClass class with BufferedImage mock
replace the ImageEditor img argument in ThirdClass's constructor with BufferedImage img
replace any other stuff involving img to correctly handle it as a BufferedImage
One other thing, although this problem isn't itself the cause of any program malfunction, you should rename the Train() method in ThirdClass to something like train() so it matches proper java style.
After my initial post of the above question I have gone back to the basics and managed to answer my own question.
I am inserting the complete code below so another user having the same problem would not have to go through the same process over again.
My mistake was very trivial. However for people starting swing I think this might be helpful
(MainTest.java)
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class MainTest extends JFrame {
ImageEditor img;
JPanel panel;
Timer t;
public MainTest()
{
setSize(600,600);
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(null);
img = new ImageEditor();
panel = img;
panel.setBounds(0, 0, 510, 510);
getContentPane().add(panel);
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
test();
}
});
btnStart.setBounds(0, 528, 89, 23);
getContentPane().add(btnStart);
}
private void test() {
Train tx = new Train(img);
t = new Timer(100, tx);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
MainTest frame = new MainTest();
frame.setVisible(true);
}
});
}
}
(ImageEditor.java)
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
#SuppressWarnings("serial")
public class ImageEditor extends JPanel {
private static BufferedImage img = new BufferedImage(500, 500, 1);
public ImageEditor() {
setLayout(null);
}
public void paintComponent(Graphics g) {
if (img == null)
super.paintComponents(g);
else
g.drawImage(img, 0, 0, this);
}
public void render() {
float cellWidth = 10;
float cellHeight = 10;
int imgW = img.getWidth();
int imgH = img.getHeight();
float r, g, b;
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.black);
g2.clearRect(0,0,imgW,imgH);
for (int x=0; x<100; x++) {
for (int y=0; y<100; y++) {
r = (float)Math.random();
g = (float)Math.random();
b = (float)Math.random();
g2.setColor(new Color(r,g,b));
g2.fillRect((int)(x*cellWidth), (int)(y*cellHeight),
(int)cellWidth+1, (int)cellHeight+1);
}
}
g2.setColor(Color.black);
g2.dispose();
repaint();
}
public BufferedImage getImage() {
if (img == null)
img = (BufferedImage)createImage(500, 500);
return img;
}
public void setImage(BufferedImage bimg) {
img = bimg;
}
}
(Train.java this class was named ThirdClass.java in my question)
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Train implements ActionListener {
ImageEditor temp;
Train(ImageEditor img)
{
temp = img;
}
public void train()
{
temp.render();
}
#Override
public void actionPerformed(ActionEvent e) {
train();
}
}
Thank you for all who commented and answered my question.

Drawn image inside panel seems to have wrong x,y offset

So, I have a JFrame with a menu, a toolbar and panel. I load images inside the panel but for some strange reason (to me at least) they are not correctly displayed in the panel. Sometimes they start under the toolbar, sometimes above. Furthermore the image is cut on bottom. The code is a cleaned example from the full one that can be compiled and tested. Thanks in advance.
Class of containing frame:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipInputStream;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
public class SSCE extends JFrame {
private JComicPanel panel;
private JToolBar toolbar;
private JButton buttonZoom;
private JButton buttonPrev;
private JButton buttonNext;
private JMenuBar menuBar;
private Dimension dim;
private BufferedImage img;
private int currentPage;
private JFrame parentFrame;
public SSCE(){
super("JComic");
BorderLayout layout = new BorderLayout();
setLayout(layout);
dim = Toolkit.getDefaultToolkit().getScreenSize();
setSize((int)(dim.width /2.5),dim.height);
this.setPreferredSize(new Dimension((int) (dim.width /2.5),dim.height));
createToolbar();
createPanel();
add(toolbar,BorderLayout.NORTH);
add(panel,BorderLayout.CENTER);
createMenu();
add(menuBar);
setJMenuBar(menuBar);
panel.setVisible(true);
img = null;
pack();
parentFrame = this;
}
private void createPanel(){
Border raisedbevel, loweredbevel;
raisedbevel = BorderFactory.createRaisedBevelBorder();
loweredbevel = BorderFactory.createLoweredBevelBorder();
panel = new JComicPanel(img);
panel.setBorder(BorderFactory.createCompoundBorder(raisedbevel,loweredbevel));
}
private void createToolbar(){
toolbar = new JToolBar();
toolbar.setPreferredSize(new Dimension(dim.width,45));
toolbar.setFloatable(false);
buttonZoom = new JButton("+");
toolbar.add(buttonZoom);
buttonPrev = new JButton("<-");
toolbar.add(buttonPrev);
buttonNext = new JButton("->");
toolbar.add(buttonNext);
toolbar.setBackground(Color.RED);
}
private void createMenu(){
JMenu menuFile,menuJComic;
JMenuItem fileOpen;
JMenuItem quitJComic,aboutJComic;
menuBar = new JMenuBar();
menuJComic = new JMenu("JComic");
aboutJComic = new JMenuItem("About JComic...");
menuJComic.add(aboutJComic);
quitJComic = new JMenuItem("Quit");
quitJComic.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
);
menuJComic.add(quitJComic);
menuBar.add(menuJComic);
menuFile = new JMenu("File");
fileOpen = new JMenuItem("Open...");
fileOpen.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e) {
try {
img = ImageIO.read(new File("superman.jpg"));
currentPage = 1;
int offset = menuBar.getHeight() + toolbar.getHeight();
panel.setImage(img,parentFrame,offset);
}
catch (IOException e1) {
System.out.println(e1.getMessage());
}
}
}
);
menuFile.add(fileOpen);
menuBar.add(menuFile);
}
/**
* #param args
*/
#SuppressWarnings("deprecation")
public static void main(String[] args) {
// TODO Auto-generated method stub
SSCE f = new SSCE();
f.show();
}
}
Class of panel
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class JComicPanel extends JPanel{
private BufferedImage img;
private int offset;
private final float scaling = 0.5f;
public JComicPanel(BufferedImage img){
super();
this.img = img;
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e)
{
repaint();
}
});
}
public void setImage(BufferedImage img,JFrame parentFrame,int offset){
try{
int w = img.getWidth();
int h = img.getHeight();
int newW = (int)(w * scaling);
int newH = (int)(h * scaling);
BufferedImage dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
this.img = img;
System.out.printf("dim %d x %d",newW,newH);
this.setSize(new Dimension(newW,newH+offset));
parentFrame.pack();
}
catch(Exception e){
}
}
public Dimension getPreferredSize(){
return new Dimension(img.getWidth(),img.getHeight());
}
public void paintComponent(Graphics g){
// Draw our Image object.
super.paintComponent(g);
g.drawImage(img,0,0,getSize().width,getSize().height, this); // at location 50,10
System.out.println("painting 2");
}
}
Image superman.jpg can be found here http://i50.tinypic.com/2yxnc3n.jpg. As you can see the image is below the toolbar, but in my full code it goes also above.
Let's start here...
public void setImage(BufferedImage img,JFrame parentFrame,int offset){
try{
// You're scaling the incoming image, which means you no longer
// have a reference to the original image should you want to
// change that scale...
// You're previous code...
// Don't do this. The parent container's layout manager will simple
// override it, so it's useless...
this.setSize(newW,newH);
repaint();
// This is a bad idea (personally)...
parentFrame.setSize(newW,newH+offset);
} catch(Exception e){
}
}
Calling setSize in this way will temporarily allow the component to assume the size you have set. If you were to call invalidate() after it, the component would actually be re-sized back to meet the requirements of the layout manager.
The larger problem is the fact that you are setting the parent frame's size, but you have no idea of the frame's layout requirements with regards to it's other components, such as the tool bar, menu bar and frame (for example)
This is drawing the image without consideration to the ratio of the original image
g.drawImage(img,0,0,getSize().width,getSize().height, this);
As it has being suggested, after scaling the image, it might be easier to simply set the image as the icon of a JLabel which has been added to the image pane using a BorderLayout
You're assuming that the size of the panel is correct, but it won't be as the panel's layout manager will take over.
This is redundant as Swing will automatically repaint the component when it's resized.
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e)
{
repaint();
}
});
You're best bet is to either drop the image pane into a scroll pane and or rescale the image to fit the size of the pane dynamically.
For example...
Scalable Page
public class ComicPage {
public static void main(String[] args) {
new ComicPage();
}
public ComicPage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
try {
BufferedImage page = ImageIO.read(getClass().getResource("/1346.gif"));
ComicPagePane comicPagePane = new ComicPagePane();
comicPagePane.setComicPage(page);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(comicPagePane);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception exp) {
exp.printStackTrace();
}
}
});
}
public class ComicPagePane extends JPanel {
private BufferedImage comicPage;
private Image scaledInstance;
public void setComicPage(BufferedImage page) {
if (page != comicPage) {
comicPage = page;
scaledInstance = null;
repaint();
}
}
#Override
public void invalidate() {
scaledInstance = null;
super.invalidate();
}
public BufferedImage getComicPage() {
return comicPage;
}
public double getScaleFactor(int iMasterSize, int iTargetSize) {
return (double) iTargetSize / (double) iMasterSize;
}
public double getScaleFactorToFit(BufferedImage img) {
double dScale = 1d;
double dScaleWidth = getScaleFactor(img.getWidth(), getWidth());
double dScaleHeight = getScaleFactor(img.getHeight(), getHeight());
dScale = Math.min(dScaleHeight, dScaleWidth);
return dScale;
}
protected Image getScaledInstance(BufferedImage master) {
if (scaledInstance == null) {
double scaleFactor = getScaleFactorToFit(master);
System.out.println("scaleFactor = " + NumberFormat.getNumberInstance().format(scaleFactor));
// This is not the best scaling alorithm
scaledInstance = master.getScaledInstance(
(int) Math.round(master.getWidth() * scaleFactor),
(int) Math.round(master.getHeight() * scaleFactor), Image.SCALE_SMOOTH);
}
return scaledInstance;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage comicPage = getComicPage();
if (comicPage != null) {
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
// Normally, I would put this into a background worker as this
// operation can be expensive....
Image scaledInstance = getScaledInstance(comicPage);
int x = (width - scaledInstance.getWidth(this)) / 2;
int y = (height - scaledInstance.getHeight(this)) / 2;
g2d.drawImage(scaledInstance, x, y, this);
g2d.dispose();
}
}
}
}
Scrollable Page
public class ScrollableComicPage {
public static void main(String[] args) {
new ScrollableComicPage();
}
public ScrollableComicPage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
try {
BufferedImage page = ImageIO.read(getClass().getResource("/1346.gif"));
ComicPagePage comicPagePane = new ComicPagePage();
comicPagePane.setComicPage(page);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(comicPagePane));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception exp) {
exp.printStackTrace();
}
}
});
}
public class ComicPagePage extends JPanel {
private BufferedImage comicPage;
#Override
public Dimension getPreferredSize() {
return comicPage != null ? new Dimension(comicPage.getWidth(), comicPage.getHeight()) : new Dimension(0, 0);
}
public void setComicPage(BufferedImage page) {
if (page != comicPage) {
comicPage = page;
invalidate();
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (comicPage != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(comicPage, 0, 0, this);
g2d.dispose();
}
}
}
}
You can have a read through Java: maintaining aspect ratio of JPanel background image for more information on scaling techniques.
The technical reason is that you are temporarily adding the menuBar to the center of the contentPane, that is the same logical location as the previously added panel:
add(panel, BorderLayout.CENTER);
// following line is wrong - must be removed!!!
add(menuBar); // no constraint == BorderLayout.CENTER
setJMenuBar(menuBar);
Doing so pushes the panel out off the control of the LayoutManager, but not out of the panel - the net effect is that it has no constraint.
That's not special to being a menuBar (which needs to be added to the layeredPane of the rootPane, not the contentPane - that's why it has its own specialized method setJMenuBar), the same mess would happen with any other arbitrary component at the center.
Apart from that, I would recommend you cleaning up your code:
remove all setXXSize (some reasons)
decide whether the frame should come up at its preferred (using pack) or an arbitrary fixed size (using setSize). The former is the correct thingy to do in most cases, the latter has its use-cases - but doing both doesn't make sense
components are visible by default

How to draw an image over another image?

I have a Java project that's about traffic network simulation in a random city, I've managed to figure out a way to implement this project, so I divided each intersection into a section which is basically an extended JPanel class (named Carrefour)...everything works well until I got stuck with how to draw vehicles and make them pass through roads.
So my problem is how to draw an image (vehicle image) over an another image (road)?
Another approach that does not require extending components.
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Random;
import java.net.URL;
import javax.imageio.ImageIO;
public class ImageOnImage {
ImageOnImage(final BufferedImage bg, BufferedImage fg) {
final BufferedImage scaled = new BufferedImage(
fg.getWidth()/2,fg.getHeight()/2,BufferedImage.TYPE_INT_RGB);
Graphics g = scaled.getGraphics();
g.drawImage(fg,0,0,scaled.getWidth(),scaled.getHeight(),null);
g.dispose();
final int xMax = bg.getWidth()-scaled.getWidth();
final int yMax = bg.getHeight()-scaled.getHeight();
final JLabel label = new JLabel(new ImageIcon(bg));
ActionListener listener = new ActionListener() {
Random random = new Random();
public void actionPerformed(ActionEvent ae) {
Graphics g = bg.getGraphics();
int x = random.nextInt(xMax);
int y = random.nextInt(yMax);
g.drawImage( scaled, x, y, null );
g.dispose();
label.repaint();
}
};
Timer timer = new Timer(1200, listener);
timer.start();
JOptionPane.showMessageDialog(null, label);
}
public static void main(String[] args) throws Exception {
URL url1 = new URL("http://i.stack.imgur.com/lxthA.jpg");
final BufferedImage image1 = ImageIO.read(url1);
URL url2 = new URL("http://i.stack.imgur.com/OVOg3.jpg");
final BufferedImage image2 = ImageIO.read(url2);
//Create the frame on the event dispatching thread
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new ImageOnImage(image2, image1);
}
});
}
}
If this is Swing, then draw the background image in a BufferedImage. Display this BufferedImage in a JComponent's (such as a JPanel's) paintComponent method using Graphic's drawImage(...) method, and then draw the changing images over this in the same paintComponent method. Don't forget to call the super.paintComponent(...) method first though.
Please note that this question has been asked quite a bit here and elsewhere, and as you would expect, there are lots of examples of this sort of thing that you can find here with a bit of searching.
Edit
You ask:
Thanks, this is how I draw the firt image (road)
Again, you would create a BufferedImage for this, likely by using ImageIO.read(...). Then you'd draw this in your JPanel's paintComponent(Graphics g) method override using g.drawImage(...).
For example...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class IntersectionImagePanel extends JPanel {
private static final String INTERSECTION_LINK = "http://www.weinerlawoffice.com/" +
"accident-diagram.jpg";
private BufferedImage intersectionImage;
public IntersectionImagePanel() {
URL imageUrl;
try {
imageUrl = new URL(INTERSECTION_LINK);
intersectionImage = ImageIO.read(imageUrl );
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (intersectionImage != null) {
g.drawImage(intersectionImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
if (intersectionImage != null) {
int width = intersectionImage.getWidth();
int height = intersectionImage.getHeight();
return new Dimension(width , height );
}
return super.getPreferredSize();
}
private static void createAndShowGui() {
IntersectionImagePanel mainPanel = new IntersectionImagePanel();
JFrame frame = new JFrame("IntersectionImage");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories

Resources