When I run the program, the JPanel is not visible. It works without the JScrollPane though. This is driving me crazy! Before, I had it using a Canvas and a ScrollPane. Note that FlowchartPanel extends JPanel.
public class Window extends JFrame{
private FlowchartPanel panel; // contains all the main graphics
private JScrollPane scrollpane; // contains panel
private int canvasWidth, canvasHeight; // the width and height of the canvas object in pixels
private Flowchart flowchart; // the flowchart object
public Window(Flowchart flowchart) {
super();
canvasWidth = 900;
canvasHeight = 700;
this.flowchart = flowchart;
flowchart.setWidth(canvasWidth);
flowchart.setHeight(canvasHeight);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new FlowchartPanel(flowchart);
panel.setPreferredSize(new Dimension(canvasWidth, canvasHeight));
scrollpane = new JScrollPane();
scrollpane.setPreferredSize(new Dimension(canvasWidth, canvasHeight));
scrollpane.add(panel);
add(scrollpane);
//add(panel);
pack();
}
}
Don't add components directly to a JScrollPane.
The component needs to be added to the JViewPort of the JScrollPane
The easiest way to do this is to use:
JScrollPane scrollPane = new JScrollPane( panel );
Another way is to replace (add) the component in the viewport is to use:
scrollPane.setViewportView( panel );
panel.setPreferredSize(new Dimension(canvasWidth, canvasHeight));
Don't set the preferred size of a component. Every Swing component is responsible for determining its own preferred size. Instead override the getPreferredSize() method of your custom panel to return the size. This way as the custom painting changes, you can dynamically change the preferred size as required.
Related
i been working on some bigger project lately but couldn't figure it out why JScrollPane wouldn't work. I have never used it before and I read many solved problems about it on stackOverflow and other programming forums but non of the code were looking similar to mine to help me implement my method.
this is new project i made to make it short and show some examples.
Red colour is main panel that will contain another panel/JScrollPane inside that will be colour black
and i would like to make this Jpanel with colour black to be scrollable and hold any number of that white JPanels that might be from 0 to a 100+
public class ScrollablePane {
private JFrame frame;
private JPanel panelCopy;
private JPanel panel;
private JPanel container;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScrollablePane window = new ScrollablePane();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ScrollablePane() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
panel = new JPanel();
panel.setBackground(Color.RED);
panel.setBounds(0, 0, 434, 261);
frame.getContentPane().add(panel);
panel.setLayout(null);
container = new JPanel();
container.setBackground(Color.BLACK);
container.setBounds(10, 10, 414, 241);
container.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
panel.add(container);
for(int i = 0; i < 20; i++) {
if(i > 0) {
panelCopy = new JPanel();
panelCopy.setPreferredSize(new Dimension(400, 40));
container.add(panelCopy);
}
}
}
}
if you want to use a JScrollPane, then your code actually needs to use a JScrollPane. The code you posted doesn't even create a JScrollPane.
If you want the panels to display vertically then don't use a FlowLayout. The FlowLayout is a horizontal layout. You could use a BoxLayout or a GridBagLayout.
Why do you create the "panel" variable and add it the the content pane? The content pane of the frame already is a JPanel that uses a BorderLayout. There is no need to add another panel
Don't use a null layout!!! Swing was designed to be used with layout managers. Scrolling won't work if the panel added to the scroll pane uses a null layout.
So in your case the basic logic might be something like:
Box container = Box.createVerticalBox();
// add you child panels to the container.
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add(container, BorderLayout.PAGE_START);
JScrollPane scrollPane = new JScrollPane(wrapper);
frame.add(scrollPane, BorderLayout.CENTER);
Note the "wrapper" panel is used to prevent the panels from expanding in size when the scroll pane is larger then the preferred size of the "container" panel.
Try:
//JScrollPane scrollPane = new JScrollPane(wrapper);
JScrollPane scrollPane = new JScrollPane(container);
to see the different result.
My GUI consists of a Diagram class which extends JFrame. I've created a different class called DrawingTool which extends JComponent. The DrawingTool class is like a canvas area for users to drop and drag shapes. I've also added a button panel at the bottom of the JFrame for the users to click various buttons to choose their desired shape and control actions. I've added the button panel and an instance of the DrawingTool class to the Diagram class. How do I make the canvas area (DrawingTool) scrollable? The way I have attempted it is not working, I know I am missing something.
Here is the Diagram class:
public class Diagram extends JFrame {
JButton serverButton, vipButton, arrowButton, undoButton, dragButton, loadButton, submitButton;
JButton applicationButton;
int currentAction = 1;
Graphics2D graphSettings;
Color strokeColor = Color.BLUE, fillColor = Color.BLACK;
/**
* Constructor to generate new diagram with empty drawing board and button
* panel.
*/
public Diagram() {
// Define the defaults for the JFrame
this.setSize(1000, 1000);
this.setTitle("Diagram Tool");
//this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel buttonPanel = new JPanel();
// Swing box that will hold all the buttons
Box theBox = Box.createHorizontalBox();
// Make all the buttons in makeButtons by calling helper function
serverButton = makeButtons("Server", 2);
vipButton = makeButtons("VIPs", 3);
arrowButton = makeButtons("Arrow", 4);
undoButton = makeButtons("Undo", 5);
dragButton = makeButtons("Drag", 6);
loadButton = makeButtons("Load", 11);
applicationButton = makeButtons("Application", 8);
submitButton = makeButtons("Submit", 12);
// Add the buttons to the box
theBox.add(serverButton);
theBox.add(vipButton);
theBox.add(applicationButton);
theBox.add(arrowButton);
theBox.add(undoButton);
theBox.add(dragButton);
theBox.add(loadButton);
theBox.add(submitButton);
// Add the box of buttons to the panel
buttonPanel.add(theBox);
// Position the buttons in the bottom of the frame
JPanel container=new JPanel();
container.add(new DrawingBoard(),BorderLayout.CENTER);
JScrollPane jsp=new JScrollPane(container);
this.add(buttonPanel, BorderLayout.SOUTH);
this.add(jsp);
// Make the drawing area take up the rest of the frame
// Show the frame
this.setVisible(true);
}
Here is the DrawingBoard class:
private class DrawingBoard extends JComponent implements MouseListener, MouseMotionListener {
//declare variables
/**
* Constructor to initialize the drawing board
*/
public DrawingBoard() {
addMouseListener(this);
addMouseMotionListener(this);
// initializeCanvas();
}
//Rest of the code for DrawingBoard
}
This is how it looks now. I'd like to make the gray canvas area scrollable.
Diagram Image
What MadProgrammer said in the comments is just about right. You need to set some informations so your ScrollPanel knows how to behave. What is it's own size, the size of the components inside it, etc.
So normally you'll have a ContentPane, and inside of it panes with your content. To do a scrollable pane you only need to put the ScrollPane inside of your ContentPane and then set a viewport for your ScrollPane. A little code I used fully functional:
contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setLayout(null);
JScrollPane scrollPane = new JScrollPane();
//Vertical and Horizontal scroll bar policy is set to choose when the scroll will be visible scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBounds(0, 217, 414, 505);
scrollPane.setPreferredSize(new Dimension(414, 414));
JPanel viewport = new JPanel();
viewport.setLayout(null);
viewport.setBounds(0, 0, 414, 505);
//Create your components here, then:
//viewport.add(component)
viewport.setPreferredSize(new Dimension(414, 150));
scrollPane.setViewportView(viewport);
contentPane.add(scrollPane);
Anything you put inside of your ViewPort
will be automaticaly scrolable, if it's size is bigger than the PreferredSize.
Note that all the dimensions I've put is only for example.
I am using Miglayout to define a layout for my program. The problem is the JScrollPane prevents the JButton shrinking below its preferred size. The minimum, preferred, and maximum widths for the JButton are set like this, "w 300:600:900" //min:pref:max.
What is the best way to fix this problem?
SSSCE
import java.awt.*;
import javax.swing.*;
import net.miginfocom.swing.MigLayout;
public class ButLay extends JFrame {
private ButLay() {
super("Button Layout");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new MigLayout("", "grow", "grow"));
createPanel();
setSize(800, 200);
setVisible(true);
}
JPanel panel = new JPanel(new MigLayout("", "grow", "grow"));
JScrollPane scroll;
JButton button = new JButton("Button");
private void createPanel() {
panel.add(button, "gapleft 100, align right, w 300:600:900, south");
scroll = new JScrollPane(panel);
getContentPane().add(scroll, "grow");
}
public static void main(String[] args) {
new ButLay();
}
}
The default behaviour of a JScrollPane is to display the component in the scroll pane at its preferred size so that the scrollbars can appear as required.
If you want to change the behaviour then you can try to implement the Scrollable interface on your panel. You might be able to override the getScrollableTracksViewportWidth() method to return true. Now your panel should resize as the viewport of the scrollpane resizes. However using this approach your won't get a scrollbar if you make the viewport too small.
If you want the scrollbar in the above situation, then you may also need to override the getPreferredSize() method to return the minimum size when the preferredSize is greater than the size of the viewport.
You can also check out Scrollable Panel which implements the Scrollable interface for you and allows you to customize the behaviour with some convenience methods.
I have the following code to create my GUI.
private static void createGUI() {
JFrame frame = new JFrame ("Tiles Game");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar (new JMenuBar());
frame.setContentPane (MainPanel.getInstance());
frame.pack();
frame.setResizable (false);
frame.setLocationRelativeTo (null);
frame.setVisible (true);
}
This is the MainPanel (extends JPanel) constructor:
private MainPanel() {
super (new BorderLayout());
setPreferredSize (new Dimension (IMG_SIZE + 10, IMG_SIZE + 10));
...
panel = new ImagePanel();
add (panel, BorderLayout.CENTER);
}
And this is the ImagePanel (extends JPanel) constructor:
private ImagePanel() {
super();
setPreferredSize (new Dimension (IMG_SIZE, IMG_SIZE));
...
}
However the ImagePanel is aligned to the top left corner of the MainPanel rather than centered, so I get a bunch of extra padding at the bottom and right sides, and none at the top and left sides. How do I place it at the center of the MainPanel?
Probably what's happening is that you are drawing your image from (0, 0) which are the top-left corner. Then you set the preferred size to 10 pixels larger which makes the panel larger, but the image is still at (0, 0)
Instead use the same size witoout adding 10, and just use an EmptyBorder for the panel. Also as a recommendation, override getPreferredSize() instead of using setPreferredSize()
public class ImagePanel extends JPanel {
public ImagePanel() {
setBorder(new EmptyBorder(10, 10, 10, 10));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(IMG_SIZE, IMG_SIZE);
}
}
Also you may want to consider using a GridBagLayout for the container panel, for a sure center, if the container is to be larger than the the child panel. Few things you could do. Even consider using a ImageIcon and JLabel instead of painting (if the image doesn't need to be resized (as Camickr(+1) pointed out). A JLabel could easily be made a background by just setting the layout of the label and set it as the content pane of the frame.
ImageIcon icon = new ImageIcon(...)
JLabel frameBackground = new JLabel(icon);
frameBackground.setLayout(new BorderLayout());
frame.setContentPane(frameBackground);
Don't use a JPanel to display an image.
Instead use a JLabel with an ImageIcon.
If you want extra space around the image then you use an EmptyBorder on the label.
I have a JFrame, in this JFrame I have a JPanel that I draw on, this Panel can be any size and so I placed it into a JScrollpane to let me scroll when the panel is larger than the window screen size.
Unfortunately does not work as I expected:
Making the JFrame window smaller than the JPanel size does not show scroll bars
The JScrollPane size now seems locked to the size of the JPanel I have added to it, where as before it resized to the bounds of it's JFrame window (it still kinda does this but only vertically now?!)
The JPanel seems to assume the size of the JScrollpane regardless of what I set for preferred size
I am sure I'm doing something stupid, if someone could point out what I would be most grateful!
JPanel imageCanvas = new JPanel(); // 'Canvas' to draw on
JScrollPane scrollPane = new JScrollPane();
// set size of 'canvas'
imageCanvas.setMinimumSize(new Dimension(100,100));
// Scroll pane smaller then the size of the canvas so we should get scroll bars right?
scrollPane.setMinimumSize(new Dimension(50,50));
// Add a border to 'canvas'
imageCanvas.setBorder(BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
scrollPane.setViewportView(imageCanvas);
setPreferredSize() is the trick, setMinimumSize() and even setSize() on the component will be ignored by JScrollPane. Here's a working example using a red border.
import java.awt.*;
import javax.swing.*;
public class Scroller extends JFrame {
public Scroller() throws HeadlessException {
final JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.red));
panel.setPreferredSize(new Dimension(800, 600));
final JScrollPane scroll = new JScrollPane(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(scroll, BorderLayout.CENTER);
setSize(300, 300);
setVisible(true);
}
public static void main(final String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Scroller().setVisible(true);
}
});
}
}
// suggest a size of 'canvas'
_ImageCanvas.setPreferredSize(new Dimension(100,100));
// Scroll pane smaller then the size of the canvas so we should get scroll bars right?
_ScrollPane.setPreferredSize(new Dimension(50,50));
// ..later
_Frame.pack();
Set preferred size on the canvas.
Increase dimensions 100,100 is too small atleast on my computer.
You may want to use new GridLayout(1,1); for you JFrame if you want the scrollpane to expand when you expand the frame.
As far as I remember there are 2 options:
define the preferredSize of _ImageCanvas
create a subclass of JPanel and implement Scrollable: http://docs.oracle.com/javase/7/docs/api/javax/swing/Scrollable.html
For more details, see the Javadoc:
http://docs.oracle.com/javase/7/docs/api/javax/swing/JScrollPane.html
Check out the Scrollable interface, this may help with the sizing issues.
These two method maybe helpful:
boolean getScrollableTracksViewportWidth();
boolean getScrollableTracksViewportHeight();