JScrollPane scrolling issue - java

Initially all the components are aligning only in the Horizontal direction in a single row.
Then I set the size of scroll enabled panel as below
main.setPreferredSize(scroll.getViewport().getSize());
main.setMaximumSize(new Dimension(scroll.getViewport().getWidth(),Integer.MAX_VALUE));
And it worked the components start aligning in multiple lines,and not going beyond the screen horizontally. But why the vertical scroll is not happening, In fact the components are getting overridden, the height is also getting fixed as of viewport size even the maxsize is defined.
Please help.........
What i need is only vertical scrolling..... The components should not go beyond screen horizontally, but can go beyond screen vertically.
UPDATE with the code: Now all I want is the buttons should not go beyond the screen horizontally instead can use vertical scroll if the whole window is occupied.
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("JAVA GUI");
JPanel main = new JPanel();
JScrollPane scroll = new JScrollPane(main);
BoxLayout box = new BoxLayout(main, BoxLayout.Y_AXIS);
main.setLayout(box);
main.add(new JLabel("row 1"));
JPanel panel1 = new JPanel(new FlowLayout());
for(int i=0;i<200;i++){
panel1.add(new JButton("b"+i));
}
JPanel panel2 = new JPanel(new FlowLayout());
for(int i=0;i<200;i++){
panel2.add(new JButton("b"+i));
}
JPanel panel3 = new JPanel(new FlowLayout());
for(int i=0;i<200;i++){
panel3.add(new JButton("b"+i));
}
Border border = BorderFactory.createLineBorder(Color.black,10);
panel1.setBorder(border);
panel2.setBorder(border);
panel3.setBorder(border);
main.add(panel1);
main.add(new JLabel("row2"));
main.add(panel2);
main.add(new JLabel("row3"));
main.add(panel3);
frame.setContentPane(scroll);
frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
}

Scrollbars only appear when the preferred size of the component is greater than the size of the scrollpane.
A FlowLayout will wrap components, but it will not change the preferred size.
Check out the Wrap Layout which extends FlowLayout and will recalculate the preferred size for you when components wrap.

As camickr pointed out in https://stackoverflow.com/a/21816061 , the main problem here is that the FlowLayout does not properly compute the preferred size of the component. The WrapLayout that he linked solves this issue basically. But in this case, this is still not sufficient, because the preferred size of the panels will simply be "as wide as necessary to show all buttons". In order to really wrap the buttons, you also have to replace your main panel with a panel that implements the Scrollable interface and returns true in Scrollable#getScrollableTracksViewportWidth()
class ScrollablePanel extends JPanel implements Scrollable
{
#Override
public Dimension getPreferredScrollableViewportSize()
{
return getPreferredSize();
}
#Override
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation, int direction)
{
return 1;
}
#Override
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation, int direction)
{
return 1;
}
#Override
public boolean getScrollableTracksViewportWidth()
{
return true;
}
#Override
public boolean getScrollableTracksViewportHeight()
{
return false;
}
}
So in your code:
JPanel main = new ScrollablePanel(); // Use ScrollablePanel here
JScrollPane scroll = new JScrollPane(main);
...
JPanel panel1 = new JPanel(new WrapLayout()); // Use WrapLayout here
for(int i=0;i<200;i++){
panel1.add(new JButton("b"+i));
}

Related

Dynamically adding to JScrollPane without removing child components

I'm currently adding JPanels to a JScrollPane by pressing a button:
However, I can't get the panels to stack on top of each other when adding more than 1 panel to the scroll pane. The previously added panel in the scroll pane seems to be getting removed when I call getViewport().add().
Is there a way to get a JScrollPane to save it's children and make my GUI look like this when adding multiple JPanels with a button press?
MainWindow class:
JScrollPane trackerPanel = new JScrollPane();
trackerPanel.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
trackerPanel.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
trackerPanel.setPreferredSize(new Dimension(500, 400));
frame.getContentPane().add(BorderLayout.NORTH, trackerPanel);
frame.setVisible(true);
//method: called from EnterButtonListener to create and append TrackerTile to GUI
public void addTrackerTile() {
incrementTrackerPanelCounter();
TrackerTile trackerTile = new TrackerTile();
trackerPanel.getViewport().add(trackerTile);
}
TrackerTile class:
public class TrackerTile extends JPanel implements Scrollable {
public Dimension preferredSize = new Dimension(794, 100);
public TrackerTile() {
setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(794, 100);
}
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
public boolean getScrollableTracksViewportWidth() {
return false;
}
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
The basic logic to create the GUI should be:
JPanel somePanel = new JPanel( some layout );
JScrollPane scrollPane = new JScrollPane( somePanel );
frame.add(scrollPane. BorderLayout.CENTER);
Then in the ActionListener that adds new panels you just do:
somePanel.add( new TrackerTile() );
So its just like adding components to a panel. The only difference is that the panal has been added to a scroll pane.
There is no need to implement Scrollable. But if you really want to customize the Scrollable properties, then you need to implement Scrollable on the "somePanel", not the individual components you add to "somePanel".
Or another option is to use the Scrollable Panel which implements the Scrollable interface and has methods that allow you to customize the behaviour.

Add JPanels dynamically to either a JTable or a JScrollPane

Currently working on a project and I need to add a panel I've made to a scrollpane or a table dynamically. The scrollpane should start out empty and add the panels.
The GuiConstructor is where i make the window.
My problem is that if I don't comment out the setSize in the GuiConstructor, the window starts out very small.
Secondly, when i press the add button, it doesn't add the panels.
public GuiConstructor(){
super(APPLICATION_NAME);
setLayout(new BorderLayout());
LoopControlWindow loopwin = new LoopControlWindow(connect);
add(loopwin , BorderLayout.NORTH);
pack();
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
//this.setSize(500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public class LoopControlWindow extends JPanel {
IConnector connect;
public LoopControlWindow(IConnector connect) {
super(new BorderLayout());
this.connect = connect;
initPane();
}
private void initPane() {
JPanel panel = new JPanel(new GridLayout(3,1));
FolderSearchComp fsc = new FolderSearchComp(connect);
JScrollPane scrollPane = new JScrollPane();
JButton button = new JButton("Add");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.add(new FolderSearchComp(connect));
scrollPane.getViewport().setView(panel);
}
});
scrollPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setViewportBorder(new LineBorder(Color.BLACK));
add(scrollPane, BorderLayout.CENTER);
add(button, BorderLayout.SOUTH);
}
This is typical of this style of GUI app. You need to tell the layout manager how big to make the Window initialy without using setSize(). The way to do this is to override getPreferredSize() to return a default size. In your case:
public LoopControlWindow extends JPanel {
private Dimension size;
public LoopControlWindow() {
Preferences prefs = Preferences.userNodeForPackge("your.java.package");
size = new Dimension(prefs.getInt("width", 800), prefs.getInt("height", 600));
}
public Dimension getPreferredSize() {
return size;
}
}
By doing it this way you can store the user preferences for the window dimensions but also provide sensible defaults to start.
You should also make sure that this JPanel is your main panel and is added to the JFrame at BorderLayout.CENTER to ensure that your window gets drawn properly. All other panels should be somewhere inside this one.
Once you have this set up calling pack() will work correctly.
For your first problem, you need to specify a size for the initial JFrame(). One way is to call setSize as you are doing. Another is to override getPreferredSize() to return the default size. And one other option is to find the size of the user's monitor and set the JFrame to be a percentage of that size. That way you can ensure your window always fits on your user's screen.
int height = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration().
getBounds().height;
height = (int) (height * .85);
int width = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration().
getBounds().width;
width = (int) (width * .85);
frame.setSize(width, height);
Second, you need to call revalidate() and repaint() anytime you add or remove from a layout in order to see the changes.
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.add(new FolderSearchComp(connect));
scrollPane.getViewport().setView(panel);
revalidate();
repaint();
}
});
One note on border layout. The components in it will not resize with your JFrame. Whatever component that is placed in BorderLayout.CENTER will, however. That component will grow to fill all extra space as the JFrame grows. It will also be the component that shrinks when the JFrame windows gets smaller.

java swing how to restrict JScrollPane to only vertical

Check out if you can help on this.
I need to restrict the scrolling to only vertical when using JScrollPane.
REMEMBER: not disabling the hortizontal scroll bar by using HORIZONTAL_SCROLLBAR_NEVER, which just disable horizontal. And i need is the components should not go beyond the window horizontally.
Add this to the container within the JScrollPane:
#Override
public java.awt.Dimension getPreferredSize() {
int h = super.getPreferredSize().height;
int w = getParent().getSize().width;
return new java.awt.Dimension(w, h);
}
At first I suggest you to check this out.
http://www.java-tips.org/java-se-tips/javax.swing/how-to-use-a-scrollbar-in-both-vertical-and-horizontal-dire.html
and you can actually try these lines of codes as well:
public class AddScroll
{
public static void main(String[] args)
{
JPanel panel = new JPanel();
JScrollPane scrollBar = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JFrame frame = new JFrame("AddScrollBarToJFrame");
frame.add(scrollBar);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}

JLayeredPane not respecting layers

I have a JLayeredPane. My program works something like this:
JPanel p1 = new JPanel(new BoxLayout(p1, BoxLayout.X_AXIS));
JPanel p2 = new JPanel(new BoxLayout(p2, BoxLayout.Y_AXIS));
JLayeredPane lp = new JLayeredPane();
lp.add(p1, 1);
lp.add(p2, 0);
Both p1 and p2 have components like buttons, etc...
The issue is that when I add both JPanels to the JLayeredPane, NOTHING appears.
I tried changing the layout of the JLayeredPane().
For example, I did:
lp.setLayout(new BoxLayout(lp, BoxLayout.X_AXIS));
Then, the JPanels do show, but they are shown adjacent, not respecting the layers of the JLayeredPane.
Am I forced to use a null layout?
How can I make my JLayeredPane respect the layers and show my two BoxLayout JPanels correctly?
When I give my JLayeredPane a layout, it shows the panels, but it is not respecting the layers at all.
You need a layout manager which understands the Z-Axis. The default layout managers don't understand the Z-Axis of the JLayeredPane.
If you simply want to overlay stuff on top of each other you can use a LayoutManager like this:
JLayeredPane layeredFooPane = new JLayeredPane();
// The magic!
layeredFooPane.setLayout(new LayeredPaneLayout(layeredPane));
// Add components:
layeredFooPane.add(fooComponent, new Integer(JLayeredPane.DEFAULT_LAYER + 10));
layeredFooPane.add(barComponent, JLayeredPane.DEFAULT_LAYER);
LayoutManager Class:
public class LayeredPaneLayout implements LayoutManager {
private final Container target;
private static final Dimension preferredSize = new Dimension(500, 500);
public LayeredPaneLayout(final Container target) {
this.target = target;
}
#Override
public void addLayoutComponent(final String name, final Component comp) {
}
#Override
public void layoutContainer(final Container container) {
for (final Component component : container.getComponents()) {
component.setBounds(new Rectangle(0, 0, target.getWidth(), target.getHeight()));
}
}
#Override
public Dimension minimumLayoutSize(final Container parent) {
return preferredLayoutSize(parent);
}
#Override
public Dimension preferredLayoutSize(final Container parent) {
return preferredSize;
}
#Override
public void removeLayoutComponent(final Component comp) {
}
}
The JLayeredPane acts as if it were using null layout. You must specify your JPanel's size and position when adding it to the JLayeredPane. One of the few times I'll recommend this:
JPanel p1 = new JPanel(new BoxLayout(p1, BoxLayout.X_AXIS));
JPanel p2 = new JPanel(new BoxLayout(p2, BoxLayout.Y_AXIS));
JLayeredPane lp = new JLayeredPane();
lp.add(p1, 1);
lp.add(p2, 0);
p1.setSize(lp.getPreferredSize());
p2.setSize(lp.getPreferredSize());
I was having a similar problem. Instead of passing the layer when you add the panes, try to do it separately:
lp.setLayer(p1, 1);
lp.setLayer(p2, 0);
lp.add(p1);
lp.add(p2);
Layers must be defined before adding components.
You can also try to use JLayeredPane.DEFAULT_LAYER instead of 0.
In my case, my JLayeredPane had GridBagLayout, I don't know if it works with default layout.

How to get JScrollPanes within a JScrollPane to follow parent's resizing

So I have a bunch of JTables. Each JTable is inside a JScrollPane. I'm then adding each of these JScrollPanes to a JPanel. I'm then adding this JPanel to a JScrollPane then that to another JPanel with BorderLayout. The larger JScrollPane properly resizes with its parent, but each of the smaller JScrollPanes have constant height, which is larger than the window when it is small. How can I get each of the children JScrollPanes to resize with the height of the window/their parent?
I've tried adding more intermediary JPanels with FlowLayout, BorderLayout, and nothing seems to work.
Here's some relevant code:
public class MyPanel extends JPanel
{
public MyPanel()
{
super(new BorderLayout());
JPanel panel = new JPanel();
for (int i = 0; i < 5; i++)
{
// View extends JTable
panel.add(new JScrollPane(new View(new Model())));
}
add(new JScrollPane(panel));
}
}
I'm really just trying to get a bunch of tables with scrollbars horizontally next to each other inside a larger panel with a horizontal scrollbar. And I want all that stuff to resize appropriately when the window size changes.
more code:
final MyPanel panel = new MyPanel();
final JTabbedPane tabView = new JTabbedPane();
tabView.add(...);
tabView.add("foo", panel);
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, ..., tabView);
this.add(splitPane); // this extends JFrame
You can use a BoxLayout. If you want the opposite: some table being fixed, you can wrap it with constraint Box.createRigidArea(new Dimension(100, 100)) .

Categories

Resources