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

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)) .

Related

JFrame turns blue when adding tabs

I currently have a Jframe that I want to add to a tab instead.
(I used a frame just for testing purposes, to make sure the look and feel is correct, but when trying to add it to a JTabbedPane, the frame starts to look blue (weird top aswell).
I tried copying my settings from my original frame to the new frame but that did not help.
JTabbedPane tabs = new JTabbedPane();
tabs.addTab("1", frame.getContentPane());
JFrame FinalFrame = new JFrame();
FinalFrame.setDefaultLookAndFeelDecorated(true);
FinalFrame.setSize(WIDTH, HEIGTH);
FinalFrame.setLocation(100, 150);
FinalFrame.setTitle("Primal-Pvm Notification center");
FinalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FinalFrame.add(tabs);
Side by side view of the problem and the frame before adding it to the tab:
Edit: Answer by George Z. helped me out a lot.
Like he said to solve the problem:
Don't add things to your main frame but add them to a Jpanel and add that to a JTabbedPane.
If you have a Jpanel that you are adding to a tab that contains an override in the paintComponent, you have to create that class as the Jpanel so:
JPanel panel = new LineDrawer([Enter parameters]);
panel.setLayout([Enter Layout]);
The way you are approaching this seems to be pretty complex hence this weird behavior. (Looks like a look and feel problem? - show the part of the code that sets it)
However, I suggest you to create only one JFrame (this question explains why you should do that), set the layout of its content pane to BorderLayout and keep it like this. Its a rare situation to mess up with content panes. After that create independent JPanels representing the tab(s) you would like to have. Finally create a JTabbedPane with these panels and add it to the content frame of the JFrame.
A small example would be:
public class TabbedPanelExample extends JFrame {
public TabbedPanelExample() {
super("test");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
JTabbedPane pane = new JTabbedPane();
pane.addTab("FirstTab", createFirstTab());
pane.addTab("SecondTab", createSecondTab());
add(pane);
setSize(400, 400);
setLocationRelativeTo(null);
}
private Component createFirstTab() {
JPanel panel = new JPanel(new FlowLayout());
panel.add(new JLabel("Some Component"));
panel.add(new JTextField("Some Other Component"));
return panel;
}
private Component createSecondTab() {
JPanel panel = new JPanel(new FlowLayout());
panel.add(new JLabel("Some Component"));
panel.add(new JButton("Some Other Component"));
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new TabbedPanelExample().setVisible(true);
});
}
}
Post edit based on this comment:
Well I do have a Jframe with a lot of elements added to it so it kinda
is a hassle to switch it all to panels;
A JFrame cannot have a lot of elements. You take a look on how to use root panes. The container that "has a lot of elements" of a JFrame is its rootpane which is mostly completed by its contentpane. When you frame.add(component), you add the component to its content pane. Guess what? A JFrame's content pane is a JPanel. So are a already to panels.
Now in order to make this work, try to do as i said and frame.setLayout(new BorderLayout(); //changes layout to contentpane. Assuming you have a bunch of components (lets say comp1,comp2) and you are adding them like:
frame.add(comp1);
frame.add(comp2);
You must do the following in order to make it clear. Create a JPanel and instead of frame.add(comp1), do panel.add(comp1). So this JPanel has all the components you added in JFrame. After that create your JTabbedPane:
JTabbedPane pane = new JTabbedPane();
pane.addTab("tab", panel);
and finally add this pane to the content pane of your JFrame:
frame.add(pane);
In conclusion, you will move all the components you have added to your frame into a JPanel, add this JPanel to a JTabbedPane, and finally add this JTabbedPane to the frame (contentpane). Frame has only one component.

Centering a fixed size canvas in a JFrame

I'm in the process of creating a circuit editor (similar to any regular paint software with a basic menu and a canvas with specifiable dimensions). I am currently trying to transform the previously unscrollable canvas (JPanel) to a scrollable one.
The obvious design error at the moment is that while the scrollbars seem to correctly reflect the internal size of the canvas (which can of course be way bigger than the JFrame), due to the canvas JPanel being added in the CENTER of the BorderLayout of the master panel, it always resizes along with the JFrame.
public final class MainFrame extends JFrame
{
public MainFrame()
{
JPanel menuPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
// Populate Menu Panel
// ...
JPanel canvasPanel = new JPanel();
canvasPanel.setBackground(Color.white);
Dimension canvasDims = new Dimension(800,600);
canvasPanel.setPreferredSize(canvasDims);
canvasPanel.setMinimumSize(canvasDims);
canvasPanel.setMaximumSize(canvasDims);
JScrollPane canvasScrollPane = new JScrollPane(
canvasPanel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JPanel masterPanel = new JPanel(new BorderLayout());
masterPanel.add(menuPanel, BorderLayout.NORTH);
masterPanel.add(canvasScrollPane, BorderLayout.CENTER);
setContentPane(masterPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1200, 700);
setMinimumSize(new Dimension(500, 500));
setLocationRelativeTo(null);
setVisible(true);
}
I've read quite a few posts regarding centering JPanels and scrollbars but with both complexities added together, things might be a bit more complicated as I haven't yet found a solution.
What I'm really trying to achieve is to have the canvas' JPanel fixed in whatever size the user might have specified and centered in the middle as well as the scrollbars behaving as one would expect like in the beloved windows' paint:
How would you go about doing this/fixing my design? Any help would be greatly appreciated!
P.S. Happy new Year :)
JPanel fixed in whatever size the user might have specified and centered in the middle as well as the scrollbars behaving as one would expect
So you need to nest panels so the canvas panel can be displayed at its preferred size, while the parent panel resizes with the size of the frame.
An easy way to do this is with a JPanel that uses a GridBagLayout. Then you add the canvas panel to this panel using the default GridBagConstraints.
So the basic structure of the panels would be:
JPanel canvas = new JPanel();
canvas.setPreferredSize( new Dimension(300, 300) );
canvas.setBackground(Color.RED);
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(canvas, new GridBagConstraints() );
frame.add(new JScrollPane(wrapper));
Note: there is no need for your "masterPanel". The default layout manager for the content pane of a JFrame is a BorderLayout, so you just add the "menuPanel" and "scrollPane" directly to the frame with the proper BorderLayout constraints.

Swing flow layout break element in scrollable JPanel

I'm trying to put multiple JPanel cards into my main panel. and if new card panel does not fit I want it to be placed in next line. In the image below, you see that all my card panels go to right and if I set HORIZONTAL_SCROLLBAR_ALWAYS horizontal scroll works. So here I want 4 card panel in each line of my main panel so that vertical scroll works.
public class PanelTraining extends JPanel{
private static final long serialVersionUID = 1L;
public PanelTraining(List<FccMeta> ffcms) {
super(new BorderLayout()); // set layout to absolute
setPreferredSize(new Dimension(880, 580));
setBorder(new LineBorder(Color.decode("#A11E1E"),1, true));
JPanel pnlChart = new JPanel();
pnlChart.setPreferredSize(new Dimension(860, 180));
pnlChart.setBackground(Color.YELLOW);
add(pnlChart, BorderLayout.NORTH);
JPanel pnlTrSet = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
//pnlTrSet.setSize(860, 380);
for (FccMeta fccMeta : ffcms) {
JPanel pnlCard = new MyCustomPanelCard();
pnlTrSet.add(pnlCard);
}
JScrollPane scroll = new JScrollPane(pnlTrSet);
//scroll.setPreferredSize(new Dimension(860, 380));
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
add(scroll, BorderLayout.CENTER);
}
}
EDIT according to the answer given below. I changed my implementation by this Class
ScrollablePanel pnlTrSet = new ScrollablePanel(new FlowLayout());
pnlTrSet.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
pnlTrSet.setScrollableBlockIncrement(
ScrollablePanel.VERTICAL, ScrollablePanel.IncrementType.PIXELS, 230);
You need to implement the Scrollable interface of your panel to have the width fixed to the size of the viewport of the scrollpane.
Basically you need to override the getScrollableTracksViewportWidth() method to return “true”.
An easy way to do this is to use the Scrollable Panel. It has a method that allows you to control this property.
Edit:
The above will only prevent the horizontal scrollbar from appearing. However the FlowLayout will continue to display all the buttons on a single row because the preferred size calculation of the panel is still not correct.
To get the buttons to wrap, you must replace the FlowLayout of your panel with the Wrap Layout. The Wrap Layout will recalculate the preferred height of the panel correctly so that the components can wrap and the vertical scrollbar can appear.

Adding Component to JScrollPane has weird behavior

Executing this code produces very strange behavior.
When running, try resizing and typing to see what I mean.
import java.awt.BorderLayout;
import javax.swing.*;
public class FrameWithScrollPanel extends JFrame {
public static void main(String[] args) {
FrameWithScrollPanel myFrame = new FrameWithScrollPanel();
}
public FrameWithScrollPanel()
{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JTextArea textArea1 = new JTextArea(5, 30);
JTextArea textArea2 = new JTextArea(5, 30);
JPanel jPanel = new JPanel();
jPanel.setSize(400,400);
jPanel.setLayout(new BorderLayout());
jPanel.add(textArea1, BorderLayout.NORTH);
jPanel.add(textArea2, BorderLayout.SOUTH);
JScrollPane scrollPane = new JScrollPane();
scrollPane.add(jPanel);
getContentPane().add(scrollPane, BorderLayout.CENTER);
pack();
setVisible(true);
}
}
Now, replace these 2 lines :
JScrollPane scrollPane = new JScrollPane();
scrollPane.add(jPanel);
With this one line and the behavior is as expected.
JScrollPane scrollPane = new JScrollPane(jPanel);
Based on the documentation the JScrollPane constructor accepts a Component and so does the add().
Why the difference in behavior?
This is wrong:
scrollPane.add(jPanel);
Since you're replacing the JScrollPane's all important viewport with this add, preventing it from functioning. You should instead be adding this to the JScrollPane's viewport as per the JScrollPane tutorial and JScrollPane API:
scrollPane.setViewportView(jPanel);
or
scrollPane.getViewport().add(jPanel);
Moral of the story: when in doubt, read the docs.
Note that if you pass the jPanel into the JScrollPane's constructor,
JScrollPane scrollPane = new JScrollPane(jPanel);
it automatically places the component into the viewport for you.
Per the API:
public JScrollPane(Component view)
Creates a JScrollPane that displays the contents of the specified component, where both horizontal and vertical scrollbars appear whenever the component's contents are larger than the view.
Parameters:
view - the component to display in the scrollpane's viewport

Layout for displaying panels dynamically with scroll bar

In java, I have been trying to create a panel that can accept other panels with a scroll bar.
I tried using gridlayout, and this works fine, except for the fact that if I only add a few panels, it grows those panels to fit the size of the parent panel.
I tried using flowlayout, but this makes the panels flow horizontally as there is a scroll bar.
How do I make it so I can add panels to the parent panel starting at the top and make them always the same size(or their preferred size).
Also, when I add panels to the parent panel after an event, they do not appear until after I move or resize the form. How do I make it repaint? calling repaint() on it did not work.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
/** This lays out components in a column that is constrained to the
top of an area, like the entries in a list or table. It uses a GridLayout
for the main components, thus ensuring they are each of the same size.
For variable height components, a BoxLayout would be better. */
class ConstrainedGrid {
ConstrainedGrid() {
final JPanel gui = new JPanel(new BorderLayout(5,5));
gui.setBorder(new EmptyBorder(3,3,3,3));
gui.setBackground(Color.red);
JPanel scrollPanel = new JPanel(new BorderLayout(2,2));
scrollPanel.setBackground(Color.green);
scrollPanel.add(new JLabel("Center"), BorderLayout.CENTER);
gui.add(new JScrollPane(scrollPanel), BorderLayout.CENTER);
final JPanel componentPanel = new JPanel(new GridLayout(0,1,3,3));
componentPanel.setBackground(Color.orange);
scrollPanel.add(componentPanel, BorderLayout.NORTH);
JButton add = new JButton("Add");
gui.add(add, BorderLayout.NORTH);
add.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent ae) {
componentPanel.add(new JTextField());
gui.validate();
}
});
Dimension d = gui.getPreferredSize();
d = new Dimension(d.width, d.height+100);
gui.setPreferredSize(d);
JOptionPane.showMessageDialog(null, gui);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ConstrainedGrid cg = new ConstrainedGrid();
}
});
}
}
Assuming JScrollPane, see Sizing a Scroll Pane. For convenience, Scrollable clients such as JTable offer setPreferredScrollableViewportSize(), but you can always set the viewport's size explicitly.

Categories

Resources