Java 如何在JScrollPane中显示底部组件?

Java 如何在JScrollPane中显示底部组件?,java,swing,jscrollpane,Java,Swing,Jscrollpane,我有一个Java Swing应用程序,它有一个JScrollPane,其中有一些组件[multipleJPanels]。这些JPanels是在单击“新建”JButton后创建的。我的目标是使JScrollPane向下滚动到创建的最后一个JPanel(即一直向下滚动)。我尝试了以下方法: JScrollBar vertical = Scroll_Pane.getVerticalScrollBar(); vertical.setValue(vertical.getMaximum() + 40);

我有一个Java Swing应用程序,它有一个
JScrollPane
,其中有一些组件[multiple
JPanel
s]。这些
JPanel
s是在单击“新建”
JButton
后创建的。我的目标是使
JScrollPane
向下滚动到创建的最后一个
JPanel
(即一直向下滚动)。我尝试了以下方法:

JScrollBar vertical = Scroll_Pane.getVerticalScrollBar();
vertical.setValue(vertical.getMaximum() + 40); 
但是它不起作用,当
JScrollPane
中至少有3个项目时,最后创建的
JPanel总是丢失。这是我的最小代码,如何修复

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+" ]"; }
}
import java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
导入javax.swing.border.*;
导入java.io.File;
导入java.util.*;
导入javax.swing.event.*;
公共类项目测试面板扩展JPanel
{
公共静态最终长serialVersionUID=26362862L;
静态维度Screen_Size=Toolkit.getDefaultToolkit().getScreenSize();
静态JFrame=新JFrame(“项目测试面板”);
JScrollPane滚动窗格;
静态int W=495,H=110,最大H=110,信息文本区域H=500,命令信息面板宽度=W-23,命令信息面板高度=33;
int Item_Count=0;
颜色标题\背景\颜色=新颜色(150206236);
插图A_插图=新插图(0,0,0,0);
JPanel主面板;
静态字符串Dir\u Data=“C:/Dir\u Data/”,当前项目文件路径;
静态过程子;
布尔值Show_Password_B=true;
矢量命令\信息\矢量;
JTextArea Info_TextArea=新的JTextArea();
DocumentListener命令\信息\字段\侦听器;
Swing_Robot Robot=新的Swing_Robot();
ButtonGroup Item_Group=新建ButtonGroup();//将单选按钮分组。
静止的
{
如果(!new File(Dir_Data).exists())新建文件(Dir_Data).mkdirs();
}
公共项目测试面板(int W,int H)
{
FlowLayout主面板\u FL=新的FlowLayout();
主配电盘层安装图(2);
主面板水平设置间隙(2);
Max_H=H;
命令\信息\字段\侦听器=新文档侦听器()
{
public void removeUpdate(DocumentEvent e){}
public void insertUpdate(DocumentEvent e){}
public void changedUpdate(DocumentEvent e){}
};
主面板=新的JPanel(主面板);
滚动窗格=新的JScrollPane(主窗格);
Scroll_Pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel按钮_面板=新JPanel(新流程布局(1,36,0));
按钮面板。设置首选尺寸(新尺寸(命令信息面板宽度+22,命令信息面板高度-6));
添加(按钮面板);
JButton New_按钮=新JButton(“新”);
设置字体(新字体(“Times New Roman”,0,15));
新按钮。设置前景(新颜色(0,28128));
新按钮。设置边距(插入);
新建按钮。设置首选尺寸(新尺寸(56,26));
新建按钮。添加ActionListener(新建ActionListener()
{
已执行的公共无效操作(操作事件evt)
{
Out(“Command_Info_Vector.size()=”+Command_Info_Vector.size());
创建命令信息面板(++项目计数+1,空);
重新验证();
}
});
按钮面板。添加(新按钮);
JPanel标题_面板=新JPanel(新流程布局(0,1,1));
添加(标题面板);
标题_面板订单(新蚀刻边框());
Title_Panel.setPreferredSize(新尺寸(命令信息面板宽度+22,命令信息面板高度-4));
JLabel Id_Label=新的JLabel(“#”);
Id_Label.setFont(新字体(“Times new Roman”,0,15));
Id_标签。设置不透明(真);
Id\u标签。背景(标题\u背景\u颜色);
设置前景(新颜色(0,28128));
Id_标签设置水平对齐(SwingConstants.中心);
Id_标签setPreferredSize(新尺寸(69,22));
标题面板。添加(Id标签);
JLabel命令_标签=新JLabel(“结果”);
命令_Label.setFont(新字体(“Times new Roman”,0,15));
命令_Label.setOpaque(true);
命令\标签.背景(标题\背景\颜色);
命令_Label.set前台(新颜色(0,28128));
命令\u Label.setHorizontalAlignment(SwingConstants.CENTER);
命令_Label.setPreferredSize(新尺寸(416,22));
标题面板。添加(命令标签);
添加(滚动窗格);
JScrollPane Info\u TextArea\u ScrollPane=新的JScrollPane(Info\u TextArea);
信息\文本区域\滚动窗格。设置垂直滚动条策略(JScrollPane.垂直滚动条\始终);
Info_TextArea_ScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HorizontalScrollbar_ALWAYS);
信息文本区域滚动窗格。设置首选大小(新维度(W-2,信息文本区域H));
添加(信息\文本区域\滚动窗格);
加载_数据(“”);
}
无效创建命令信息面板(int Id、最终命令信息和命令信息)
{
FlowLayout面板_FL=新的FlowLayout();
配电盘FL.setHgap(1);
面板层设置间隙(1);
JPanel命令\信息\面板=新的JPanel(面板\ FL);
命令信息面板.设置命令(新的蚀刻边框());
命令信息面板.setPreferredSize(新尺寸(命令信息面板宽度、命令信息面板高度));
JRadioButton Id_Button=新的JRadioButton(“[”+(Id=-1?项目计数+1:Id)+“]);
设置字体(新字体(“Times new Roman”,0,15));
设置前景(新颜色(0,28128));
Id_按钮。设置首选尺寸(新尺寸(65,26));
项目组。添加(Id按钮);
Id_按钮。选择设置(真);
命令信息面板。添加(Id按钮);
JTextField Result\u Field=新的JTextField(A\u Command\u Info==null?“:A\u Command\u Info.Result);
结果_字段setPreferredSize(新维度(398,27));
结果\字段.getDocument().addDocumentListener(命令\信息\字段\侦听器);
命令信息面板。添加(结果字段);
主面板。添加(命令信息面板);
如果(A_Command_Info==null)Command_Info_Vector.add(new Command_Info(“[”+(项目计数)+“]),”,“,”,”);
更新_布局();
}
无效加载\u数据(字符串项\u目录)
{
命令信息A\u命令信息=null;
主面板。卸下所有();
项目计数=0;
Info_TextArea.setText(“”);
命令信息向量=新向量();
如果(命令信息向量大小()>0)
{
Item\u Count=命令\u Info\u Vector.siz
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();
    }