Welcome to a wonderful example of why null
layouts suck...
Avoid using null
layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
Also see Why is it frowned upon to use a null layout in SWING? for more details...
The basic problem is, the JScrollPane
, has a JViewport
, which actually contains your component. The JViewport
uses your components sizing hints to make determinations about how big it should be and the JScrollPane
uses the decisions the JViewport
makes to make determinations about whether it needs to display the scrollbars or not.
The JViewport
is taking a look at your component and has decided, because you've not told it otherwise, that it should be 0x0
in size.
You can prove this by adding a LineBorder
to your component, setBorder(new LineBorder(Color.RED));
, you won't see it either (or if you do, it will be a little red square)
Start by overriding the getPrefferedSize
method of the Test
panel and return some appropriate size
Next, call super.paintComponent
before you perform any custom painting, otherwise you'll end up with some awesome, but annoying, paint artifacts...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test extends JPanel {
public static void main(String... args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Test test = new Test();
JFrame frame = new JFrame();
JScrollPane scrollPane = new JScrollPane(test);
frame.add(scrollPane);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(3000, 3000);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawLine(30, 30, 30, 3000);
g2.drawLine(30, 400, 500, 3000);
}
}
You'll probably want to take a look at the Scrollable
interface
next, so you can control the default size of the JViewport
, so it won't try and fill the entire screen.
Take a look at Implementing a Scrolling-Savvy Client for more details