我觉得这个可能是JScrollPane的一个bug,不过影响也不是很大呀,不就是要人手工拉一下吗,这样把,你就人工改成可以显示到你需要文本的最后一行呀,比如加个空行:sp4 = new JScrollPane(t4,
                      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                      JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),t4.append("appned 33 \n");
这样它就可以显示你所要加的全部文本了呀,因为最后一行已经变成空行\n了
不好意思,我只能想出这个治标不治本的方法了。

解决方案 »

  1.   

    It might be a bug. But you can always use
     scrollRectToVisible(modelToView(m_doc.getLength()));
    to overcome.
      

  2.   

    我没发现这个问题,不过我想可以自己强行把JScrollPane滚动到最后一行,用放在jscrollPane里的那个组件的scrollRectToVisible(Rectangle)方法
    下面的代码中,表格中有新行插入后,还是强行滚动到第一行,供你参考
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import java.util.*;public class SplitTest extends JFrame {
    JScrollPane sp1 = new JScrollPane();
        JTable table = new JTable();
        DefaultTableModel tm = new DefaultTableModel();

    public SplitTest() {
    this.setSize(400, 300);
    this.getContentPane().add(sp1, BorderLayout.CENTER);
    sp1.getViewport().add(table);
    tm.addColumn("c1");
    tm.addColumn("c2");
    tm.addColumn("c3");
    table.setModel(tm);
    java.util.Timer timer = new java.util.Timer();
    timer.schedule(new TimerTask() {
    public void run() {
    refreshTable();
    }
    }, 0, 2000);
    }

    void refreshTable() {
    Vector row = new Vector();
    for (int i = 0; i < 3; i++) {
    row.add("value " + Integer.toString(i));
    }
    tm.addRow(row);
    table.scrollRectToVisible(new Rectangle(0, 0, table.getSize().width, table.getSize().height)); //强行把显示滚动到第一行(其实是顶端)
    System.out.println("add new row into tablemodel.");
    }
         public static void main(String[] args) {
    SplitTest frame = new SplitTest();
    frame.setVisible(true);
    }
    }
      

  3.   

    这些方法差不多都试过了,好像绝大部分情况下都是不行的。
    我把这个类的相关code贴出来,有兴趣地看一下吧。
    package ClientMessage;/**
     * <p>Title: JavaMe</p>
     * <p>Description: </p>
     * <p>Copyright: Copyright (c) 2003</p>
     * <p>Company: ISMT, HKUST</p>
     * @author group4
     * @version 1.0
     */import javax.swing.*;
    import javax.swing.text.*;
    import javax.swing.event.*;
    import java.awt.*;
    import java.awt.event.*;
    import com.borland.jbcl.layout.*;
    import javax.swing.border.*;import PropertyManager.*;
    import MainApplication.*;
    import ClientMessage.*;
    public class MessageBox extends JSplitPane implements ActionListener
    {
      protected JPanel lowerPanel = new JPanel();
      protected BorderLayout borderLayout1 = new BorderLayout();
      protected JButton sendButton = new JButton();
      protected JPanel upperPanel = new JPanel();
      protected JPanel controlPanel = new JPanel();
      protected MyTextArea displayArea = new MyTextArea();
      protected JScrollPane upperScrollPane = new JScrollPane();
      protected BorderLayout borderLayout2 = new BorderLayout();
      protected JScrollPane lowerScrollPane = new JScrollPane();
      protected JTextArea sendArea = new JTextArea();
      protected Border border1;
      protected PlainButton blockButton = new PlainButton();
      protected PlainButton fontButton = new PlainButton();
      protected PlainButton colorButton = new PlainButton();
      protected FlowLayout flowLayout1 = new FlowLayout();
      protected Border border2, border3;  protected JTextField wordCountField = new JTextField(3);  protected int type = 1;  public MessageBox(int type)
      {
        jbInit();
        this.type = type;
      }
      //this method is declared as protected to make it able to be inherited
      protected void jbInit()
      {
        wordCountField.setEditable(false);
        //create the border
        border1 = BorderFactory.createCompoundBorder(new EtchedBorder(EtchedBorder.RAISED,
            Color.blue,new Color(178, 178, 178)),BorderFactory.createEmptyBorder(5,5,1,4));    border2 = BorderFactory.createCompoundBorder(new TitledBorder(BorderFactory.createEtchedBorder(Color.white,Color.blue),""),BorderFactory.createEmptyBorder(2,2,2,2));
        border3 = BorderFactory.createCompoundBorder(new TitledBorder(BorderFactory.createEtchedBorder(Color.white,Color.red),""),BorderFactory.createEmptyBorder(2,2,2,2));
        this.setDividerLocation(360);
        this.setOrientation(JSplitPane.VERTICAL_SPLIT);
        this.setDividerSize(2);
        this.setResizeWeight(1.0);
        lowerPanel.setLayout(borderLayout1);
        sendButton.setBorder(border2);
        sendButton.setText("Send");
        sendButton.addMouseListener(new MouseAdapter() // set the effect for the send button
        {
          public void mouseEntered(MouseEvent e)
          {
            sendButton.setBorder(border3);
          }
          public void mouseExited(MouseEvent e)
          {
            sendButton.setBorder(border2);
          }
        });
        //set the starting value of the word count field
        wordCountField.setText(String.valueOf(0));    upperPanel.setLayout(borderLayout2);
        displayArea.setBorder(border1);
        /*displayArea.setText("Venus0608 wrote:\nHello World\nHello World\nthis is my first game\n"
                            +"who are you after all?\nI am from china, what about you?"
                            +"Thanks a lot. this is from Cananda\n.. goood, thank you for you kindness\n");*/
        //displayArea.setLineWrap(true);
        //displayArea.setWrapStyleWord(true);
        displayArea.setBackground(PropertyManager.Parameters.currentBackgroundColor);
        displayArea.setFont(PropertyManager.Parameters.currentDefaultFont);
        displayArea.setDocument(new DefaultStyledDocument());    controlPanel.setMinimumSize(new Dimension(9, 20));
        controlPanel.setLayout(flowLayout1);
        sendArea.setBorder(border1);
        sendArea.setDocument(new MyDocument()); //set the default document to be MyDocument
        sendArea.setText("Send message here");
        sendArea.setLineWrap(true);
        sendArea.setWrapStyleWord(true);
        sendArea.setBackground(Parameters.currentBackgroundColor);
        sendArea.setFont(Parameters.currentDefaultFont);    //register key listeners to the sendArea
        sendArea.registerKeyboardAction(new ActionListener(){
          public void actionPerformed(ActionEvent e)
          {
            sendButton.doClick();
          }
        },  KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,KeyEvent.CTRL_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
        //buttons
        blockButton.setText("Block");
        blockButton.setIcon(new ImageIcon("images\\stop.gif"));
        fontButton.setText("Font");
        fontButton.setIcon(new ImageIcon("images\\font.gif"));
        fontButton.addActionListener(this);
        colorButton.setText("Color");
        colorButton.setIcon(new ImageIcon("images\\color.gif"));
        colorButton.addActionListener(this);    this.add(lowerPanel, JSplitPane.BOTTOM);
        lowerPanel.add(sendButton,  BorderLayout.EAST);
        lowerPanel.add(lowerScrollPane, BorderLayout.CENTER);    lowerScrollPane.getViewport().add(sendArea, null);
        this.add(upperPanel, JSplitPane.TOP);
        upperPanel.add(upperScrollPane, BorderLayout.CENTER);
        upperPanel.add(controlPanel,  BorderLayout.SOUTH);    controlPanel.add(blockButton, null);
        controlPanel.add(fontButton, null);
        controlPanel.add(colorButton, null);
        controlPanel.add(Box.createHorizontalStrut(2));
        controlPanel.add(wordCountField, null);    displayArea.setEditable(false);
        upperScrollPane.getViewport().add(displayArea, null);
      }
      //get the sended message
      public String getOutMessage()
      {
        try{
           return sendArea.getText();
        }
        catch(NullPointerException npe)
        {
          return null;
        }
      }
      

  4.   

    //clear the displayArea
      public void clearDisplayArea()
      {
        displayArea.setText("");
      }
      //clear the sendArea
      public void clearSendArea()
      {
        sendArea.setText("");
        sendArea.requestFocus();
      }  //set client message header
      public synchronized void setInMessage(String from,
                                                   String to, boolean ownMessage, String message)
      {
        displayArea.appendInMessage(from, to, ownMessage, message);
        //upperScrollPane.getVerticalScrollBar()
        //      .setValue(upperScrollPane.getVerticalScrollBar().getMaximum());
        upperScrollPane.getViewport().scrollRectToVisible(new Rectangle(0,
            displayArea.getHeight()-upperScrollPane.getHeight()+25,
            displayArea.getWidth(), upperScrollPane.getHeight()-25));
      }
      public synchronized void setAlertMessage(String message)
      {
        SimpleAttributeSet attr = new SimpleAttributeSet();
        StyleConstants.setForeground(attr, Color.GREEN);
        displayArea.append(message+"\n", attr);
        //lowerScrollPane.getVerticalScrollBar()
        //      .setValue(upperScrollPane.getVerticalScrollBar().getMaximum());
        upperScrollPane.getViewport().scrollRectToVisible(new Rectangle(0,
            displayArea.getHeight()-upperScrollPane.getHeight()+25,
            displayArea.getWidth(), upperScrollPane.getHeight()-25));
      }
      //get the send button
      public JButton getSendButton() { return sendButton; }
      //get the block button
      public PlainButton getBlockButton() { return blockButton; }
      //get the font button
      public PlainButton getFontButton() { return fontButton; }
      //get the colorbutton
      public PlainButton getColorButton() { return colorButton; }
      //get the display area
      public MyTextArea getDisplayArea() { return displayArea; }
      //get send area
      public JTextArea getSendArea() { return sendArea; }
      //remove block button
      public void removeBlockButton() { controlPanel.remove(blockButton); }  //set the color of control panel
      public void setControlPanelColor(Color color)
      { controlPanel.setBackground(color); }
      //add buttons to the control panel for customization
      public void addJButtonToControlPanel(JButton button)
      {
        controlPanel.add(button);
      }
      //set the divider location
      public void setMessageBoxDividerLocation(int location)
      {
        this.setDividerLocation(location);
      }
      //set the font of the display area and send area
      public void setFont(java.awt.Font font, boolean applyToDisplayArea, boolean applyToSendArea)
      {
        if(applyToDisplayArea == true)
        {
          displayArea.setFont(font);
        }
        if(applyToSendArea == true)
        {
          sendArea.setFont(font);
        }
      }  //set the background color of the display area and send area
      public void setBackgroundColor(Color color, boolean applyToDisplayArea, boolean applyToSendArea)
      {
        if(applyToDisplayArea == true)
        {
          displayArea.setBackground(color);
        }
        if(applyToSendArea == true)
        {
          sendArea.setBackground(color);
        }
      }  //action listener method
      public void actionPerformed(ActionEvent event)
      {
        //font button
        if(event.getSource() == fontButton)
        {
          FontChooser fontChooser = new FontChooser(null, "Font Chooser", true, displayArea.getFont());
          int option = fontChooser.showFontChooser();
          if(option == FontChooser.OK_OPTION)
          {
            Font font = fontChooser.getSelectedFont();
            setFont(font, true, true);
            //set the default value for new instances of this messagebox
            Parameters.currentDefaultFont = font;
          }
          else
          {
            return;
          }
        }    //color button
        if(event.getSource() == colorButton)
        {
          Color color = JColorChooser.showDialog(this, "Chooser background color", displayArea.getBackground());
          setBackgroundColor(color, true, true);
          //set the default value
          Parameters.currentBackgroundColor = color;
        }
      }
      //my modified document
      class MyDocument extends DefaultStyledDocument implements DocumentListener
      {
        int maxLength = Parameters.MAX_MESSAGE_LENGTH;    public MyDocument()
        {
          super();
          this.addDocumentListener(this);
          if(type == 1)
          {
            maxLength = Parameters.MAX_MESSAGE_LENGTH;
          }
          else if(type == 2)
          {
            maxLength = Parameters.MAX_MULTICAST_MESSAGE_LENGTH;
          }
        }    public void insertString(int offset, String str, AttributeSet a) throws BadLocationException
        {
          int lastPosition = this.getLength();
          if( (lastPosition+str.length()) <= maxLength)
          {
            super.insertString(lastPosition, str, a);
          }
          else if(lastPosition <= maxLength && (lastPosition+str.length()) >= maxLength)
          {
            super.insertString(lastPosition, str.substring(0, maxLength-lastPosition), a);
          }
        }    public void changedUpdate(DocumentEvent e) { }
        //overried insertUpdate() method
        public void insertUpdate(DocumentEvent e)
        {
          sendButton.setEnabled(true);
          int oldCount = Integer.parseInt(wordCountField.getText());
          wordCountField.setText(String.valueOf(oldCount+e.getLength()));
        }
        //override removeUpdate() method
        public void removeUpdate(DocumentEvent e)
        {
          if(this.getLength() == 0)
          {
            sendButton.setEnabled(false);
          }
          int oldCount = Integer.parseInt(wordCountField.getText());
          wordCountField.setText(String.valueOf(oldCount-e.getLength()));
        }
      }
    }
      

  5.   

    好像太长了一点。不过比起我写的全部还是很短的了:)
    我觉得主要问题可能是这下边的么?//set client message header
      public synchronized void setInMessage(String from,
                                                   String to, boolean ownMessage, String message)
      {
        displayArea.appendInMessage(from, to, ownMessage, message);
        //upperScrollPane.getVerticalScrollBar()
        //      .setValue(upperScrollPane.getVerticalScrollBar().getMaximum());
        upperScrollPane.getViewport().scrollRectToVisible(new Rectangle(0,
            displayArea.getHeight()-upperScrollPane.getHeight()+25,
            displayArea.getWidth(), upperScrollPane.getHeight()-25));
      }
      public synchronized void setAlertMessage(String message)
      {
        SimpleAttributeSet attr = new SimpleAttributeSet();
        StyleConstants.setForeground(attr, Color.GREEN);
        displayArea.append(message+"\n", attr);
        //lowerScrollPane.getVerticalScrollBar()
        //      .setValue(upperScrollPane.getVerticalScrollBar().getMaximum());
        upperScrollPane.getViewport().scrollRectToVisible(new Rectangle(0,
            displayArea.getHeight()-upperScrollPane.getHeight()+25,
            displayArea.getWidth(), upperScrollPane.getHeight()-25));
      }
    另外我还重载了DefaultStyledDocument的insertString方法,大家觉得这个有问题么?
    public void insertString(int offset, String str, AttributeSet a) throws BadLocationException
        {
          int lastPosition = this.getLength();
          if( (lastPosition+str.length()) <= maxLength)
          {
            super.insertString(lastPosition, str, a);
          }
          else if(lastPosition <= maxLength && (lastPosition+str.length()) >= maxLength)
          {
            super.insertString(lastPosition, str.substring(0, maxLength-lastPosition), a);
          }
        }
      

  6.   

    I did not read your code. Put the following test case works!!package com.lanTest;import com.borland.jbcl.layout.*;
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.text.*;
    import java.util.*;
    import java.awt.event.*;
    public class ScrollText extends JFrame {
       private XYLayout xYLayout1 = new XYLayout();
       private JScrollPane jScrollPane1 = new JScrollPane();
       private JTextArea txt = new JTextArea();
       Document m_doc = new DefaultStyledDocument();
       boolean isContinue = true;
       private JButton btnStop = new JButton();
       public static void main(String[] args) {
          ScrollText t = new ScrollText();
          t.setSize(300,200);
          t.show();
       }   public ScrollText() {
          try {
             jbInit();
             txt.setDocument(m_doc);
          }
          catch(Exception e) {
             e.printStackTrace();
          }
          new Thread(new Runnable() {
             public void run() {
                while(true) {
                try{
                   Thread.sleep(1000);
                   if(isContinue)
                   m_doc.insertString(m_doc.getLength(),new Date()+"\nlast line\n",null);
                   txt.scrollRectToVisible(txt.modelToView(m_doc.getLength()));
                }catch(Exception e){}
                }
             }
          }).start();
       }
       private void jbInit() throws Exception {
          this.getContentPane().setLayout(xYLayout1);
          xYLayout1.setWidth(425);
          xYLayout1.setHeight(289);
          btnStop.setText("Stop");
          btnStop.addActionListener(new java.awt.event.ActionListener() {
             public void actionPerformed(ActionEvent e) {
                btnStop_actionPerformed(e);
             }
          });
          this.getContentPane().add(jScrollPane1, new XYConstraints(58, 25, 291, 182));
          this.getContentPane().add(btnStop, new XYConstraints(122, 236, 97, 24));
          jScrollPane1.getViewport().add(txt, null);
       }   void btnStop_actionPerformed(ActionEvent e) {
          isContinue = !isContinue;
          btnStop.setText(isContinue?"Stop":"Resume");
       }
    }
      

  7.   

    问题可能在upperScrollPane.getViewport().scrollRectToVisible(new Rectangle(0,
            displayArea.getHeight()-upperScrollPane.getHeight()+25,
            displayArea.getWidth(), upperScrollPane.getHeight()-25));
    你现在用的还是jviewport的scrollrecttovisible方法,改成
    displayArea.getViewport().scrollRectToVisible(new Rectangle(0,
            displayArea.getHeight()-upperScrollPane.getHeight()+25,
            displayArea.getWidth(), upperScrollPane.getHeight()-25));
    看看。《Java2图形设计V2 Swing》里说法是:一般很少直接调用JViewport.scrollRectToVisible方法,而是为视口的视图调用scrollRectToVisible方法。(你这个例子中upperScrollPane的视图就是displayArea)
      

  8.   

    不知道为什么,还是解决不了哦,如果诸位不信,可以用我的代码试一下。真是很奇怪。另外,Apocalypse(逍遥思辨)好像JTextArea没有getViewPort()方法哦。helpall:你的方法只是每次都跳到textArea的开头,而不是结尾哦。
      

  9.   

    mercury1231仁兄:
      你是试了我的方法还是最后一段代码(打印new Date()+"\nlast line\n"的)?  如果是最后一段代码,这就奇怪了,因为在我这里(JB7中),是跳到最后啊. 我是用JDK1.3.
      

  10.   

    sry, 不用getViewport,如下
    displayArea.scrollRectToVisible(new Rectangle(0,
            displayArea.getHeight()-upperScrollPane.getHeight()+25,
            displayArea.getWidth(), upperScrollPane.getHeight()-25));