The_Lost_Avatar
The_Lost_Avatar

Reputation: 988

Scrollbar not appearing on custom Panel

I have made a class RefreshablePanel that extends JPanel

public class RefreshablePanel extends JPanel {

static String description="";
static int x=10;
static int y=11;
    
protected void paintComponent(Graphics g){
       super.paintComponent(g);
    for (String line : description.split("\n"))
        g.drawString(line, x, y += g.getFontMetrics().getHeight());
}
void updateDescription(String dataToAppend){
        description = description.concat("\n").concat(dataToAppend);
        System.out.println("The description is "+description);
   }   
}

and then I am adding it into my GUI_class like this

JScrollPane scrollPane_2 = new JScrollPane();
scrollPane_2.setBounds(32, 603, 889, 90);
frmToolToMigrate.getContentPane().add(scrollPane_2);

descriptionPanel = new RefreshablePanel();
scrollPane_2.setViewportView(descriptionPanel);
descriptionPanel.setBackground(Color.WHITE);
descriptionPanel.setLayout(null);
    

I have added the scrollbar in the class where I am making an instance of RefreshablePanel but scrollbar is not appearing. I have tried adding

@Override
public Dimension getPreferredSize() {
    return new Dimension(400, 1010);
}

to refreshable Panel but then the string is disappearing like this enter image description here

and nothing is appearing when I scroll down

Upvotes: 0

Views: 229

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347334

  1. You're using null layouts, so nothing is going to work the way it should. Swing is designed at the core to utilise layout managers.

  2. You're RefreshablePanel has no discernible size, meaning that when you add to the scroll pane, the scroll pane is likely to simply think it's size should 0x0. RefreshablePanel needs to provide some kind of size hint back to the scrollpane, preferably via the getPreferredSize method

  3. You could use a JLabel (with text wrapped in html) or a non-editable JTextArea to achieve the same results

Updated

Take a quick check of your code. You are declaring the x and y values as static and you are incrementing the y value in your paintComponent method

static int x=10;
static int y=11;

protected void paintComponent(Graphics g){
   super.paintComponent(g);
    for (String line : description.split("\n"))
        g.drawString(line, x, y += g.getFontMetrics().getHeight());
}

This means two things.

  1. If you have more than one instance of your RefreshablePanel they will ALL share the same x/y values AND update them
  2. y is constantly being update to a new position, so if the panel is painted twice, on the second paint, the y position will start from the position it was last at when the first call exited.

Remember, you don't control the paint process. A paint cycle may be executed at any time that the system decides it needs to...

Make the x/y values local variables to the paintComponent method...

Updated

The scroll pane will try and match the preferred size of the component if the available space allows for it. This may mean that the scroll bars may not appear until you resize the window...but you're using a null layout so that won't work for you...

To affect the size of the scroll pane, you can use the Scrollable interface instead...

enter image description here

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Scrollable01 {

    public static void main(String[] args) {
        new Scrollable01();
    }

    public Scrollable01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                RefreshablePanel pane = new RefreshablePanel();
                pane.updateDescription("1. You're using null layouts, so nothing is going to work the way it should. Swing is designed at the core to utilise layout managers.");
                pane.updateDescription("2. You're RefreshablePanel has no discernible size, meaning that when you add to the scroll pane, the scroll pane is likely to simply think it's size should 0x0. RefreshablePanel needs to provide some kind of size hint back to the scrollpane, preferably via the getPreferredSize method");
                pane.updateDescription("3. You could use a JLabel (with text wrapped in html) or a non-editable JTextArea to achieve the same results");

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(pane));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class RefreshablePanel extends JPanel implements Scrollable {

        public String description = "";

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 1010);
        }

        @Override
        protected void paintComponent(Graphics g) {
            int x = 10;
            int y = 11;
            super.paintComponent(g);
            for (String line : description.split("\n")) {
                g.drawString(line, x, y += g.getFontMetrics().getHeight());
            }
        }

        void updateDescription(String dataToAppend) {
            description = description.concat("\n").concat(dataToAppend);
            System.out.println("The description is " + description);
            repaint();
        }

        @Override
        public Dimension getPreferredScrollableViewportSize() {
            return new Dimension(400, 400);
        }

        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 64;
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 64;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            return false;
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            return false;
        }
    }
}

Upvotes: 3

Related Questions