Java Swing Scrollpane not scrolling - java

I want to be able to scroll down a dynamically generated list of movies. I tried adding a Scrollpane.
I have a navigation bar at the page start and in the center a jpanel with all the movies.
You can recreate this example by using this code:
private static JFrame frame;
public static void main(String[] args) throws HeadlessException {
frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setBackground(new Color(32, 32, 32));
JPanel navigationPanel = createNavigationBar();
frame.add(navigationPanel, BorderLayout.PAGE_START);
JPanel moviePanel = createMoviePanel();
frame.add(moviePanel, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(1920, 1080));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Example App");
frame.pack();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
// MoviePanel Class
public static JPanel createMoviePanel() {
JPanel parentMoviePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 25));
JPanel contentPanel = new JPanel(new GridLayout(0, 1));
JPanel moviePanel = new JPanel(new GridLayout(0, 9, 8, 5));
JScrollPane scrollPane = new JScrollPane(moviePanel);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(0, 0));
scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0));
parentMoviePanel.setBackground(new Color(32, 32, 32));
contentPanel.setBackground(new Color(32, 32, 32));
moviePanel.setBackground(new Color(32, 32, 32));
final File root = new File("");
for (int i = 0; i < 70; i++) {
// Get the image and scale it down
BufferedImage movieCover=new BufferedImage(150,200,BufferedImage.TYPE_INT_RGB);
Graphics2D g2d=(Graphics2D)movieCover.getGraphics();
g2d.setColor(Color.GRAY);
g2d.fillRect(0,0,movieCover.getWidth(),movieCover.getHeight());
// Create button and change settings
JButton movieButton = new JButton("Movie " + i, new ImageIcon(movieCover));
movieButton.setMargin(new Insets(0, 0, 0, 0));
movieButton.setPreferredSize(new Dimension(180, 250));
movieButton.setForeground(Color.WHITE);
movieButton.setContentAreaFilled(false);
movieButton.setBorderPainted(false);
movieButton.setFocusPainted(false);
movieButton.setHorizontalTextPosition(JButton.CENTER);
movieButton.setVerticalTextPosition(JButton.BOTTOM);
moviePanel.add(movieButton);
scrollPane.revalidate();
}
contentPanel.add(moviePanel);
contentPanel.add(scrollPane);
parentMoviePanel.add(contentPanel);
return parentMoviePanel;
}
// Navbar Class
public static JPanel createNavigationBar() {
JPanel navBar = new JPanel();
navBar.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 20));
navBar.setBackground(new Color(25, 25, 25));
JButton homeButton = new JButton("Home");
homeButton.setContentAreaFilled(false);
homeButton.setBorderPainted(false);
homeButton.setFocusPainted(false);
JButton movieButton = new JButton("Movies");
movieButton.setContentAreaFilled(false);
movieButton.setBorderPainted(false);
movieButton.setFocusPainted(false);
// Add all the buttons to the navbar
navBar.add(homeButton);
navBar.add(movieButton);
return navBar;
}
What I'm trying to do is to scroll down this list of movies, using my mouse wheel without seeing any kind of scrollbar. It should look exactly how it looks now, but I want to be able to scroll down and see all the movies.
I don't know why it isn't working that's why I'm asking here in hope someone can explain to me what I'm doing wrong.

Your usage of a scroll pane is incorrect.
A Swing component can only have a single parent. The following code is creating the scroll pane with a child component. However you then remove the moviePanel from the scroll pane when you add it to the content pane.
So the scroll pane has no child component and will never work.
JScrollPane scrollPane = new JScrollPane(moviePanel);
...
contentPanel.add(moviePanel);
contentPanel.add(scrollPane);
However, even that won't solve your problem because you are now using a FlowLayout on your top level panel so all the child components will always be displayed at their preferred size so there is no need for scroll bars.
Get rid of all the scroll pane logic in your createMoviePanel() method.
Instead you probably want to add the scroll pane to the content pane:
//frame.add(moviePanel, BorderLayout.CENTER);
frame.add(new JScrollPane(moviePanel), BorderLayout.CENTER);
Now the scroll pane will dynamically resize as the frame size changes. Scrollbars will then appear as required.

Related

Trying to add ScrollPane in Jpanel with null layout inside BorderLayout

I am trying to add a scrollbar in jpanel with null layout.
I want to create a form. This should should display few buttons at the bottom at all times.Any content inside form should maintain it's size and ratio even if the parent container is resized.
Here is what I've come with. I have a panel with borderlayout and added buttons at the south of border. Then created another jpanel to contain form that is added at the center of parent jpanel. Since I want form to maintain it's ratio I went with null layout for inner panel. But I want it to display scrollbar when content is not fully visible. enter image description here
Now adding inner jpanel into scrollpane and adding scrollpanel into parent panel (.add(scrollpane, BorderLayout.CENTER)) doesn't give desired format.
Is there any thing that I can do to get desired format?
Here is code Sample:
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(new Dimension(1000, 700));
Container c = jFrame.getContentPane();
c.setLayout(new BorderLayout());
bottomPanel(c);
centerPanel(c); //scrollbar should go in this panel
jFrame.setVisible(true);
}
private static void centerPanel(Container c) {
JPanel centerPanel = new JPanel();
centerPanel.setLayout(null);
JButton button = new JButton("This jObject should not resize when window resizes and also should maintain relative position.");
button.setBounds(new Rectangle(10, 10, 600, 50));
JButton button1 = new JButton("Just like it works in this code. Just Add ScrollPane to centerPanel That is in green backround");
button1.setBounds(new Rectangle(10, 70, 600, 50));
JButton button2 = new JButton("For clearity");
button2.setBounds(new Rectangle(10, 130, 600, 50));
centerPanel.add(button);
centerPanel.add(button1);
centerPanel.add(button2);
centerPanel.setBackground(Color.GREEN);
c.add(centerPanel, BorderLayout.CENTER);
}
private static void bottomPanel(Container c) {
JPanel bottomPanel = new JPanel(); //Buttons that goes at the bottom of screen will go in here
JPanel bottomInnerPanel = new JPanel();
bottomInnerPanel.setLayout(new BorderLayout());
bottomPanel.setLayout(new GridLayout());
bottomInnerPanel.add(new JButton("Add"), BorderLayout.WEST);
bottomInnerPanel.add(new JButton("Search"), BorderLayout.EAST);
bottomPanel.add(bottomInnerPanel);
bottomPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
c.add(bottomPanel, BorderLayout.SOUTH);
}

Resizing JFrame while shrinking a scrollpane acordingly

I currently have a JFrame to start fullscreen, inside this jframe i have a jpanel, this jpanel includes a vertical scrollpane. Now if i resize my jframe vertically it just kinda removes the bottom part of the jpanel. Is there any way to just shrink the jscrollpane.
im currently using flowlayout for the jframe,
Scrollbar appear automatically when the preferred size of the components added to the scroll pane area greater than the size of the scroll pane.
The FlowLayout will wrap components to a new row, but it always gives the preferred size as the size required to fit the components on a single row, so the preferred height will never change.
To solve this problem you can use the Wrap Layout which simple extend FlowLayout to recalculate the preferred size when wrapping occurs.
The JPanel consists of 3 other panels, a top panel, a scrollpane in the middle and a botpanel. The top and bot panel are just button and checkboxes and stuff
private void initPane() {
createFolderCompPanel();
createBotPanel();
createTopPanel();
createScrollPane();
createTotalPanel();
add(totalPanel);
}
private void createFolderCompPanel() {
//Create folderCompPanel
folderCompPanel = new JPanel();
folderCompPanel.setLayout(new BoxLayout(folderCompPanel, BoxLayout.Y_AXIS));
folderCompPanel.add(Box.createVerticalGlue());
}
private void createTotalPanel() {
//Create TotalPanel
totalPanel = new JPanel();
totalPanel.setLayout(new BoxLayout(totalPanel, BoxLayout.Y_AXIS));
totalPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
totalPanel.add(topPanel);
totalPanel.add(scrollPane);
totalPanel.add(botPanel);
}
private void createScrollPane() {
//Create ScrollPane
scrollPane = new JScrollPane();
scrollPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setViewportBorder(BorderFactory.createEtchedBorder());
scrollPane.getVerticalScrollBar().setUnitIncrement(6);
}
private void createBotPanel() {
//Create BotPanel
botPanel = new JPanel();
botPanel.setLayout(new BoxLayout(botPanel, BoxLayout.X_AXIS));
//AddButton
addButton = new JButton("Add");
addButton.setEnabled(false);
addButton.addActionListener(this);
//SaveButton
saveButton = new JButton("Save");
saveButton.setEnabled(false);
saveButton.addActionListener(this);
//CancelButton
cancelButton = new JButton("Cancel");
cancelButton.setEnabled(false);
cancelButton.addActionListener(this);
lblTotalLength = new JLabel("Total Length: " + totalLength);
botPanel.add(Box.createRigidArea(new Dimension(10, 0)));
botPanel.add(addButton);
botPanel.add(Box.createRigidArea(new Dimension(10, 0)));
botPanel.add(lblTotalLength);
botPanel.add(Box.createHorizontalGlue());
botPanel.add(saveButton);
botPanel.add(Box.createRigidArea(new Dimension(10, 0)));
botPanel.add(cancelButton);
botPanel.add(Box.createRigidArea(new Dimension(10, 0)));
}
private void createTopPanel() {
//Create TopPanel
topPanel = new JPanel();
topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
//create deletedisplay button
deleteDisplayButton = new JButton("Delete Display");
deleteDisplayButton.addActionListener(this);
deleteDisplayButton.setEnabled(false);
//create displaybox
displayBox = new JComboBox();
displayBox.addActionListener(this);
displayBox.addItem("<None>");
for (String s : connect.getAllDisplays()) {
displayBox.addItem(s);
}
displayBox.setMaximumSize(displayBox.getPreferredSize());
//create newdisplay button
newDisplayButton = new JButton("New Display");
newDisplayButton.addActionListener(this);
topPanel.add(Box.createRigidArea(new Dimension(10, 0)));
topPanel.add(displayBox);
topPanel.add(Box.createHorizontalGlue());
topPanel.add(newDisplayButton);
topPanel.add(Box.createRigidArea(new Dimension(5, 0)));
topPanel.add(deleteDisplayButton);
topPanel.add(Box.createRigidArea(new Dimension(10, 0)));
}
this is the panel i add to the jframe
public GuiConstructor(){
super(APPLICATION_NAME);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setMinimumSize(new Dimension(630, 600));
setLayout(new FlowLayout(FlowLayout.LEFT));
LoopControlWindow folderSearch = new LoopControlWindow(connect, this);
add(folderSearch);
pack();
setLocationRelativeTo(null);
setResizable(true);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

Dynamically resize outer JPanel depending on JPanels inner JTextPane height

I have a JTextPane inside a JPanel, this JTextPane is at runtime being populated with text. I want the JPanel that is holding the JTextPane to dynamically change in height when JTextPane gets more than one line of text.
This is what ive got so far:
pnlChatMsgs = new JPanel(new BorderLayout());
pnlChatMsgs.setBackground(new java.awt.Color(244, 244, 244));
pnlMainTable.add(pnlChatMsgs, c);
pnlMidLiveType = new JPanel(new BorderLayout());
pnlMidLiveType.setPreferredSize(new Dimension(100, 30));
JTextPane.setFont(new java.awt.Font("Lucida Grande", 0, 13));
JTextPane.setText("<html></html>");
JTextPane.setContentType("text/html");
JTextPane.setForeground(new java.awt.Color(153, 153, 153));
JTextPane.setBackground(new java.awt.Color(250, 250, 250));
pnlMidLiveType.add(JTextPane, BorderLayout.NORTH);
pnlChatMsgs.add(pnlMidLiveType, BorderLayout.SOUTH);
pnlMidLiveType.setVisible(false);
So when JTextPane grows in size i want to change the height of the pnlMidLiveType JPanel.
How could i accomplish this?
Consider the following example. It demonstrates expandable JFrame and JPanel:
final JFrame frame = new JFrame();
JPanel panel = new JPanel(new BorderLayout());
JTextPane pane = new JTextPane();
pane.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
frame.pack();
}
});
panel.add(pane, BorderLayout.CENTER);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
JFrame#pack() triggers resize event and does the trick.

Need opinions about this basic layout

I guess this is a simple question... basically it's about layout considerations. So let consider the code below, I get this:
.
public class TestCode_Web {
public static void main(String[] args) {
JFrame window = new JFrame("Test");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(200, 300);
// Inner panel ---------------------------------------------------------
JPanel innerPanel = new JPanel(new BorderLayout());
innerPanel.setBackground(new Color(250, 250, 200));
window.add(innerPanel);
// Northern panel ------------------------------------------------------
JPanel panelN = new JPanel(new BorderLayout());
JLabel labelN = new JLabel("Label");
panelN.add(labelN, BorderLayout.WEST);
panelN.setBackground(new Color(200, 250, 250));
innerPanel.add(panelN, BorderLayout.NORTH);
// Center panel --------------------------------------------------------
JPanel panelC = new JPanel();
panelC.setBackground(new Color(250, 200, 250));
JPanel panelCheckBoxes = new JPanel(new GridLayout(0, 1));
final JCheckBox c1 = new JCheckBox("C1");
final JCheckBox c2 = new JCheckBox("C2");
final JCheckBox c3 = new JCheckBox("C3");
panelCheckBoxes.add(c1);
panelCheckBoxes.add(c2);
panelCheckBoxes.add(c3);
int width = panelCheckBoxes.getPreferredSize().width;
int height = panelCheckBoxes.getPreferredSize().height;
panelCheckBoxes.setPreferredSize(new Dimension(width, height));
panelC.add(panelCheckBoxes);
innerPanel.add(panelC, BorderLayout.CENTER);
// Southern panel --------------------------------------------------------
JPanel panelS = new JPanel(new BorderLayout());
JLabel labelS = new JLabel(String.valueOf(width) + "/" + String.valueOf(height));
panelS.add(labelS, BorderLayout.WEST);
panelS.setBackground(new Color(250, 250, 200));
innerPanel.add(panelS, BorderLayout.SOUTH);
// ...
window.setVisible(true);
}
}
What I would like is to have this:
How could I achieve that ? I guesss there are several ways, I'm waiting for your diverse proposals...
One way to do this would be to overwrite the getPreferredSize() method of panelCheckBoxes to return panelC's width. This way, panelCheckBoxes' size will automatically adapt to the width of panelC.
final JPanel panelC = new JPanel();
// [...]
JPanel panelCheckBoxes = new JPanel(new GridLayout(0, 1)) {
public Dimension getPreferredSize() {
return new Dimension(panelC.getWidth(),
super.getPreferredSize().height);
}
};
For accessing panelC inside the anonymous inner class, it has to be final (i.e., after initialization, the panelC variable can not be assigned a new value, which is no problem in your case).
Just setting the preferredSize at that point in the constructor will not work, since (1) the size is not known yet, and (2) it might change when the window is resized. You could, however, use setPreferredSize after the call to window.setVisible(true);, when panelC got a size:
// after window.setVisible(true);
panelCheckBoxes.setPreferredSize(new Dimension(panelC.getWidth(),
panelCheckBoxes.getHeight()));
However, note that this way panelCheckBoxes still won't resize when you resize the window.
If you just want the checkboxes to be aligned to the left (but not necessarily stretch over the whole width), a simpler way would be to put panelC into the WEST container of the BorderLayout. Assuming that the colors are only for debugging and in the end everything will be the same color, you won't see a difference.
Finally, for more complex layouts you might want to check out GridBadLayout. It takes some getting used to, but once mastered, it's worth the effort.

horizontal split pane resize with window

I have a horizontal split pane that contains a vertical split pane. When the window shows up i want the vertical split pane in the top of the horizontal split pane to be split in the middle. I want the horizontal divider to be in the middle.
I have that working, however, i also want to the horizontal split pane to change its size when the window is maximized. (It currently does not.)
I also have a button box below the horizontal pane and would like it to always be visible when the window is resized. Currently when the window launches i can see everything in the horizontal split. I am unable to see the buttons, because they do not fit in the preferred size of the window (800, 600). But i would like everything to show up in the window automatically and stay Glue'd to the border of the window when it is resized...
How can i do this?
Thanks!
Below is the code i am currently using. I call the create methods in a controller. createView is called first then the rest in sequential order.
public void createView() {
dialog = new JFrame();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
dialog.setAlwaysOnTop(true);
dialog.setBounds(0, 0, 800, 600);
dialog.setMinimumSize(new Dimension(800, 600));
dialog.setPreferredSize(new Dimension(800, 600));
dialog.setResizable(true);
dialog.setTitle("MJLA Class Control Panel");
contentPanel = new JPanel();
// contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
contentPanel.setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
dialog.getContentPane().add(contentPanel, BorderLayout.CENTER);
classQuizSRTSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
contentPanel.add(classQuizSRTSplit, BorderLayout.NORTH);
classQuizSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
classQuizSRTSplit.setTopComponent(classQuizSplit);
// classQuizHBox = Box.createHorizontalBox();
// contentPanel.add(classQuizHBox);
sRTHBox = Box.createHorizontalBox();
contentPanel.add(sRTHBox);
buttonBox = Box.createHorizontalBox();
contentPanel.add(buttonBox, BorderLayout.SOUTH);
refreshButton = new JButton("Refresh");
buttonBox.add(refreshButton);
doneButton = new JButton("Done");
buttonBox.add(doneButton);
this.validateView();
}
public void createClassTablePanel() {
this.classTablePanel = new JPanel();
this.classTablePanel.setBorder(BorderFactory.createLineBorder(Color.black, 3));
this.classTablePanel.setPreferredSize(new Dimension(300, 300));
this.classTablePanel.setLayout(new BorderLayout());
// this.classQuizHBox.add(classTablePanel);
this.classQuizSplit.setLeftComponent(classTablePanel);
classTableModel = cPModel.getClassTableModel();
classTable = new JTable(this.classTableModel);
classTable.getSelectionModel().addListSelectionListener(this);
JScrollPane scrollPane = new JScrollPane(classTable);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
classTablePanel.add(scrollPane, BorderLayout.CENTER);
this.validateView();
}
public void createQuizTablePanel() {
this.quizTablePanel = new JPanel();
this.quizTablePanel.setBorder(BorderFactory.createLineBorder(Color.black, 3));
this.quizTablePanel.setPreferredSize(new Dimension(300, 300));
this.quizTablePanel.setLayout(new BorderLayout());
// this.classQuizHBox.add(quizTablePanel);
this.classQuizSplit.setRightComponent(quizTablePanel);
quizTableModel = cPModel.getQuizTableModel();
this.quizSorter = new TableRowSorter<DefaultTableModel>(quizTableModel);
quizTable = new JTable(this.quizTableModel);
quizTable.getSelectionModel().addListSelectionListener(this);
quizTable.setRowSorter(quizSorter);
JScrollPane scrollPane = new JScrollPane(quizTable);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
quizTablePanel.add(scrollPane, BorderLayout.CENTER);
Box buttonHBox = Box.createHorizontalBox();
quizTablePanel.add(buttonHBox, BorderLayout.SOUTH);
addQuizButton = new JButton("Add Quiz");
buttonHBox.add(addQuizButton);
removeQuizButton = new JButton("Remove Quiz");
buttonHBox.add(removeQuizButton);
editQuizButton = new JButton("Edit Quiz");
buttonHBox.add(editQuizButton);
this.validateView();
}
public void createStudentRecordTablePanel() {
this.studentRecordTablePanel = new JPanel();
this.studentRecordTablePanel.setBorder(BorderFactory.createLineBorder(Color.black, 3));
this.studentRecordTablePanel.setLayout(new BorderLayout());
// this.sRTHBox.add(studentRecordTablePanel);
this.classQuizSRTSplit.setBottomComponent(studentRecordTablePanel);
this.studentRecordTableModel = cPModel.getStudentRecordTableModel();
this.sRTSorter = new TableRowSorter<DefaultTableModel>(studentRecordTableModel);
sRTTable = new JTable(this.studentRecordTableModel);
sRTTable.setRowSorter(sRTSorter);
JScrollPane scrollPane = new JScrollPane(sRTTable);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
studentRecordTablePanel.add(scrollPane, BorderLayout.CENTER);
Box buttonHBox = Box.createHorizontalBox();
studentRecordTablePanel.add(buttonHBox, BorderLayout.SOUTH);
editGradeButton = new JButton("Edit Grade");
buttonHBox.add(editGradeButton);
generateReportButton = new JButton("Generate Report");
buttonHBox.add(generateReportButton);
this.validateView();
}
Another issue.
That fixed one of the problems #TrashGod. However, how can i make the horizontal split pane resize its component to fit the new size of the window, instead of their being that big gap between the done and refresh button and the bottom of the horizontal split pane?
I was thinking that i would have to listen for an event for when the window size changes and then call the pack() method when that happens, is that the only way or would that even work? (Just tested this, it did not work... just puts everything back to preferred sizes. duh)
Initial look.
After window maximized.
You might look at setResizeWeight(); a value of 0.5 should distribute the space evenly.
The pack() method "Causes this Window to be sized to fit the preferred size and layouts of its subcomponents." BorderLayout.NORTH and BorderLayout.SOUTH seem like suitable layouts for staying with the divider.
For additional help, please provide an sscce that exhibits the problem.

Categories