I've googled it and found the code:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ImageTest {
public static void main(String[] args) {
ImagePanel panel = new ImagePanel(new ImageIcon("background.png").getImage());
JFrame frame = new JFrame();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
class ImagePanel extends JPanel {
private Image img;
public ImagePanel(String img) {
this(new ImageIcon(img).getImage());
}
public ImagePanel(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
This worked for me when I create the ImageTest.java file, and put the background.png in the same folder.
But when I paste the same code in Eclipse IDE (in default package) along with the image, then it doesn't set the image as background. Actually it doesn't find the images and this is the reason.
I've tried keeping them both in same package pack; Even then it doesn't find the image, so no output.
I've tried to open the workspace > project folder > war > WEB-INF > classes
Then compiled the program from cmd. Still it doesn't show.
I don't know what the problem is. Anyone knowing any solution is most welcomed.
Thanks in Advance.
Setting background directly onto the frame is also welcomed...
I've done all this using code, but when this will be working then I'll be shifting to windows builder for GUI. So will the help from you will work in window builder also?
..new ImageIcon("background.png")..
This is a stupid (but common) way to load an image that provides no feed-back1.
You will most likely find that the background.png is no longer a file but now part of a Jar. In that case, the way to access it is using an URL obtained from Class.getResource().
The smart way to load images is using ImageIO, which throws helpful & informative exceptions if the image cannot be loaded.
This is not really answering your question but since an answer has been accepted I figured, what the hell, you might want to take a peek.
This class can be used it like any JPanel. It will slap an image on the background of the panel and will resize the image as the frame is resized.
public class JPanelWithBackground extends JPanel {
Image imageOrg = null;
Image image = null;
{
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
int w = JPanelWithBackground.this.getWidth();
int h = JPanelWithBackground.this.getHeight();
image = w>0&&h>0?imageOrg.getScaledInstance(w,h,
java.awt.Image.SCALE_SMOOTH):imageOrg;
JPanelWithBackground.this.repaint();
}
});
}
public JPanelWithBackground(Image i) {
imageOrg=i;
image=i;
setOpaque(false);
}
public void paint(Graphics g) {
if (image!=null) g.drawImage(image, 0, 0, null);
super.paint(g);
}
}
Usage Example:
Image image = your image
JFrame f = new JFrame("");
JPanel j = new JPanelWithBackground(image);
j.setLayout(new FlowLayout());
j.add(new JButton("YoYo"));
j.add(new JButton("MaMa"));
f.add(j);
f.setVisible(true);
Related
I need help to add an image to the separate JFrame, but I can't seem to get it to work. Like I want the image to open in a separate frame like when I run this code it opens a blank JFrame. d help to add an image to the separate JFrame, but I can't seem to get it to work. Like I want the image to open in a separate frame like when I run this code it opens a blank JFrame.
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import javax.swing.JFrame;
class PPJJ extends JFrame implements ActionListener, KeyListener
{
public void paint(Graphics g) {
Toolkit t=Toolkit.getDefaultToolkit();
Image i=t.getImage("tenor.gif");
g.drawImage(i, 120,100,this);
}
public static void main(String[] args)
{
JFrame frame = new JFrame("VOLUNTEER FOR THING");
PPJJ obj = new PPJJ();
JPanel panel = new JPanel();
JLabel lname = new JLabel("Enter your name here");
JTextField tname = new JTextField(21);
JButton btn = new JButton("Click");
btn.addActionListener(obj);
tname.addKeyListener(obj);
panel.add(lname);
panel.add(tname);
panel.add(btn);
frame.add(panel);
frame.setSize(300, 130);
frame.show();
frame.setLocationRelativeTo(null);
PPJJ m = new PPJJ();
JFrame f =new JFrame();
//f.add(m);
f.setSize(500,500);
f.setVisible(true);
frame.add(new JLabel(new ImageIcon("volunteer.jpeg")));
}
public void actionPerformed(ActionEvent e)
{
String s = e.getActionCommand();
if(s.equals("Click here")){
JOptionPane.showMessageDialog(null , "THANKS FOR SIGNING UP");
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_ENTER){
JOptionPane.showMessageDialog(null , "THANKS FOR SIGNING UP");
}
}
#Override
public void keyReleased(KeyEvent arg) {}
#Override
public void keyTyped(KeyEvent arg) {}
}
Oh, animated GIFs 😓.
Image handling isn't simple in most cases, but animated GIFs are whole other level of pain ... I mean fun.
Normally, I prefer to use ImageIO.read, but ImageIO returns a BufferedImage and it's not (easily) possible to then render animated GIFs through it.
The "easy" route of displaying animated GIFs is by using Image or ImageIcon.
The first step is get your image "embedded" within your application context (assuming that you're not allowing the user to select the image). How this is done will depend on your IDE and build system (Eclipse and Netbeans allow you to simply include them in the src folder, when you're not using Maven).
Next, you want to use Class#getResource to obtain a URL reference to the embedded resource. In this case, you can use ImageIO.read, ImageIcon(URL) or Toolkit#getImage(URL) to load the image. But, as I've said, ImageIO.read isn't going to help you.
Next, you need a component which can render the image, lucky for us, Swing can do this pretty much auto magically for use, all we need to do is make sure the component is passed as the ImageObserver reference, for example...
public class BackgroundPane extends JPanel {
private Image image;
public BackgroundPane(Image image) {
this.image = image;
}
#Override
public Dimension getPreferredSize() {
Image image = getBackgroundImage();
return image == null ? super.getPreferredSize() : new Dimension(image.getWidth(this), image.getHeight(this));
}
public Image getBackgroundImage() {
return image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Image image = getBackgroundImage();
if (image == null) {
return;
}
int x = (getWidth() - image.getWidth(this)) / 2;
int y = (getHeight() - image.getHeight(this)) / 2;
g.drawImage(image, x, y, this);
}
}
Also, note, JLabel supports animated GIFs via it's icon property as well, but look at How to set a background picture in JPanel for reasons why you shouldn't use a JLabel as a background container.
Now, all we need to do is load the image, pass it to the background, add what ever content we need to the component and show it, easy, or at least it should be. ImageIcon and Toolkit#getImage both off load the reading of the image to a background thread, so inspecting the images dimensions before the image is loaded will return 0x0 😓, so, we need to wait for it to load (this is why I prefer ImageIO.read as it won't return until the image is loaded or an error occurs).
Something like...
Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/images/kitty.gif"));
BackgroundPane backgroundPane = new BackgroundPane(image);
// Did I mention I had this workflow, but ImageIO doesn't
// support animated images, without a lot of work
MediaTracker mt = new MediaTracker(backgroundPane);
mt.addImage(image, 0);
mt.waitForAll();
// The image is now loaded, hooray for us
Runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/images/kitty.gif"));
BackgroundPane backgroundPane = new BackgroundPane(image);
// Did I mention I had this workflow, but ImageIO doesn't
// support animated images, without a lot of work
MediaTracker mt = new MediaTracker(backgroundPane);
mt.addImage(image, 0);
mt.waitForAll();
backgroundPane.setLayout(new GridBagLayout());
JLabel label = new JLabel("All your kitty is belong to us");
label.setForeground(Color.WHITE);
backgroundPane.add(label);
JFrame frame = new JFrame();
frame.add(backgroundPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class BackgroundPane extends JPanel {
private Image image;
public BackgroundPane(Image image) {
this.image = image;
}
#Override
public Dimension getPreferredSize() {
Image image = getBackgroundImage();
return image == null ? super.getPreferredSize() : new Dimension(image.getWidth(this), image.getHeight(this));
}
public Image getBackgroundImage() {
return image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Image image = getBackgroundImage();
if (image == null) {
return;
}
int x = (getWidth() - image.getWidth(this)) / 2;
int y = (getHeight() - image.getHeight(this)) / 2;
g.drawImage(image, x, y, this);
}
}
}
Please note...
If you're not using an animated GIF, then you can just use ImageIO.read instead of Toolkit#getImage and you won't need to wait (as ImageIO.read works in the current thread), in which case the code would look more like...
try {
BackgroundPane backgroundPane = new BackgroundPane(ImageIO.read(getClass().getResource("/images/kitty.gif")));
backgroundPane.setLayout(new GridBagLayout());
JLabel label = new JLabel("All your kitty is belong to us");
label.setForeground(Color.WHITE);
backgroundPane.add(label);
JFrame frame = new JFrame();
frame.add(backgroundPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
(the BackgroundPane code doesn't change)
I have this class which should draw an image.
package ro.adlabs.imnuriAZSMR.UIClases;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class JImage extends JPanel {
private BufferedImage image;
private int height;
private int width;
public JImage(String imagePath,int height,int width) {
try {
image = ImageIO.read(getClass().getResourceAsStream(imagePath));
} catch (IOException ex) {
ex.printStackTrace();
}
this.width = width;
this.height = height;
}
public JImage(String imagePath,int size){
new JImage(imagePath,size,size);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, width, height, this);
}
}
And this Class which show an About Dialog:
package ro.adlabs.imnuriAZSMR.UIClases;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AboutDialog extends JDialog {
public AboutDialog() {
setTitle("About");
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
JLabel name = new JLabel("<html><div style='text-align: center;'>Aceasta aplicatie e dezvoltata sub Termenii si Conditiile ADLabs.</div></html>");
JLabel copyright = new JLabel("© ADLabs - www.adlabs.ro");
name.setAlignmentX(0.5f);
copyright.setAlignmentX(0.5f);
add(name);
add(new JImage("../ico/appicon_200x200.png",50));
add(copyright);
JButton close = new JButton("Close");
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
dispose();
}
});
close.setAlignmentX(0.5f);
add(close);
setModalityType(ModalityType.APPLICATION_MODAL);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setSize(300, 200);
}
}
I add to the dialog the Image which is the app logo. First time when I created the JImage class it worked, it drawn the picture. Then I added the method:
setSize(width+20,height+20);
to the Jpanel in the JImage class and when I ran the program again it didn't draw the image. Then anything I did it didn't solve this wierd bug.
Anyone has any ideea? What am I doing wrong?
Graphics doesn't draw image in java
You are using a BoxLayout. A BoxLayout will use the preferred size information of the panel when doing the layout. Your preferred size is (0, 0) so there is nothing to paint.
You need to override the getPreferredSize() method of the panel when you do custom painting to return the size of your component so layout managers can do their job.
However, as already mention there is no need to create a custom class as you can just use a JLabel to display an image. The only time you do custom painting is when you need to somehow modify the image when it is painted.
You are using a resource path, not a file system path. Such a path may not contain .. and is either relative to the package directory of the class or absolute.
new JImage("../ico/appicon_200x200.png", 50)
should become something like:
new JImage("/ro/adlabs/imnuriAZSMR/ico/appicon_200x200.png", 50)
Also:
public JImage(String imagePath, int size){
new JImage(imagePath, size, size);
}
should be
public JImage(String imagePath, int size){
this(imagePath, size, size);
}
I am working on an assignment (GASP) and having issues with my image displaying. I am not looking for someone to complete my assignment for me but I desperately need some help figuring out why my code is not working properly. I have reviewed my Java Programming book as well as searched for the answers online to no avail so if someone could lead me in the right direction I would greatly appreciate it!!
Here is my displayImage code:
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DisplayImage extends JFrame {
public void DislayImage(){
add (new ImagePanel());
}
public static void main(String[] args) {
JFrame frame = new DisplayImage ();
frame.setTitle("Go Bearcats!");
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Assignment02 a = new Assignment02();
frame.add(a);
}
}
class ImagePanel extends JPanel {
public final static String LOC = "C:\\UCincinnatiLogo.jpg";
private ImageIcon imageIcon = new ImageIcon (LOC);
private Image image = imageIcon.getImage();
#Override /**Draw image on the panel*/
protected void paintComponent(Graphics g){
super.paintComponent(g);
if (image !=null)
g.drawImage(image, 200, 200, getWidth(), getHeight(), this);
}
}
You're adding a component right on top of your image panel. The JFrame uses borderLayout, so anything added to it as you're doing will cover anything added previously.
JFrame frame = new DisplayImage ();
frame.setTitle("Go Bearcats!");
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Assignment02 a = new Assignment02();
frame.add(a); // here you add something on top of your imagePanel
Instead, make the ImagePanel the JFrame's contentPane via setContentPane(...), and then add things to the JFrame/contentPane, but be sure that they're not opaque.
public class DisplayImage extends JFrame {
public void DislayImage(){
setContentPane(new ImagePanel());
}
and then,
Assignment02 a = new Assignment02();
a.setOpaque(false);
frame.add(a);
Note, as an aside, I rarely create any classes that extend JFrame, and instead create my JFrame when needed. Instead I'd create my ImagePane and then add components directly to it before adding all to a JFrame.
Also you don't show us the Assignment02 class, but it had better have non-opaque JPanels and components.
So I have my own custom JFrame, and in it I am trying to create an auto-resizing image to be contained in my JFrame's content JPanel, frameContent. My layout manager for the JPanel is MigLayout, so I figured I would create a child of JPanel again, called ImagePanel. Here is what my ImagePanel class ended up looking like:
class ImagePanel extends JPanel{
private static final long serialVersionUID = -5602032021645365870L;
private BufferedImage image;
public ImagePanel() {
try {
image = ImageIO.read(new File(getClass().getResource("../res/Title.png").toURI()));
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, getWidth(), getHeight(), null);
}
}
Now for some reason it doesn't seem like it's actually 'working'. When I am setting up my main JFrame's content, I call:
framecontent.add(new ImagePanel(), "pos 5% 5% 95% 45%");
It's not that it's not adding the component, as with this code I'm able to get the following screen:
Notice how it outlines the area against the gray background, meaning the paintComponent(g) method is being run, and the program also isn't outputting any errors, which is strange, so that means it is finding my image, just not placing it.
Here is what my file hierarchy looks like:
Project Folder >
src >
res >
Title.png (Picture I want to retrieve)
guiwork >
Working.class (Class that is running instructions/ main)
Got it all fixed up, here is the auto-resizing result:
Notice how it outlines the area against the gray background, meaning the paintComponent(g) method is being run, and the program also isn't outputting any errors, which is strange, so that means it is finding my image, just not placing it.
Not so as a null image will throw no errors. To prove this, test your image variable in the paintComponent method and you'll likely find that it is in fact null.
i.e., try this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("image is null: " + (image == null)); // TODO: Delete this
g.drawImage(image, getWidth(), getHeight(), null);
}
Solution: don't change your resource to a file, but instead use the resource as is, and make sure that you're looking for it in the correct location.
Edit
Oh chit, you're drawing your image beyond the bounds of your component:
g.drawImage(image, getWidth(), getHeight(), null);
try:
g.drawImage(image, 0, 0, null);
Edit 2
What if you try a simple test program, something like:
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
public class TestImage {
public TestImage() throws IOException {
String path = "/res/Title.png";
BufferedImage img = ImageIO.read(getClass().getResource(path));
ImageIcon icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, icon);
}
public static void main(String[] args) {
try {
new TestImage();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and be sure to place this in the same location as your current class. Does it run?
For those who might have trouble understanding HoverCraft's Answer:
Say you have a Panel in which you want to add an image that scales, the following code does that for you
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
public class MasterSlidePanel extends JPanel {
private ImageIcon imageIcon;
private JLabel image;
public MasterSlidePanel() {
super(new MigLayout("", "2% [] 2%", "2% [] 2%"));
}
#Override
protected void paintComponent(Graphics g) {
image.setIcon(new ImageIcon(imageIcon.getImage().getScaledInstance(image.getWidth(), image.getHeight(), Image.SCALE_SMOOTH)));
super.paintComponent(g);
}
public void setImage(SlidePanel panel) {
imageIcon = <Where you get the imageIcon>;
image = new JLabel();
image.setMinimumSize(new Dimension(10, 10));
image.setPreferredSize(new Dimension(10, 10));
this.add(image, "width 96%, height 96%");
}
}
We add 2 new members to the panel, image and imageIcon. The moment when the application needs to paint the panel, a scaled inscance of the imageIcon is loaded and given to image.
To prevent 0 height/width errors, we add a minimumsize to the JLabel.
Hope this helps.
Credits still go to HoverCraft Full Of Eels.
I am trying to display a large image inside a JFrame's contentpane. I would like to make the image or contentpane scrollable as the image is large. I tried to do it using Jscrollpane and add it into the contentpane but it didn't work. Did some searching for solution but end up failed to find one. Can someone guide me? My code are below
FinalEnvironment.java
package environment;
import java.awt.*;
import java.net.URL;
import javax.swing.*;
public class FinalEnvironment{
public FinalEnvironment(){
Image Eastlake;
URL EastlakeURL = null;
EastlakeURL = FinalEnvironment.class.getResource("/image1/eastlake_night.png");
Eastlake = Toolkit.getDefaultToolkit().getImage(EastlakeURL);
JFrame frame = new JFrame("UniCat World");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
JMenuBar yellowMenuBar = new JMenuBar();
Map map = new Map(800, 550, Eastlake);
yellowMenuBar.setOpaque(true);
yellowMenuBar.setBackground(Color.YELLOW);
yellowMenuBar.setPreferredSize(new Dimension(800, 50));
frame.setJMenuBar(yellowMenuBar);
JScrollPane scroller = new JScrollPane(map);
scroller.setAutoscrolls(true);
scroller.setPreferredSize(new Dimension(800, 550));
frame.getContentPane().add(scroller, BorderLayout.CENTER);
frame.setSize(800, 600);
frame.setVisible(true);
}
public static void main(String[] args){
FinalEnvironment fe = new FinalEnvironment();
}
}
Here is my map.java
package environment;
import java.awt.*;
import javax.swing.*;
public class Map extends JPanel{
private int width;
private int height;
private Image img;
public Map(int width, int height, Image img){
this.width = width;
this.height = height;
this.img = img;
}
protected void paintComponent(Graphics g)
{
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(img,0,0,2624,1696,null);
}
}
Lastly, I would like to place Jbuttons on top of this image. Should I call a Rectangle and place it on top the image in the contentpane which then I use Point to position my buttons or should I straight away use the image or the component itself to do it? I need the button to be able to synchronize with the image when it is scrolled instead of static in the contentpane.
Thanks
What I would do here:
1.Have a panel (canvas) which only responsibility is to paint a given image independent of the real image size in overridden method paintComponent()
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
2.Make sure the canvas preferred size equals to image real size.
3.Have a second panel which will serve as content pane of a frame.
4.In it you will set a JScrollPane as its centre.
5.In the scroll pane viewport will be the component from step 1.
6.Add your button to canvas panel from step 1. It will be scrolled together with the image.
7.Add the content pane, the panel from step 3, to a frame, and run the application.
EDIT:
Code sample with button added to canvas, which stays always in its place, independent of scroll position or frame size.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class ScrollImageTest extends JPanel {
private static final long serialVersionUID = 1L;
private BufferedImage image;
private JPanel canvas;
public ScrollImageTest() {
try {
this.image = ImageIO.read(new URL("http://interviewpenguin.com/wp-content/uploads/2011/06/java-programmers-brain.jpg"));
}catch(IOException ex) {
Logger.getLogger(ScrollImageTest.class.getName()).log(Level.SEVERE, null, ex);
}
this.canvas = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
canvas.add(new JButton("Currently I do nothing"));
canvas.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
JScrollPane sp = new JScrollPane(canvas);
setLayout(new BorderLayout());
add(sp, BorderLayout.CENTER);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JPanel p = new ScrollImageTest();
JFrame f = new JFrame();
f.setContentPane(p);
f.setSize(400, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
What if you use your dimensions to set the Map's preferred size. For instance, give Map this method:
// method in the Map class
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
This way the Map JPanel will take up the necessary room to show the entire image. Also, why does your drawImage method in the paintComponent method have the large magic numbers? Why not use the width and height there as well? Edit 1: or don't even specify the image size as Boro suggests in his answer (1+ to him).
Why is everybody reinventing the wheel??? There is no need for a custom panel to paint the image!!!
All you need to do is create a JLabel and add an ImageIcon to the label and you won't have a problem. The label will:
paint the image at (0, 0) at its original size (which is exactly what the custom code is doing).
determine the preferred size of the image based on the image size. Now scrolling will happen automatically.
Also there is rarely any reason to use the setPreferredSize() method since all components have a default preferred size. So you should not set the default size of the menu bar. The only time I set a preferred size would be on the JScrollPane. This will allow the frame to be packed at a reasonable size and then scrollbars will appear automatically based on the size of the image in the label.
In addition to other helpful answers, you might like studying this example that uses mouse gestures to scroll arbitrary content.