3

Problem and Code Summary:

This will make sense if you run the code below. I'm using a JScrollPane and its scroll bar is disappearing when it is placed in a JPanel with a BorderLayout (NORTH). When the JPanel has a BorderLayout (CENTER), it works fine (with the scroll bar showing up). If you try to remove many of the components with the remove buttons, it gets annoying because the JScrollPane (with all of its components) clumps up in the middle of the JPanel it's in, when you want it to stay at the top. I tried to prevent this by obviously changing the BorderLayout of the JPanel from CENTER TO NORTH, but that just takes out the scroll bar completely. In the following code, the Main.placement (line 28) (change it to CENTER/NORTH to mess with it) controls the type of layout being used and line 171 shows how it is implemented. I just want to align the JSCrollPane at the top with the scroll bar showing up when it is neccessary.

Code Summary:

package main;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;

public class Main{
    public static final String placement = BorderLayout.CENTER;
    public static void main(String[] args){
        new TimeChart(true);
    }

}

@SuppressWarnings("serial")
class TimeChart extends JFrame {
    private boolean admin;

    private TimeTable timeTable;
    private static final JLabel title;
    private final JLabel volLabel;

    static {
        title = new JLabel("Time Chart ");
    }

    private class TimeTable extends JPanel {

        private JScrollPane scrollPane;
        private JPanel table;

        public final ArrayList<SessionRow> sessionRows;

        private final JButton addButton;

        private final JButton applyButton;

        private static final double weight_sessnum = 0.2;
        private static final double weight_signinout = 1.0;
        private static final double weight_time = 0.3;
        private static final double weight_delete = 0.0;

        public class SessionRow {
            private final SessionRow thisSessionRow; // for inner classes
            private JTextField sessionnum, signinField, signoutField, total;

            private JButton removeButton;

            private SessionRow(int y) {
                thisSessionRow = this;

                String signinstring = "*signin time*";

                String signoutstring = "*signout time*";

                sessionnum = new JTextField("Session " + y + ": ");
                sessionnum.setEditable(false);

                signinField = new JTextField(signinstring);
                signinField.addFocusListener(new FocusListener() {
                    @Override
                    public void focusGained(FocusEvent e) {
                        signinField.selectAll();
                    }

                    @Override
                    public void focusLost(FocusEvent e) {
                    }
                });
                signinField.setEditable(admin);

                signoutField = new JTextField(signoutstring);
                signoutField.addFocusListener(new FocusListener() {
                    @Override
                    public void focusGained(FocusEvent e) {
                        signoutField.selectAll();
                    }

                    @Override
                    public void focusLost(FocusEvent e) {
                    }
                });
                signoutField.setEditable(admin);

                String totalstring = null;
                try {
                    totalstring = "*session total*";
                } catch (Exception e) {
                    totalstring = " -- ";
                }
                total = new JTextField(totalstring);
                total.setEditable(false);

                removeButton = new JButton("Remove");
                removeButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        thisSessionRow.remove();
                        sessionRows.remove(thisSessionRow);
                        revalidate();
                        repaint();

                    }
                });
            }
            public void remove() {
                table.remove(this.sessionnum);
                table.remove(this.signinField);
                table.remove(this.signoutField);
                table.remove(this.total);
                table.remove(this.removeButton);
            }

        }

        public TimeTable() {
            super();

            table = new JPanel();
            scrollPane = new JScrollPane(table);

            applyButton = new JButton("<html><div style=\"text-align: center;\">Apply<br>Changes</html>");
            applyButton.setMargin(new Insets(5, 5, 5, 5));
            applyButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    applyAllChanges();
                }
            });
            applyButton.setEnabled(false);

            addButton = new JButton("Add");
            addButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    sessionRows.add(new SessionRow(sessionRows.size() + 1));
                    setupAll();
                    revalidate();
                    repaint();
                    if (!applyButton.isEnabled())
                        applyButton.setEnabled(true);
                }
            });

            sessionRows = new ArrayList<SessionRow>();
            setupSessionRows();

            setupAll();

            this.setLayout(new BorderLayout());
            this.add(scrollPane, Main.placement); //PAY ATTENTION HERE

            JScrollBar bar = scrollPane.getVerticalScrollBar();
            bar.setPreferredSize(new Dimension(30, 0));
            bar.setUnitIncrement(10);
            InputMap im = bar.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);

            im.put(KeyStroke.getKeyStroke("down"), "positiveUnitIncrement");
            im.put(KeyStroke.getKeyStroke("up"), "negativeUnitIncrement");

            scrollPane.setBorder(BorderFactory.createLineBorder(Color.red));
            this.setBorder(BorderFactory.createLineBorder(Color.green));

        }

        public void setupSessionRows() {
            sessionRows.clear();
            for (int i = 0; i < 30; i++) {
                sessionRows.add(new SessionRow(i + 1));
            }
            System.gc();
        }

        public void setupAll() {
            table.removeAll();

            table.setLayout(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();
            c.fill = GridBagConstraints.HORIZONTAL;
            c.insets = new Insets(0, 0, 5, 2);

            c.gridx = 0;
            c.gridy = 0;
            initColumnHeader(c);

            for (int y = 0; y < sessionRows.size(); y++) {
                c.gridy++;
                initSessRow(sessionRows.get(y), c);
            }

            c.gridy++;

            if (admin) {
                initNewButtonRow(c);
                c.gridy++;
            }

            initTotalHeader(c);

        }

        public void initSessRow(SessionRow row, GridBagConstraints c) {

            c.weightx = weight_sessnum;
            c.gridx = 0;
            table.add(row.sessionnum, c);

            c.weightx = weight_signinout;
            c.gridx = 1;
            table.add(row.signinField, c);

            c.weightx = weight_signinout;
            c.gridx = 2;
            table.add(row.signoutField, c);

            c.weightx = weight_time;
            c.gridx = 3;
            table.add(row.total, c);

            if (admin) {
                c.weightx = weight_delete;
                c.gridx = 4;
                table.add(row.removeButton, c);
            }

        }

        public void initTotalHeader(GridBagConstraints c) {
            c.weightx = weight_sessnum;
            c.gridx = 0;
            JTextField totalLabel = new JTextField("Total: ");
            totalLabel.setEditable(false);
            table.add(totalLabel, c);

            c.weightx = weight_signinout;
            c.gridx = 1;
            JTextField blank1 = new JTextField();
            blank1.setEditable(false);
            table.add(blank1, c);

            c.weightx = weight_signinout;
            c.gridx = 2;
            JTextField blank2 = new JTextField();
            blank2.setEditable(false);
            table.add(blank2, c);

            c.weightx = weight_time;
            c.gridx = 3;
            JTextField totaltime = new JTextField("*TOTAL*");
            totaltime.setEditable(false);
            table.add(totaltime, c);

            if (admin) {
                c.weightx = weight_delete;
                c.gridx = 4;
                table.add(applyButton, c);
            }

        }

        public void initNewButtonRow(GridBagConstraints c) {
            c.weightx = weight_sessnum;
            c.gridx = 0;
            table.add(addButton, c);

            c.weightx = weight_signinout;
            c.gridx = 1;
            JTextField blank1 = new JTextField();
            blank1.setEditable(false);
            table.add(blank1, c);

            c.weightx = weight_signinout;
            c.gridx = 2;
            JTextField blank2 = new JTextField();
            blank2.setEditable(false);
            table.add(blank2, c);

            c.weightx = weight_time;
            c.gridx = 3;
            JTextField blank3 = new JTextField();
            blank3.setEditable(false);
            table.add(blank3, c);

            if (admin) {
                c.weightx = weight_delete;
                c.gridx = 4;
                JTextField blank4 = new JTextField();
                blank4.setEditable(false);
                table.add(blank4, c);
            }

        }

        public void initColumnHeader(GridBagConstraints c) {

            c.weightx = weight_sessnum;
            c.gridx = 0;
            JTextField sessnum = new JTextField("Session #");
            sessnum.setEditable(false);
            table.add(sessnum, c);

            c.weightx = weight_signinout;
            c.gridx = 1;
            JTextField signintime = new JTextField("Sign in Time");
            signintime.setEditable(false);
            table.add(signintime, c);

            c.weightx = weight_signinout;
            c.gridx = 2;
            JTextField signouttime = new JTextField("Sign out Time");
            signouttime.setEditable(false);
            table.add(signouttime, c);

            c.weightx = weight_time;
            c.gridx = 3;
            JTextField time = new JTextField("Time");
            time.setEditable(false);
            table.add(time, c);

            if (admin) {
                c.weightx = weight_delete;
                c.gridx = 4;
                JTextField delete = new JTextField("Delete");
                delete.setEditable(false);
                table.add(delete, c);
            }
        }

        @Override
        public void revalidate() {
            if (sessionRows != null) {

                int i = 1;
                for (SessionRow sr : sessionRows) {
                    sr.sessionnum.setText("Session " + i);
                    i++;
                }
            }
            super.revalidate();
        }

    }

    public TimeChart(boolean admin) {
        super();

        this.admin = admin;

        volLabel = new JLabel("Billy");

        timeTable = new TimeTable();

        this.setSize(900, 900);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        initFrame();

        this.setVisible(true);
        scrollDown();
    }

    public void initFrame() {
        this.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.BOTH;

        c.weightx = 1.0;
        c.weighty = 0.0;
        c.gridx = 0;
        c.gridy = 0;
        this.add(title, c);

        c.weightx = 1.0;
        c.weighty = 0.0;
        c.gridx = 0;
        c.gridy = 1;
        this.add(volLabel, c);

        c.weightx = 1.0;
        c.weighty = 1.0;
        c.gridx = 0;
        c.gridy = 2;
        this.add(timeTable, c);

    }

    public void scrollDown() {
        JScrollBar bar = timeTable.scrollPane.getVerticalScrollBar();
        bar.setValue(bar.getMaximum());
    }

    public void applyAllChanges() {
    }

}

Thanks in advance, I really appreciate it.

akarshkumar0101
  • 367
  • 2
  • 10
  • The component in the north position is been maintained at it's preferredSize, so the `JScrollPane` is never been decreased in size to the point where it needs scroll bars. Personally, I'd think a `JTable` would be simpler to setup, but that's just me – MadProgrammer Feb 27 '16 at 03:24
  • @MadProgrammer How can the table(JPanel) inside the JScrollPane be at its preferredSize if it doesn't show up completely? Not all of it is visible. And i can't use JTable because our teacher has not allowed us to. – akarshkumar0101 Feb 27 '16 at 03:27
  • It is been all displayed, your initial window size is to small, try using `pack` on the frame instead of `setSize`, but do it just before you call `setVisible` (the `JScrollPane` is been allowed to overflow the visible bounds of the window) – MadProgrammer Feb 27 '16 at 03:30
  • @MadProgrammer I did this.pack(); then this.setVisible(); and the frame got much longer to match the preferredSize of the table, but when I resized the JFrame smaller, the JScrollBar still didn't show up. Instead it just started cutting the other components in the table out completely. – akarshkumar0101 Feb 27 '16 at 03:35
  • *"so the JScrollPane is never been decreased in size to the point where it needs scroll bars"* - which is why it never shows scroll bars...This might sound weird, but that would the expectations of `BorderLayout` – MadProgrammer Feb 27 '16 at 03:36
  • @MadProgrammer Is there a layout or any fix that allows the entire JScrollPane to fit inside the JPanel (decrease to the size of the JPanel) yet maintain a position on the TOP/NORTH if the JScrollPane is too small? – akarshkumar0101 Feb 27 '16 at 03:39
  • `GridBagLayout` can do, if you configure it right – MadProgrammer Feb 27 '16 at 03:48
  • @MadProgrammer Thank you. – akarshkumar0101 Feb 27 '16 at 03:50
  • 1
    Was this ever figured out? I'm having pretty close to the same problem using BorderLayout. If you achieved it with BorderLayout or GridBagLayout, can you display your answer? – DarkHark Jul 06 '18 at 13:58
  • @DarkHark i am pretty sure I switched to a gridbaglayout, they almost never have any problems. – akarshkumar0101 Jul 06 '18 at 18:24
  • @akarshkumar0101 Thanks. Unfortunately I can't really do that because I'm trying to make my panels dynamic. I'm trying out the BoxLayout now. – DarkHark Jul 06 '18 at 18:50

0 Answers0