I have an issue with Swing. I have placed two JScrollPane inside a JSplitPane horizontally and have synchronized the JScrollPanes. Inside each of the JScrollPane I have placed one JPanel. The synchronization i.e. (scrolling a JScrollPane also scrolls the other JScrollPane) between the two JScrollPane works normally. But when I drag the JSplitPane divider towards left/right till some part of a JPanel becomes hidden then horizontal scroll bar is shown but in disabled form. I am not able to scroll to see the hidden part of JPanel.
Here is the code:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
public class SplitPaneTest extends JFrame {
public SplitPaneTest() {
setTitle( "Splits" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
setSize( 400, 400 );
JPanel panel1 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.add( new JLabel( "Left panel!" ) );
JScrollPane scrollPane1 = new JScrollPane(panel1);
JPanel panel2 = new JPanel();
panel2.setLayout(new BorderLayout());
panel2.add( new JLabel( "Right Panel" ) );
JScrollPane scrollPane2 = new JScrollPane(panel2);
scrollPane2.getVerticalScrollBar().setModel(scrollPane1.getVerticalScrollBar().getModel());
scrollPane2.getHorizontalScrollBar().setModel(scrollPane1.getHorizontalScrollBar().getModel());
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollPane1,
scrollPane2);
splitPane.setResizeWeight(0.5);
add(splitPane);
setVisible( true );
}
public static void main( String[] args ) {
new SplitPaneTest();
}
}
Scrollbars are displayed automatically when the preferred size of the component is greater than the size of the scroll pane.
You can't share the models because the state of each scrollbar will be different depending on how much space is allocation to each scroll pane. The only time they will be in sync is when the divider of the split pane is in the middle.
So you need to listen for changes in the scrollbar of each scroll pane and than attempt to adjust the scrollbar from the other scroll pane.
Something like:
import java.awt.BorderLayout;
import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import java.awt.event.*;
public class SplitPaneTest2 extends JFrame {
public SplitPaneTest2() {
setTitle( "Splits" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
setSize( 400, 400 );
JPanel panel1 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.add( new JLabel( "Left panel!11111111111111111111" ) );
JScrollPane scrollPane1 = new JScrollPane(panel1);
JPanel panel2 = new JPanel();
panel2.setLayout(new BorderLayout());
panel2.add( new JLabel( "Right Panel11111111111111111111" ) );
JScrollPane scrollPane2 = new JScrollPane(panel2);
// scrollPane2.getVerticalScrollBar().setModel(scrollPane1.getVerticalScrollBar().getModel());
// scrollPane2.getHorizontalScrollBar().setModel(scrollPane1.getHorizontalScrollBar().getModel());
new ScrollBarSynchronizer(scrollPane1.getHorizontalScrollBar(), scrollPane2.getHorizontalScrollBar());
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollPane1,
scrollPane2);
splitPane.setResizeWeight(0.5);
add(splitPane);
setVisible( true );
}
public static void main( String[] args ) {
new SplitPaneTest2();
}
static class ScrollBarSynchronizer implements AdjustmentListener
{
JScrollBar[] scrollBars;
public ScrollBarSynchronizer(JScrollBar... scrollBars)
{
this.scrollBars = scrollBars;
for (JScrollBar scrollBar: scrollBars)
scrollBar.addAdjustmentListener( this );
}
#Override
public void adjustmentValueChanged(AdjustmentEvent e)
{
JScrollBar source = (JScrollBar)e.getSource();
int value = e.getValue();
for (JScrollBar scrollBar: scrollBars)
{
if (scrollBar != source)
{
scrollBar.removeAdjustmentListener( this );
scrollBar.setValue( value );
scrollBar.addAdjustmentListener( this );
}
}
}
}
}
You can also create a separate synchronizer for the vertical scrollbars.
Maybe the point is that shifting the divider of the JSplitPane does not RESIZE the JScrollPane. Nevertheless the VIEW on the JScrollPane is changed therefore the scrollbar is shown by the JScrollPane (The scrollbar automatically appears when the preferred size of a component is greater than the size of the viewport on the JPanel in the JScrollPane)
But the scrollbar it is greyed-out because from the viewpoint of the JScrollPane there is no need to scroll (the JPanel it contains was not resized and therefore does not exceed the size of the JScrollPane...)
UPDATE this works for me, the solution is to put as much content in the JPanels that the scrollbars appear (the font is a bit shredded when scrolled fast)
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
public class SplitPaneTest extends JFrame {
public SplitPaneTest() {
setTitle( "Splits" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
setSize( 200, 200 );
JPanel panel1 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.setBackground(Color.YELLOW);
panel1.setLayout(new BorderLayout());
//panel1.setMinimumSize(new Dimension(100,200));
//panel1.setPreferredSize(new Dimension(100,200));
//panel1.revalidate();
panel1.add( new JLabel( "Left panel! fhajsdfasbkfbbsdkjafbkajhbshabshjdfbajsbskjaSK" ) );
JScrollPane scrollPane1 = new JScrollPane(panel1, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
//scrollPane1.setMinimumSize(new Dimension(100,200));
//scrollPane1.setPreferredSize(new Dimension(100,200));
//scrollPane1.revalidate();
JPanel panel2 = new JPanel();
panel2.setLayout(new BorderLayout());
//panel2.setMinimumSize(new Dimension(100,200));
//panel2.setPreferredSize(new Dimension(100,200));
//panel2.revalidate();
panel2.add( new JLabel( "Right Panel dfgasdgsdghsgs<dg<sdgs<dgdsgdfsafasfasfasfsafa" ) );
JScrollPane scrollPane2 = new JScrollPane(panel2, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
//scrollPane2.setMinimumSize(new Dimension(100,200));
//scrollPane2.setPreferredSize(new Dimension(100,200));
//scrollPane2.revalidate();
scrollPane2.getVerticalScrollBar().setModel(scrollPane1.getVerticalScrollBar().getModel());
scrollPane2.getHorizontalScrollBar().setModel(scrollPane1.getHorizontalScrollBar().getModel());
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollPane1,
scrollPane2);
splitPane.setResizeWeight(0.5);
//splitPane.setContinuousLayout(true);
this.add(splitPane);
this.setVisible( true );
}
public static void main( String[] args ) {
new SplitPaneTest();
}
}
Related
I tried to add a JPanel (with FlowLayout) to a JScrollPane but the ScrollBar is not working. I want to place buttons as grid but it places horizontally.
import javax.swing.*;
import java.awt.*;
public class Test {
public static void main(String[] args){
JFrame frame = new JFrame("Test");
frame.setVisible(true);
frame.setSize(1000,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
JScrollPane pane = new JScrollPane(panel);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
frame.add(pane);
for (int i=0;i<100;i++){
panel.add(new JButton("Label"));
}
}
}
I want to place buttons as grid but it places horizontally.
That's because you do not set the preferred size of the JPanel and because you add the JPanel to a JScrollPane you are effectively giving the JPanel infinite width and FlowLayout will lay out all its components in a single row until it reaches the width limit of the JPanel but because the width is infinite, all the JButtons appear on the same line. Also, because you set the horizontal scrollbar policy to NEVER, there is no way to scroll the JPanel.
You should call method setVisible(true) after you have added all the components.
Note that in the below code I use GridLayout rather than FlowLayout because FlowLayout will not display a grid of JButton. Also note that I call method pack() rather than method setSize().
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 10, 5, 5));
JScrollPane pane = new JScrollPane(panel);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
for (int i=0;i<100;i++){
panel.add(new JButton("Label"));
}
frame.add(pane);
frame.pack();
frame.setVisible(true);
}
}
Here is a screen capture:
Note that, by default, JScrollPane will size itself so as to display all the JButtons. If you want the JScrollPane to only display a few rows, then you need to set its preferred size, for example
pane.setPreferredSize(new Dimension(710, 150));
EDIT
If you insist on using FlowLayout then you need to set the preferred size for both the JPanel and the JScrollPane.
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(710, 315));
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
for (int i = 0; i < 100; i++) {
panel.add(new JButton("Label"));
}
JScrollPane pane = new JScrollPane(panel);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
pane.setPreferredSize(new Dimension(720, 160));
frame.add(pane);
frame.pack();
frame.setVisible(true);
}
}
Here is a screen capture.
I have this piece of code that is basically a JFrame that contains a JSplitPane which contains on the left side a JScrollPane which contains a JPanel. I expected to see the scroll bars since the JPanel inside the JScrollPane is larger that the JScrollPane itself. Why are the scroll bars not displayed?
If I replace setSize() with setPreferredSize() then it works, but I want to use setSize(). Is there any way I can use setSize() and have the scroll bars showing?
import java.awt.*;
import javax.swing.*;
public class Test {
public static void main( String[] args ) {
JFrame frame = new JFrame();
frame.setLayout( new BorderLayout() );
JSplitPane splitPane = new JSplitPane();
frame.add( splitPane, BorderLayout.CENTER );
JPanel panel = new JPanel();
panel.setBackground( Color.red );
panel.setSize( 1920, 1200 );
//panel.setPreferredSize( new Dimension( 1920, 1200 ) );
JScrollPane scrollPane = new JScrollPane( panel );
splitPane.setLeftComponent( scrollPane );
splitPane.setRightComponent( new JPanel() );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
frame.setSize( 960, 600 );
}
}
Edit: I've added a modified version where I use setPreferredSize(). Is there a better solution for dynamically changing the size?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test {
public static void main( String[] args ) {
JFrame frame = new JFrame();
frame.setLayout( new BorderLayout() );
JSplitPane splitPane = new JSplitPane();
frame.add( splitPane, BorderLayout.CENTER );
final JPanel panel = new JPanel();
panel.setBackground( Color.red );
panel.setPreferredSize( new Dimension( 1920, 1200 ) );
JScrollPane scrollPane = new JScrollPane( panel );
splitPane.setLeftComponent( scrollPane );
JButton button = new JButton();
button.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
panel.setPreferredSize( new Dimension( 3840, 2400 ) );
panel.revalidate();
}
});
splitPane.setRightComponent( button );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
frame.setSize( 960, 600 );
}
}
Your setSize will be ignored by the JSplitPane because the layout of the left/right components is not null, and it tries to fit the internal components in the available space.
The layout manager for the JSplitPane's left/right components honors the preferredSize property(and not the size property) and if it hasn't been set, it just tries to fit the internal component inside the available space of left/right area in JSplitPane.
Use setPreferredSize instead or override the getPreferredSize method for your panel as camickr described in the comment.
I'm having this piece of code, I want to add a scrollbar for CanvasBoard, but it does not show the scroll bar. CanvasBoard and PointCanvas extends JPanel.
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel cb = new JPanel();
JScrollPane scrollPane = new JScrollPane(cb);
scrollPane.setPreferredSize(new Dimension(2000, 600));
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollPane,
new JPanel());
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation(150);
Dimension minimumSize = new Dimension(600, 600);
cb.setMinimumSize(minimumSize);
frame.add(splitPane);
frame.setSize(1200, 600);
frame.setVisible(true);
}
Do you have any idea why?Thanks!
The default for a JScrollPane is to have the scroll bars show up when needed.
I changed a few things in your example and added commands to make the scroll bars visible.
Here's your Swing layout.
And here's the modified code.
package com.ggl.testing;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
public class ScrollPaneTest implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new ScrollPaneTest());
}
#Override
public void run() {
JFrame frame = new JFrame("Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel cb = new JPanel();
JScrollPane scrollPane = new JScrollPane(cb);
scrollPane
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setPreferredSize(new Dimension(2000, 600));
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
scrollPane, new JPanel());
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation(150);
Dimension minimumSize = new Dimension(600, 600);
cb.setMinimumSize(minimumSize);
frame.add(splitPane);
frame.setSize(1200, 600);
frame.setVisible(true);
}
}
I would like to create a window, with 3 jPanels, separated by splitPane-s. The left, and the right one should be resizable by the user, and the one in the middle should fill the remaining space.
I've created it, but if I move the first splitPane, then the second one is also moving. And I'm not sure, if I use the best method for what I want.
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
public class MyWindow extends JFrame {
public MyWindow() {
this.setLayout(new BorderLayout());
JPanel leftPanel = new JPanel();
JPanel centerPanel = new JPanel();
JPanel centerPanel2 = new JPanel();
JPanel rightPanel = new JPanel();
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, centerPanel);
JSplitPane sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, centerPanel2, rightPanel);
centerPanel.setLayout(new BorderLayout());
this.add(sp, BorderLayout.CENTER);
centerPanel.add(sp2, BorderLayout.CENTER);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500, 500);
this.setVisible(true);
}
}
What you're doing looks pretty weird to me i.e adding the centerPanel to the split pane, then adding the split pane to the centerPane. Not sure, but I think that the latter negates the former.
All you need to do is add the first split pane to the second split pane.
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
public class MyWindow extends JFrame {
public MyWindow() {
this.setLayout(new BorderLayout());
JPanel leftPanel = new JPanel();
leftPanel.setBackground(Color.BLUE);
JPanel centerPanel = new JPanel();
centerPanel.setBackground(Color.CYAN);
JPanel rightPanel = new JPanel();
rightPanel.setBackground(Color.GREEN);
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, centerPanel);
JSplitPane sp2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp, rightPanel);
this.add(sp2, BorderLayout.CENTER);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500, 500);
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new MyWindow();
}
});
}
}
I need to let users add more text fields to my JFrame so once the size of the frame has exceeded its original value a scroll pane would step in. Since I cannot add JScrollPane to JFrame in order to enable scrolling I decided to put the JPanel on the JFrame and pass the JPanel object into the JScrollPane constructor. Scrolling now works fine but only until it has reached the borders of the JPanel. The thing is the size of JPanel stays as is and is not stretching dynamically. What happens is the buttons in my code are using up all the space of the JPanel being the size of 300x300 but what I want to do is have JPanel stretch once these controls have used up its original space. Please advise.
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Rectangle;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
public class Skrol {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setLayout(new FlowLayout());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(400,400));
JScrollPane jsp = new JScrollPane(p);
jsp.setPreferredSize(new Dimension(300,300));
jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
for(int i=0;i<100;i++)
{
JButton b = new JButton("Button "+i);
p.add(b);
}
f.add(jsp);
f.setSize(new Dimension(600,600));
f.setLocation(300, 300);
f.setVisible(true);
}
}
I changed the Layout in your JPanel to GridLayout, so the Size of it is just handeld by the Layoutmanager depending on the components on the panel.
JFrame f = new JFrame();
f.setLayout(new BorderLayout());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel(new GridLayout(0, 5));
JScrollPane jsp = new JScrollPane(p);
jsp.setPreferredSize(new Dimension(300,300));
jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
for (int i = 0; i < 100; i++) {
JButton b = new JButton("Button " + i);
p.add(b);
}
f.add(jsp, BorderLayout.CENTER);
f.setLocation(300, 300);
f.setVisible(true);
f.pack();
Choose the Miglayout option under Layouts. i found this to be the easiest way
https://i.stack.imgur.com/XKHVu.png