8

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();

    }
}

enter image description here

Frakcool
  • 10,915
  • 9
  • 50
  • 89
user2847219
  • 555
  • 1
  • 16
  • 27
  • 2
    Please read (and follow) the [Java Naming Conventions](http://www.oracle.com/technetwork/java/codeconventions-135099.html) - methods start with a *lower case* letter and with a *verb* by any chance... – Timothy Truckle Dec 12 '17 at 14:19
  • you never add the `borderLayoutPanel` to the frames content Pane. – Timothy Truckle Dec 12 '17 at 14:20
  • Related to your edits and bounty, what you are trying to achieve is display a series of buttons divided in 3 cols and 10 rows? Along with a `JScrollPane` always visible? Do you have an image of what should be the output and / or clarify what is your question? – Frakcool Dec 14 '17 at 17:48
  • I can see the actual output, but what should be the expected output. No, you're not stupid, rather than that you're not explaining clearly what your problem is and / or what you're trying to achieve. That way we'll be able to help even more – Frakcool Dec 14 '17 at 18:02

4 Answers4

4

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

enter image description hereenter image description here

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:

  1. You're extending JFrame, this isn't needed as you can create a JFrame instance / object and use it later. You're never changing the JFrame'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.

  2. You're not calling pack() nor setSize(...) this creates a tiny window, which you need to manually resize. Call pack() recommended before making your JFrame visible. (As suggested at the beginning of this answer).

  3. 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);
    
  4. You're calling gridPanel.revalidate(); and gridPanel.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.

  5. You're creating a new GridBagConstraints object on each iteration of the for loop, you can just change its properties inside it and declaring it outside the for 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:

enter image description here

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:

enter image description here

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.

Community
  • 1
  • 1
Frakcool
  • 10,915
  • 9
  • 50
  • 89
2

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.

What appears: enter image description here

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();
    }      
}
Michael McKay
  • 650
  • 4
  • 11
  • `GridLayout` is unnecessary and you are calling `invokeLater()` twice. – Jan Bodnar Dec 14 '17 at 16:19
  • @Michael McKay are you testing it? it does not work, JScrollPane not visible – user2847219 Dec 14 '17 at 16:55
  • Made the changes suggested. Not trying to fix everything here - just the Avvio method. – Michael McKay Dec 14 '17 at 16:58
  • in the Avvio() method, if I not insert this: `scrollPane.setViewportView(pane);`, all not visible – user2847219 Dec 14 '17 at 17:02
  • @user2847219. Added a picture showing the output as written before your suggestion. The `scrollPane` object is not visible inside the Avvio method as I have it coded above but the `gridPanel` is. (In your original code, you refer to gridPanel but didn't instantiate it.) The Main() JFrame is built Main->borderLayout->scrollPane->gridPanel->pane. You can remove `gridPanel` and just use the `scrollPane` if you make `scrollPane` a field. – Michael McKay Dec 14 '17 at 17:19
  • Seems you removed the call `this.add(borderLayoutPanel, BorderLayout.CENTER);` in the Main() constructor. Without that call, the Main JFrame has nothing to display. – Michael McKay Dec 14 '17 at 18:18
1

There are several things to do to make it work:

  1. Add a main method
  2. This main method is the entry point. This makes sure the swing-code runs in the AWT-thread. This is what the SwingUtilities.invokeLater is for
  3. Instantiate, pack and display the frame. The size setting is only for experimenting with the scrollpane
  4. Declare the gridPanel as an instance variable
  5. wrap the gridPanel with the scrollPane
  6. Optionally, wrap the scrollPane with the borderLayoutPanel
  7. Invoke the Avvio method because this is the one that adds the buttons
  8. 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() {...}
}
Tamas Rev
  • 7,008
  • 5
  • 32
  • 49
  • The code in my answer works. So something went wrong duirng translation. The first question is: what is the problem you're having now. Is it a compilation problem? Do the buttons appear incorrectly? Please specify. – Tamas Rev Dec 12 '17 at 16:22
  • No problem for compile , simply the Jpanel is empty. The buttons does not appear. In my Jframe I have only the Jpanel (gridPanel) – user2847219 Dec 12 '17 at 17:41
  • There are a few differences between my code and yours. What are those? – Tamas Rev Dec 12 '17 at 19:05
  • Sorry, but I do not see any difference, other than that:'private JPanel gridPanel;'of which there is no need, and this 'initComponents();'. If there is an error or a lack in my code, is inside the 'Avvio()' method. I asked help for that – user2847219 Dec 12 '17 at 20:07
  • So that's the difference. You add `gridPanel` in one method and add buttons to another `gridPanel` in another method. You can either use an instance variable or you can pass that as a method parameter. – Tamas Rev Dec 12 '17 at 20:48
1

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.

enter image description here

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);
        });
    }
}
Jan Bodnar
  • 10,969
  • 6
  • 68
  • 77