I'm trying to display a series of buttons in a JScrollpane
. Reading around, I managed to exit with this code, but nothing is displayed. I do not understand a possible mistake. Thank you for help
As suggested I made some changes, I edited but not works
EDITED or I'm stupid, or here is some other problem. Here is my complete code with the output image
public class Main extends javax.swing.JFrame { private final JPanel gridPanel; public Main() { initComponents(); // EXISTING PANEL gridPanel = new JPanel(); JScrollPane scrollPane = new JScrollPane(gridPanel); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); JPanel borderLayoutPanel = new JPanel(new BorderLayout()); borderLayoutPanel.add(scrollPane, BorderLayout.CENTER); this.Avvio(); } private void Avvio() { JPanel pane = new JPanel(new GridBagLayout()); pane.setBorder(BorderFactory.createLineBorder(Color.BLUE)); pane.setLayout(new GridBagLayout()); for (int i = 0; i < 10; i++) { JButton button; GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.PAGE_START; button = new JButton("Button 1"); c.weightx = 0.5; c.gridx = 0; c.gridy = i; pane.add(button, c); button = new JButton("Button 2"); c.gridx = 1; c.gridy = i; pane.add(button, c); button = new JButton("Button 3"); c.gridx = 2; c.gridy = i; pane.add(button, c); } gridPanel.add(pane); gridPanel.revalidate(); gridPanel.repaint(); } }
4 Answers
Answers 1
Problems noted:
- Avvio - the pane layout was reset during each loop. Set it once before the loop.
- Avvio - the pane was added to the grid pane in each loop. Add it once after the loop.
- Avvio - the constraints place the buttons in the same grid locations. With the previous two issues fixed, only the last three buttons placed appear.
I'm assuming you want three buttons in a row, so I changed the loop to use the counter as a row counter. The code below will create ten rows of three buttons.
import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.WindowConstants; public class Main extends javax.swing.JFrame { private JPanel gridPanel; public Main() { this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setSize(600,400); //EXISTING PANEL gridPanel = new JPanel(); JScrollPane scrollPane = new JScrollPane(gridPanel); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); JPanel borderLayoutPanel = new JPanel(new BorderLayout()); borderLayoutPanel.add(scrollPane, BorderLayout.CENTER); this.Avvio(); this.add(borderLayoutPanel, BorderLayout.CENTER); this.setVisible(true); } private void Avvio() { JPanel pane = new JPanel(new GridBagLayout()); pane.setBorder(BorderFactory.createLineBorder(Color.BLUE)); pane.setLayout(new GridBagLayout()); for (int i = 0; i < 10; i++) { JButton button; GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.PAGE_START; button = new JButton("Button 1"); c.weightx = 0.5; c.gridx = 0; c.gridy = i; pane.add(button, c); button = new JButton("Button 2"); c.gridx = 1; c.gridy = i; pane.add(button, c); button = new JButton("Button 3"); c.gridx = 2; c.gridy = i; pane.add(button, c); } gridPanel.add(pane); gridPanel.revalidate(); gridPanel.repaint(); } public static void main(String args[]) { new Main(); } }
Answers 2
Alright, from your comments in another answer:
No problem for compile , simply the Jpanel is empty. The buttons does not appear.
After calling this.Avvio();
you must call:
this.add(scrollPane); this.pack();
This will produce the following outputs (before and after resizing it):
But there's still no JScrollPanel
This at least solves the first problem, however you have more errors in your code, some of which have already been commented in other answers:
You're extending
JFrame
, this isn't needed as you can create aJFrame
instance / object and use it later. You're never changing theJFrame
's behavior and that's why it's not needed to extend it. See Extends JFrame vs. creating it inside the program for more information about this.You're not calling
pack()
norsetSize(...)
this creates a tiny window, which you need to manually resize. Callpack()
recommended before making yourJFrame
visible. (As suggested at the beginning of this answer).You're calling
.invokeLater()
method twice. You need to call it just once, I prefer this way:SwingUtilities.invokeLater(() -> new Main()); //Note there is no call to .setVisible(true); as per point #1. It should go later in the program like: frame.setVisible(true);
You're calling
gridPanel.revalidate();
andgridPanel.repaint()
while it doesn't affect your program, it's not needed as your GUI is still not visible, and thus those calls have no effect on your program, you can safely remove them.You're creating a new
GridBagConstraints
object on each iteration of thefor
loop, you can just change its properties inside it and declaring it outside thefor
loop, which will make your program better.
After following the above recommendations, you can end up with a code like this one:
import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; public class Main { private final JPanel gridPanel; private JFrame frame; public Main() { // EXISTING PANEL gridPanel = new JPanel(); JScrollPane scrollPane = new JScrollPane(gridPanel); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); JPanel borderLayoutPanel = new JPanel(new BorderLayout()); borderLayoutPanel.add(scrollPane, BorderLayout.CENTER); this.Avvio(); frame.add(scrollPane); frame.pack(); frame.setVisible(true); } private void Avvio() { JPanel pane = new JPanel(new GridBagLayout()); pane.setBorder(BorderFactory.createLineBorder(Color.BLUE)); pane.setLayout(new GridBagLayout()); for (int i = 0; i < 10; i++) { JButton button; GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.PAGE_START; button = new JButton("Button 1"); c.weightx = 0.5; c.gridx = 0; c.gridy = i; pane.add(button, c); button = new JButton("Button 2"); c.gridx = 1; c.gridy = i; pane.add(button, c); button = new JButton("Button 3"); c.gridx = 2; c.gridy = i; pane.add(button, c); } gridPanel.add(pane); } public static void main(String args[]) { /* Create and display the form */ SwingUtilities.invokeLater(() -> { new Main(); }); } }
Which still produces this output:
BUT... We still can improve it a little more!
We may have two nested for
loops, for the GridBagConstraints
properties as well as the generation of the buttons:
import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; public class ScrollablePaneWithButtons { private static final int ROWS = 10; private static final int COLS = 3; private JFrame frame; private JPanel pane; private JButton[][] buttons; private GridBagConstraints gbc; private JScrollPane scroll; private JButton[] menuButtons; private JPanel menuPane; public static void main(String[] args) { SwingUtilities.invokeLater(new ScrollablePaneWithButtons()::createAndShowGui); } private void createAndShowGui() { frame = new JFrame(this.getClass().getSimpleName()); pane = new JPanel(); pane.setLayout(new GridBagLayout()); menuPane = new JPanel(); menuPane.setLayout(new GridLayout(1, 3)); buttons = new JButton[ROWS][COLS]; menuButtons = new JButton[] {new JButton("Edit"), new JButton("Delete"), new JButton("Sort Fields")}; gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.PAGE_START; gbc.weightx = 0.5; for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { buttons[i][j] = new JButton("Button " + (j + 1)); gbc.gridx = j; gbc.gridy = i; pane.add(buttons[i][j], gbc); } } scroll = new JScrollPane(pane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); for (JButton b : menuButtons) { menuPane.add(b); } frame.add(scroll); frame.add(menuPane, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
And this example is (in my opinion) easier to read and follow up. And this is the output the above code is generating:
You can still choose which code to use, either doing the modifications at the first part of this answer, the second one following the recommendations above or the last one which is shorter.
Answers 3
There are several things to do to make it work:
- Add a
main
method - This
main
method is the entry point. This makes sure the swing-code runs in the AWT-thread. This is what theSwingUtilities.invokeLater
is for - Instantiate, pack and display the frame. The size setting is only for experimenting with the scrollpane
- Declare the
gridPanel
as an instance variable - wrap the
gridPanel
with thescrollPane
- Optionally, wrap the
scrollPane
with theborderLayoutPanel
- Invoke the
Avvio
method because this is the one that adds the buttons - Add the outmost element to the frame
Here is the fixed code:
public class MyFrame extends javax.swing.JFrame { public static void main(String[] args) { SwingUtilities.invokeLater(() -> { MyFrame frame = new MyFrame(); frame.pack(); frame.setSize(600, 300); frame.setVisible(true); }); } private JPanel gridPanel; public MyFrame() { this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); gridPanel = new JPanel(new GridLayout(0, 1)); JScrollPane scrollPane = new JScrollPane(gridPanel); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); JPanel borderLayoutPanel = new JPanel(new BorderLayout()); borderLayoutPanel.add(scrollPane, BorderLayout.CENTER); this.Avvio(); this.add(borderLayoutPanel, BorderLayout.CENTER); } private void Avvio() {...} }
Answers 4
I have simplified the program and removed all the mistakes and bad practices. (Missing package, unnecessary panels, calling invokeLater()
twice and others.)
Here is a working example:
package com.zetcode; import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; public class JavaScrollPaneEx extends JFrame { public JavaScrollPaneEx() { initUI(); } private void initUI() { JPanel panel = new JPanel(new BorderLayout()); JPanel buttonPanel = createButtonPanel(); JScrollPane scrollPane = new JScrollPane(buttonPanel); panel.add(scrollPane, BorderLayout.CENTER); add(panel); setTitle("Buttons in JScrollBar"); setSize(350, 250); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); } private JPanel createButtonPanel() { JPanel panel = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.PAGE_START; c.insets = new Insets(5, 5, 5, 5); for (int i = 0, j = 0; i < 5; i++) { JButton btn = new JButton("Button " + (j + 1)); c.weightx = 0.5; c.gridx = i; c.gridy = 0; panel.add(btn, c); btn = new JButton("Button " + (j + 2)); c.gridx = i; c.gridy = 1; panel.add(btn, c); btn = new JButton("Button " + (j + 3)); c.gridx = i; c.gridy = 2; panel.add(btn, c); j += 3; } return panel; } public static void main(String args[]) { EventQueue.invokeLater(() -> { JavaScrollPaneEx ex = new JavaScrollPaneEx(); ex.setVisible(true); }); } }
And this is the screenshot.
And since I consider GridBagLayout
to be a very bad layout manager, I have created a similar example with MigLayout
manager.
We need the following Maven dependency for this example:
<dependency> <groupId>com.miglayout</groupId> <artifactId>miglayout-swing</artifactId> <version>5.0</version> </dependency>
The source:
package com.zetcode; import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.JButton; import javax.swing.JFrame; import static javax.swing.JFrame.EXIT_ON_CLOSE; import javax.swing.JPanel; import javax.swing.JScrollPane; import net.miginfocom.swing.MigLayout; public class JavaScrollPaneEx2 extends JFrame { public JavaScrollPaneEx2() { initUI(); } private void initUI() { JPanel panel = new JPanel(new BorderLayout()); JPanel buttonPanel = createButtonPanel(); JScrollPane scrollPane = new JScrollPane(buttonPanel); panel.add(scrollPane, BorderLayout.CENTER); add(panel); setTitle("Buttons in JScrollBar"); setSize(350, 250); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); } private JPanel createButtonPanel() { JPanel panel = new JPanel(new MigLayout()); for (int i = 0, j = 0; i < 5; i++) { JButton btn1 = new JButton("Button " + (j + 1)); JButton btn2 = new JButton("Button " + (j + 2)); JButton btn3 = new JButton("Button " + (j + 3)); JButton btn4 = new JButton("Button " + (j + 4)); JButton btn5 = new JButton("Button " + (j + 5)); panel.add(btn1, "sgx"); panel.add(btn2, "sgx"); panel.add(btn3, "sgx"); panel.add(btn4, "sgx"); panel.add(btn5, "sgx, wrap"); j += 5; } return panel; } public static void main(String args[]) { EventQueue.invokeLater(() -> { JavaScrollPaneEx2 ex = new JavaScrollPaneEx2(); ex.setVisible(true); }); } }
0 comments:
Post a Comment