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:
Related
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.
Trying to draw an image and I have no idea why it's not appearing on the screen. Image is loaded fine.
System.out.printf("%nPlayer_1.img_player1 is: "+Player_1.img_player1); says that the image is loaded correctly (correct image w/h etc).
Have tried all manner of image observers, drawing the image from different classes (namely Player_1.drawSquare and MyPanel.painComponent)
There are regular repaint() requests coming in from the Control class, but I do not believe this is preventing the drawing.
No error's are thrown.
player_1.gif is located within the game_2 package, I have tried running the code with it in the src and root folder.
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
public class Main{
public static void main(String[] args) {
GUI.main(args);
}
}
class GUI {
static JFrame f = new JFrame("Swing Paint Demo");
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.printf("%nCreated GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.setSize(640,640);
f.setVisible(true);
}
}
class MyPanel extends JPanel {
public MyPanel() {
//setBorder(BorderFactory.createLineBorder(Color.black));
}
public Dimension getPreferredSize() {
return new Dimension(640,640);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.printf("%nPaincomponent on GUI");
Player_1.paintSquare(g);
System.out.printf("%nPlayer_1.img_player1 is: "+Player_1.img_player1);
}
}
class Player_1{
public static Image img_player1;
public int int_x = 0;
public int int_y = 1;
public int int_w = 1;
public int int_h = 1;
public static void paintSquare(Graphics g){
if (img_player1 == null)
img_player1 = IOControl.getImage("player_1.gif");
g.drawImage(img_player1, 32, 32, 32, 32, GUI.f);
}
}
class IOControl {
public static void main(String[] args) {
}
static BufferedImage getImage(String path)
{
BufferedImage tempImage = null;
try
{
URL imageURL = Main.class.getResource(path);
tempImage = toBufferedImage(Toolkit.getDefaultToolkit().getImage(imageURL));
}
catch(Exception e)
{
System.out.printf("%nAn error occured -" + e.getMessage());
}
System.out.printf("%n"+path);
System.out.printf("%nIOControl.path");
System.out.printf("%n"+tempImage);
System.out.printf("%nIOControl.tempImage");
return tempImage;
}
public static BufferedImage toBufferedImage(Image img)
{
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
// Create a buffered image with transparency
BufferedImage bimage = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
}
Don't call the main method. It is meant for the JVM to call as the starting point of your program. Also, you should only have one main method, in whichever class is the launching class.
Don't create the image in the paintXxx method. You should create in the constructor.
All the other faulty points I mentioned in my comments in the original post.
It looks like your main problem is in the getImage method. I simplified it for you and it works (given I fixed the other points I mentioned above).
public static BufferedImage getImage(String path) {
BufferedImage img = null;
try {
img = ImageIO.read(GUI.class.getResource(path));
} catch (IOException ex) {
ex.printStackTrace();
}
return img;
}
Here's the full running code. Note: you had the image location correct, with it in the same package as the Main class.
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GUI().createAndShowGUI();
}
});
}
}
class GUI {
JFrame f = new JFrame("Swing Paint Demo");
public void createAndShowGUI() {
System.out.printf("%nCreated GUI on EDT? "
+ SwingUtilities.isEventDispatchThread());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.setSize(640, 640);
f.setVisible(true);
}
}
class MyPanel extends JPanel {
Player_1 player1;
public MyPanel() {
player1 = new Player_1(MyPanel.this);
}
public Dimension getPreferredSize() {
return new Dimension(640, 640);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.printf("%nPaincomponent on GUI");
player1.paintSquare(g);
}
}
class Player_1 {
public Image img_player1;
public int int_x = 0;
public int int_y = 1;
public int int_w = 1;
public int int_h = 1;
JPanel panel;
public Player_1(JPanel panel) {
this.panel = panel;
img_player1 = IOControl.getImage("player_1.png");
}
public void paintSquare(Graphics g) {
g.drawImage(img_player1, 32, 32, 32, 32, panel);
}
}
class IOControl {
public static BufferedImage getImage(String path) {
BufferedImage img = null;
try {
img = ImageIO.read(GUI.class.getResource(path));
} catch (IOException ex) {
ex.printStackTrace();
}
return img;
}
}
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.
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
I can't figure out why this code wont work. Any ideas?
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.net.URL;
import javax.swing.JPanel;
public class ImageTool extends JPanel {
private static final long serialVersionUID = 1L;
private static Image image;
public ImageTool(URL url) {
image = Toolkit.getDefaultToolkit().getImage(url);
rightSize();
}
private void rightSize() {
int width = image.getWidth(this);
int height = image.getHeight(this);
if (width == -1 || height == -1)
return;
addNotify();
System.out.println("Image width: "+width);
System.out.println("Image height"+height);
}
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
if ((infoflags & ImageObserver.ERROR) != 0) {
System.out.println("Error loading image!");
System.exit(-1);
}
if ((infoflags & ImageObserver.WIDTH) != 0
&& (infoflags & ImageObserver.HEIGHT) != 0) {
rightSize();
System.out.println("1");
}
if ((infoflags & ImageObserver.SOMEBITS) != 0)
repaint();
if ((infoflags & ImageObserver.ALLBITS) != 0) {
System.out.println("2");
rightSize();
repaint();
return false;
}
return true;
}
public void update(Graphics g) {
paint(g);
}
public void paintComponent(Graphics g) {
Insets insets = getInsets();
g.drawImage(image, insets.left, insets.top, this);
}
public static void main(String[] args) throws Exception {
String url = "http://www.java2s.com/style/logo.png";
new ImageTool(new URL(url));
}
}
In your code you're missing a JFrame or JDialog to contain your JPanel in. Here's an example that I believe does what you're asking for. It loads the same image into a visible window and outputs the dimensions to the console.
public class ImageTool extends JPanel {
public ImageTool(URL url) {
ImageIcon icon = new ImageIcon(url);
JLabel label = new JLabel(icon, JLabel.CENTER);
add(label);
System.out.println("Image width: " + icon.getIconWidth());
System.out.println("Image height: " + icon.getIconHeight());
}
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://www.java2s.com/style/logo.png");
JPanel panel = new ImageTool(url);
JFrame frame = new JFrame();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
I'm not sure what you are trying to do either, but your code looks like an old AWT example and should not be used for Swing.
there is no need to override update()
paintComponent() should invoke super.paintComponent()
Read the Swing tutorial on How to Use Icons for example code that uses images on labels.