1

I have a Java Swing app, it has a JScrollPane which has some components [multiple JPanels ] in it. Those JPanels are created after the "New" JButton is clicked. My goal is to make the JScrollPane scroll to scroll down to the last JPanel created (i.e. scroll all the way down). I have tried the following:

JScrollBar vertical = Scroll_Pane.getVerticalScrollBar();
vertical.setValue(vertical.getMaximum() + 40); 

But it didn't work, the last JPanel created is always missing once there are at least 3 items in the JScrollPane. Here is my minimal code, how to fix this?

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.File;
import java.util.*;
import javax.swing.event.*;

public class Items_Test_Panel extends JPanel
{
  public static final long serialVersionUID=26362862L;
  static Dimension Screen_Size=Toolkit.getDefaultToolkit().getScreenSize();
  static JFrame frame=new JFrame("Items_Test_Panel");
  JScrollPane Scroll_Pane;
  static int W=495,H=110,Max_H=110,Info_TextArea_H=500,Command_Info_Panel_Width=W-23,Command_Info_Panel_Height=33;
  int Item_Count=0;
  Color Title_Background_Color=new Color(150,206,236);
  Insets An_Inset=new Insets(0,0,0,0);
  JPanel Main_Panel;
  static String Dir_Data="C:/Dir_Data/",Current_Item_File_Path;
  static Process Child;
  boolean Show_Password_B=true;
  Vector<Command_Info> Command_Info_Vector;
  JTextArea Info_TextArea=new JTextArea();
  DocumentListener Command_Info_Field_Listener;
  Swing_Robot Robot=new Swing_Robot();
  ButtonGroup Item_Group=new ButtonGroup();                                    // Group the radio buttons.

  static
  {
    if (!new File(Dir_Data).exists()) new File(Dir_Data).mkdirs();
  }

  public Items_Test_Panel(int W,int H)
  {
    FlowLayout Main_Panel_FL=new FlowLayout();
    Main_Panel_FL.setHgap(2);
    Main_Panel_FL.setVgap(2);
    Max_H=H;
    Command_Info_Field_Listener=new DocumentListener()
    {
      public void removeUpdate(DocumentEvent e) { }
      public void insertUpdate(DocumentEvent e) { }
      public void changedUpdate(DocumentEvent e) { }
    };

    Main_Panel=new JPanel(Main_Panel_FL);
    Scroll_Pane=new JScrollPane(Main_Panel);
    Scroll_Pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

    JPanel Button_Panel=new JPanel(new FlowLayout(1,36,0));
    Button_Panel.setPreferredSize(new Dimension(Command_Info_Panel_Width+22,Command_Info_Panel_Height-6));
    add(Button_Panel);   

    JButton New_Button=new JButton("New");
    New_Button.setFont(new Font("Times New Roman",0,15));
    New_Button.setForeground(new Color(0,28,128));
    New_Button.setMargin(An_Inset);
    New_Button.setPreferredSize(new Dimension(56,26));
    New_Button.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent evt)
      {
        Out("Command_Info_Vector.size() = "+Command_Info_Vector.size());
        Create_Command_Info_Panel(++Item_Count+1,null);
        revalidate();
      }
    });
    Button_Panel.add(New_Button);

    JPanel Title_Panel=new JPanel(new FlowLayout(0,1,1));
    add(Title_Panel);

    Title_Panel.setBorder(new EtchedBorder());
    Title_Panel.setPreferredSize(new Dimension(Command_Info_Panel_Width+22,Command_Info_Panel_Height-4));

    JLabel Id_Label=new JLabel(" # ");
    Id_Label.setFont(new Font("Times New Roman",0,15));
    Id_Label.setOpaque(true);
    Id_Label.setBackground(Title_Background_Color);
    Id_Label.setForeground(new Color(0,28,128));
    Id_Label.setHorizontalAlignment(SwingConstants.CENTER);
    Id_Label.setPreferredSize(new Dimension(69,22));
    Title_Panel.add(Id_Label);

    JLabel Command_Label=new JLabel("Result");
    Command_Label.setFont(new Font("Times New Roman",0,15));
    Command_Label.setOpaque(true);
    Command_Label.setBackground(Title_Background_Color);
    Command_Label.setForeground(new Color(0,28,128));
    Command_Label.setHorizontalAlignment(SwingConstants.CENTER);
    Command_Label.setPreferredSize(new Dimension(416,22));
    Title_Panel.add(Command_Label);

    add(Scroll_Pane);

    JScrollPane Info_TextArea_ScrollPane=new JScrollPane(Info_TextArea);
    Info_TextArea_ScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    Info_TextArea_ScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    Info_TextArea_ScrollPane.setPreferredSize(new Dimension(W-2,Info_TextArea_H));

    add(Info_TextArea_ScrollPane);

    Load_Data("");
  }

  void Create_Command_Info_Panel(int Id,final Command_Info A_Command_Info)
  {
    FlowLayout Panel_FL=new FlowLayout();
    Panel_FL.setHgap(1);
    Panel_FL.setVgap(1);
    JPanel Command_Info_Panel=new JPanel(Panel_FL);
    Command_Info_Panel.setBorder(new EtchedBorder());
    Command_Info_Panel.setPreferredSize(new Dimension(Command_Info_Panel_Width,Command_Info_Panel_Height));

    JRadioButton Id_Button=new JRadioButton("[ "+(Id==-1?Item_Count+1:Id)+" ]");
    Id_Button.setFont(new Font("Times New Roman",0,15));
    Id_Button.setForeground(new Color(0,28,128));
    Id_Button.setPreferredSize(new Dimension(65,26));
    Item_Group.add(Id_Button);
    Id_Button.setSelected(true);      
    Command_Info_Panel.add(Id_Button);

    JTextField Result_Field=new JTextField(A_Command_Info==null?"":A_Command_Info.Result);
    Result_Field.setPreferredSize(new Dimension(398,27));
    Result_Field.getDocument().addDocumentListener(Command_Info_Field_Listener);
    Command_Info_Panel.add(Result_Field);

    Main_Panel.add(Command_Info_Panel);

    if (A_Command_Info==null) Command_Info_Vector.add(new Command_Info("[ "+(Item_Count)+" ]","","",""));
    Update_Layout();
  }

  void Load_Data(String Items_Dir)
  {
    Command_Info A_Command_Info=null;

    Main_Panel.removeAll();
    Item_Count=0;
    Info_TextArea.setText("");
    Command_Info_Vector=new Vector();
    if (Command_Info_Vector.size()>0)
    {
      Item_Count=Command_Info_Vector.size();
      for (int i=0;i<Command_Info_Vector.size();i++)
      {
        A_Command_Info=Command_Info_Vector.elementAt(i);
        Create_Command_Info_Panel(i+1,A_Command_Info);
      }
      Item_Count--;
      Info_TextArea.setText(A_Command_Info.Info);
    }
    else Create_Command_Info_Panel(-1,null);

    Update_Layout();
  }

  void Update_Layout()
  {
    Main_Panel.setPreferredSize(new Dimension(Command_Info_Panel_Width,Item_Count*(Command_Info_Panel_Height+2)+36));
    if (Item_Count*(Command_Info_Panel_Height+2)+40<Max_H) Scroll_Pane.setPreferredSize(new Dimension(W-2,Item_Count*(Command_Info_Panel_Height+2)+40));
    else Scroll_Pane.setPreferredSize(new Dimension(W-2,Max_H));
    Scroll_Pane.revalidate();
    Scroll_Pane.repaint();
    revalidate();
    repaint();

    JScrollBar vertical=Scroll_Pane.getVerticalScrollBar();
    vertical.setValue(vertical.getMaximum()+40);
    Out(" vertical.getMaximum() = "+vertical.getMaximum()+"  vertical.getMinimum() = "+vertical.getMinimum());
/*
  Online advice of how to adjudt the Scroll_Pane : https://robbamforth.wordpress.com/2015/06/24/java-how-to-scroll-to-a-particular-component-in-jscrollpane-and-gain-focus/
    JPanel comp=(JPanel)Main_Panel.getComponent(Main_Panel.getComponentCount()-1);
//  vertical.setValue(Main_Panel.getParent().getLocation().y+(Main_Panel.getLocation().y+50));
//  JComponent comp=Main_Panel;
//  vertical.setValue(comp.getParent().getLocation().y+(comp.getLocation().y+50));
  vertical.setValue(250);
  comp.requestFocus();
Out(comp.toString());
    vertical.repaint();
    vertical.revalidate();
    */
    if (Item_Count*(Command_Info_Panel_Height+2)+40<Max_H) frame.setPreferredSize(new Dimension(W+17,Item_Count*(Command_Info_Panel_Height+2)+122+Command_Info_Panel_Height+Info_TextArea_H));
    else frame.setPreferredSize(new Dimension(W+17,Max_H+82+Command_Info_Panel_Height+Info_TextArea_H));
    frame.pack();
    frame.revalidate();
    frame.repaint();

  }

  private static void out(String message) { System.out.print(message); }
  private static void Out(String message) { System.out.println(message); }

  // Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
  static void Create_And_Show_GUI()
  {
    final Items_Test_Panel demo=new Items_Test_Panel(W,H);

    frame.add(demo);
    frame.addWindowListener( new WindowAdapter()
    {
      public void windowActivated(WindowEvent e) { }
      public void windowClosed(WindowEvent e) { }
      public void windowClosing(WindowEvent e)
      {
        System.exit(0);
        Child.destroy();
      }
      public void windowDeactivated(WindowEvent e)  { }
      public void windowDeiconified(WindowEvent e)  { demo.repaint(); }
      public void windowGainedFocus(WindowEvent e)  { demo.repaint(); }
      public void windowIconified(WindowEvent e)  { }
      public void windowLostFocus(WindowEvent e)  { }
      public void windowOpening(WindowEvent e) { demo.repaint(); }
      public void windowOpened(WindowEvent e)  { }
      public void windowResized(WindowEvent e) { demo.repaint(); }
      public void windowStateChanged(WindowEvent e) { demo.repaint(); }
    });
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public static void main(String[] args)
  {
    // Schedule a job for the event-dispatching thread : creating and showing this application's GUI.
    SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } });
  }
}

class Command_Info
{
  String Id,Date,Result,Info;

  Command_Info(String Id,String Date,String Result,String Info)
  {
    this.Id=Id;
    this.Date=Date;
    this.Result=Result;
    this.Info=Info;
  }

  public String toString() { return "Id = "+Id+"  Date = [ "+Date+" ]  Result = [ "+Result+" ]  Info = [ "+Info+" ]"; }
}
M. Al Jumaily
  • 731
  • 1
  • 6
  • 21
Frank
  • 30,590
  • 58
  • 161
  • 244

1 Answers1

1

You are assigning and updating the JScrollBar before it is updated. This is why you are one step behind (the newest JRadioButton and JTextField are not showing). The fix is to first update the your components via frame.pack(); and then use vertical.setValue(...); to set your value. Change your void Update_Layout() {...} to the following:

output

void Update_Layout() {
        Main_Panel.setPreferredSize(new Dimension(Command_Info_Panel_Width, Item_Count * (Command_Info_Panel_Height + 2) + 36));
        if (Item_Count * (Command_Info_Panel_Height + 2) + 40 < Max_H) {
            Scroll_Pane.setPreferredSize(new Dimension(W - 2, Item_Count * (Command_Info_Panel_Height + 2) + 40));
        } else {
            Scroll_Pane.setPreferredSize(new Dimension(W - 2, Max_H));
        }

        Scroll_Pane.revalidate();
        Scroll_Pane.repaint();
        revalidate();
        repaint();
        Main_Panel.revalidate();
        Main_Panel.repaint();

        /*
  Online advice of how to adjudt the Scroll_Pane : https://robbamforth.wordpress.com/2015/06/24/java-how-to-scroll-to-a-particular-component-in-jscrollpane-and-gain-focus/
    JPanel comp=(JPanel)Main_Panel.getComponent(Main_Panel.getComponentCount()-1);
//  vertical.setValue(Main_Panel.getParent().getLocation().y+(Main_Panel.getLocation().y+50));
//  JComponent comp=Main_Panel;
//  vertical.setValue(comp.getParent().getLocation().y+(comp.getLocation().y+50));
  vertical.setValue(250);
  comp.requestFocus();
Out(comp.toString());
    vertical.repaint();
    vertical.revalidate();
         */
        if (Item_Count * (Command_Info_Panel_Height + 2) + 40 < Max_H) {
            frame.setPreferredSize(new Dimension(W + 17, Item_Count * (Command_Info_Panel_Height + 2) + 122 + Command_Info_Panel_Height + Info_TextArea_H));
        } else {
            frame.setPreferredSize(new Dimension(W + 17, Max_H + 82 + Command_Info_Panel_Height + Info_TextArea_H));
        }

        //HERE!
        frame.pack();
        JScrollBar vertical = Scroll_Pane.getVerticalScrollBar();
        vertical.setValue(vertical.getMaximum());
        Out(" vertical.getMaximum() = " + vertical.getMaximum() + "  vertical.getMinimum() = " + vertical.getMinimum());
        //frame.pack();//in case you want to pack again, not needed for your fix.
        frame.revalidate();
        frame.repaint();
    }
M. Al Jumaily
  • 731
  • 1
  • 6
  • 21