I was wondering how you would get the color of the inset of a JTabbedPane. I cannot seem to get this color. Every attempt I make I get 236,236,236 which is the outside frame color, where the inside frame color is about 10 darker, 227,227,227 (using the built in apple color meter).
I am setting the look and feel using UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
You can see this in an image that I found on the internet. http://pagesofinterest.net/wordpress/wp-content/uploads/2009/06/Quaqua-Maven-Netbeans.jpg Where the words "Panel's Title" is the area that I am getting the lighter color that is not useful to me. Inside the round corners is the darker color I am trying to obtain. I tried getting the color of the content pane to no avail.
Thanks for all your help!
**EDIT:**Added code! As you see, I am trying to get the color of the area inside the rounded corners(if your on a mac) not the color of the frame or the tabs that say "1" "2". I have attached a photo and I am trying to get the background color of the portion that says "Here" Thanks!
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
public class main {
JFrame frame;
Container c1 = new Container();
Container c2 = new Container();
JTabbedPane top = new JTabbedPane();
static main GUI;
public void createGUI(){
frame = new JFrame();
Container c = frame.getContentPane();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
top = new JTabbedPane(JTabbedPane.TOP);
top.setFocusTraversalKeysEnabled(false);
top.setFocusable(false);
top.addTab("1", c1);
top.addTab("2", c2);
frame.setSize(315,450);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(true);
c.add(top);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {}
GUI = new main();
GUI.createGUI();
}
}
EDIT: camickr, Here is a screenshot of the UIManager Defaults. Unfortunately none of there colors in the are the correct color that the inset is.
You might be able to use UIMangaer Defaults to find the color.
You can override paintComponent() to use a GradientPaint in the tab's background, as shown below. A few notes,
Let the content adopt the preferred size of it contents, as shown here.
Construct the GUI in the event dispatch thread.
Use conventional Java names.
Addendum: the elements are not always in the same spot, so I do not know what place to get the color.
It sounds like you want to match a color used internally by the TabbedPaneUI delegate. One approach would be as follows:
Render a BufferedImage of the component, as shown here.
Determine the coordinates of a Point in top relative to the top of c1.
Point p = SwingUtilities.convertPoint(c1, 0, -1, top);
Obtain the color using getRGB(), as shown here; use Zoom to verify the result.
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/a/16625260/230513 */
public class Main {
JFrame frame;
Container c1 = new GradientPanel();
Container c2 = new GradientPanel();
JTabbedPane top = new JTabbedPane();
private static class GradientPanel extends JPanel {
public GradientPanel() {
this.add(new JLabel("Here"));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
GradientPaint p = new GradientPaint(0, 0, Color.white,
getWidth(), getHeight(), Color.gray);
g2d.setPaint(p);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
public void createGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
top = new JTabbedPane(JTabbedPane.TOP);
top.addTab("1", c1);
top.addTab("2", c2);
frame.add(top);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main().createGUI();
}
});
}
}
Related
1. Need set 1024*768 the size of paintComponent Area.
2. Need set drawing orientation of line on (0, 0, 1366,1024) but not a center.
I try to change the size in getPreferredSize() method but It's doesn't help me or doing another effect. I can't do this.
I try to change the size in getPreferredSize() method but It's doesn't help me or doing another effect.
I try to change
This is code which I can't change for my needs!
This is code which I can't change for my needs!
package j;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Letter {
LetterDraw letterDraw = new LetterDraw();
public Letter() {
JFrame frame = new JFrame();
JPanel letterDrawWrapper = new JPanel(new GridBagLayout());
letterDrawWrapper.add(letterDraw);
letterDrawWrapper.setSize(1024,760);
frame.add(createColorChooser(), BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setSize(111, 111);
frame.setVisible(true);
}
private JColorChooser createColorChooser() {
JColorChooser colorChooser = new JColorChooser();
colorChooser.getSelectionModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
letterDraw.setColor(colorChooser.getColor());
}
});
return colorChooser;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Letter();
}
});
}
}
class LetterDraw extends JPanel {
private Color color;
public void setColor(Color color) {
this.color = color;
repaint();
}
#Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g = (Graphics2D) graphics;
g.setColor(color);
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(3));
//g.setStroke(new BasicStroke(4, BasicStroke.JOIN_BEVEL, 0));
g.setColor(color);
g.drawLine(11,11,1024,1024);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
}```
Need set 1024*768 the size of paintComponent Area.
You should NOT be hard coding size values. You don't know what the resolution will be.
Also, The resolution of your screen is NOT the space available for painting. The frame has a title bar and border which takes away space for custom painting.
Painting code should be dynamic based on the space available to your panel, so the painting code would use methods like getWidth() and getHeight() to determine the painting area.
I try to change the size in getPreferredSize()
Yes that will work to give a suggestion for the preferred size. Then you just pack() the frame. Don't use setSize() on the frame.
//frame.setSize(111, 111);
That statement is overriding the size determined by the pack() method. Get rid of it.
g.drawLine(11,11,1024,1024);
Don't hard code values. The size of the panel will change as the frame is resized. For example to draw a diagonal line on the panel the code should be:
g.drawLine(0, 0, getWidth(), getHeight());
Try manually resizing the frame to see how the size of the line changes.
Edit:
You didn't add your panel to the frame:
frame.add(letterDraw);
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
frame.setSize(new Dimension(100, 100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel panel = new TestPanel();
panel.setPreferredSize(new Dimension(50,50));
frame.add(panel);
frame.setVisible(true);
}
static class TestPanel extends JPanel implements ActionListener{
private static final long serialVersionUID = 8518959671689548069L;
public TestPanel() {
super();
Timer t = new Timer(1000, this);
t.setRepeats(true);
t.start();
}
int opacity = 10;
#Override
public void actionPerformed(ActionEvent e) {
if(opacity >= 250) {
opacity = 0;
}
else {
this.setBackground(new Color(255, 212, 100, opacity));
this.repaint();
opacity+=10;
System.out.println("opacity is " + opacity);
}
}
}
}
The rate the alpha changes is faster than it should be. After it reaches a certain point, the opacity drops, while the the opacity printed in the console is less than 250. Resizing the window "resets" it, making the alpha correct.
How do I make it actually draw the alpha correctly?
this.setBackground(new Color(255, 212, 100, opacity));
Swing does not support semi transparent backgrounds.
Swing expects a component to be either:
opaque - which implies the component will repaint the entire background with an opaque color first before doing custom painting, or
fully transparent - in which case Swing will first paint the background of the first opaque parent component before doing custom painting.
The setOpaque(...) method is used to control the opaque property of a component.
In either case this makes sure any painting artifacts are removed and custom painting can be done properly.
If you want to use tranparency, then you need to do custom painting yourself to make sure the background is cleared.
The custom painting for the panel would be:
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
panel.setOpaque(false); // background of parent will be painted first
Similar code would be required for every component that uses transparency.
Or, you can check out Background With Transparency for custom class that can be used on any component that will do the above work for you.
When I add Swing component (like a JButton) to a JPanel, it renders with it's 'preferred size'.
However, the preferred size is actually larger than the painted button. There appears to be an invisible border around it.
Here's a simple frame with my test panel:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel pnl = new TestPanel();
frame.getContentPane().add(pnl);
frame.pack();
frame.setVisible(true);
Here's my test panel ...
public class TestPanel extends JPanel {
JButton btn1 = new JButton("Test1");
JButton btn2 = new JButton("Test2");
public TestPanel() {
this.add(btn1);
this.add(btn2);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
Dimension dim = btn1.getPreferredSize();
g.drawRect(btn1.getX(), btn1.getY(), (int)(dim.getWidth()), (int)(dim.getHeight()));
}
}
Notice I painted btn1's "PreferredSize" in RED to demonstrate that the preferredSize is actually larger than the button itself.
My question is, how can I determine the width and height of the painted button, not the JButton's preferredSize?
Any help is greatly appreciated, thanks!
UPDATE
Because I actually need this to work for all Swing components, here's a screen shot with the more components.
Unfortunately, I need to figure this out, determining the "real" size of the visible widget is crucial to my application.
I don't think this is particular or practically achievable.
The problem is, the button is using the "unpainted" area to paint other elements, like the focus highlight.
You could try look at the AbstractButton#set/getMargin
If nothing better comes along, note that the authors "recommend that you put the component in a JPanel and set the border on the JPanel."
Addendum: Based on your comments below, it's clear that your question is not about rendering borders but about establishing a component's boundary. What you perceive as unused space is actually reserved by the UI delegate for any number of uses, e.g. selection highlighting or esthetic coherence. You can get an idea of how this varies by selecting different Look & Feel themes in the examples here and here.
Using getbounds():
Using setBorder():
import component.Laf;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* #see https://stackoverflow.com/a/15490187/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
// https://stackoverflow.com/a/11949899/230513
f.add(Laf.createToolBar(f));
f.add(decorate(new JButton("Test")));
f.add(decorate(new JTextField("Test")));
f.add(decorate(new JTextArea(3, 8)));
f.add(decorate(new JCheckBox("Test")));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel decorate(final JComponent c) {
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle r = c.getBounds();
g.setColor(Color.red);
// NB pen hangs down and to the right
g.drawRect(r.x - 1, r.y - 1, r.width + 1, r.height + 1);
}
};
p.add(c);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
I am learning Java on my own. Trying to create a frame with a line in it. It seemed pretty basic, but I can't see the line. The code compiles and I can't seem to understand why I can't see the line. I see other components in the frame.
I am using 2 java files. One file is container file and the other file has the draw line code. They are part of package a1.
Here is my code (please help):
Container File:
package a1;
import javax.swing.*;
import java.awt.*;
public class gameContainer {
public static void addComponentsToPane(Container pane) {
pane.setLayout(null);
//add button to the pane
JButton b3 = new JButton("B1");
pane.add(b3);
//add line to the pane
drawingLine line1 = new drawingLine();
pane.add(line1);
//size and position all relatively
Insets insets = pane.getInsets();
Dimension size;
size = b3.getPreferredSize();
b3.setBounds(350+insets.left,15+insets.top,size.width+50,size.height+20);
size = line1.getPreferredSize();
line1.setBounds(350+insets.left,75+insets.top,size.width+50,size.height+20);
}
private static void createAndShowGUI() {
int l = 200, w = 80;
//Create and set up the window.
JFrame frame = new JFrame("Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up content pane
addComponentsToPane(frame.getContentPane());
//add menu bar
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menu.add(new JMenuItem("Do nothing"));
menuBar.add(menu);
frame.setJMenuBar(menuBar);
// size and display root pane/window
Insets insets = frame.getInsets();
frame.setSize(500+insets.left+insets.right,300+insets.top+insets.bottom);
frame.setLocation(w,l);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Draw line File:
package a1;
import javax.swing.*;
import java.awt.geom.Line2D;
import java.awt.Graphics2D;
import java.awt.Graphics;
public class drawingLine extends JPanel{
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Line2D line = new Line2D.Double(200, 300, 1000, 1000);
//g2d.setColor(Color.black);
g2d.draw(line);
//g.drawLine(200, 300, 1000, 1000);
//g.setColor(color.BLACK);
}
}
Why am I not able to see the line?
Your main problem is that you use null/Absolute layout.
You should have a read here:
Laying Out Components Within a Container
1) You should use an appropriate LayoutManager (or nest together multiple LayoutManagers) and/or override getPreferredSize() of JComponent to return correct dimensions which fit the drawings.
2) Dont call setSize on JFrame rather call pack() before setting JFrame visible (with above in mind)
3) No need for adding to contentPane via getContentPane().add(..) as add(..) setLayout(..) and remove(..) have been forwarded to the contentPane.
4) Watch class names, stick to the java convention a class name begins with a capital letter and each new word thereafter the first letter should be capitilized i.e gameContainer should be GameContainer, drawingLine should be DrawingLine
Here is your code with above fixes implemented (not the most well layed out, but its only an example):
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
public class GameContainer {
public static void addComponentsToPane(JFrame frame) {
JPanel buttonPanel=new JPanel();//create panel to hold button
//add button to the pane
JButton b3 = new JButton("B1");
buttonPanel.add(b3);
frame.add(buttonPanel, BorderLayout.EAST);//use contentPane default BorderLayout
//add line to the pane
DrawingLine line1 = new DrawingLine();
frame.add(line1);
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up content pane
addComponentsToPane(frame);
//add menu bar
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menu.add(new JMenuItem("Do nothing"));
menuBar.add(menu);
frame.setJMenuBar(menuBar);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
class DrawingLine extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Line2D line = new Line2D.Double(10, 10, 100, 100);
g2d.draw(line);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
The proper (better to say, easier, much less error prone) way to do it has been shown by David Kroukamp. As for your original question, modify the original code like this:
line1.setBounds(350+insets.left,75+insets.top,size.width+50,size.height+20);
line1.setBorder(BorderFactory.createEtchedBorder()); // add this line
Your line starts at point 200,300 but the panel you're drawing it in has width of 50+10 and height of 20+10 - on my computer at least - which means that the line is outside of the drawingLine panel and that's why it doesn't get drawn. To verify that modify the line in your original drawingLine.paintComponent like this:
Line2D line = new Line2D.Double(0, 0, 1000, 1000);
and you will see the following result:
This line in your original code:
pane.setLayout(null);
is pretty clear - you are using no layout manager, or in other words you chose to use absolute positioning. This means that the coordinates, widths and heights of components must be precalculated and set by you. But if you make a mistake somewhere (as your example nicely shows) it'll be hard to detect. Not to mention, for example if you want to handle window resizing. That's why LayoutManagers exist.
I recommend reading also:
Using Layout Managers
Solving Common Layout Problems
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.