JScrollPane-防止顶部的可见组件移动

我当前正在尝试实现聊天视图。该聊天具有类似于WhatsApp或其他您习惯的消息气泡。所有消息都位于JPanel内部的JScrollPane内部。消息的长度是可变的,并且在JTextArea中,因此消息的高度和宽度是可变的。每当JScrollPane的宽度改变时,jviewPort的大小就会改变。由于y坐标保持不变,但消息的高度不同,因此它们在可见视口内移动。更改JScrollPane的大小时,是否可以仅保留顶部的消息?

我的第一个想法是通过在AdjustmentListener的垂直JScrollBar上添加JScrollPane来跟踪组件的顶部,然后调整{{1 }},方法是使用JScrollPane。但是,这种方法对我来说似乎有点棘手,我想知道这样做最干净的方法是什么。也许我想得太多,但是我希望这是一个相对正常的用例,因此有一种直接的解决方法。

这是我的用例的最小示例:

ComponentListener#componentResized
woshill78 回答:JScrollPane-防止顶部的可见组件移动

  

添加AdjustmentListener ...,然后使用JScrollPane调整ComponentListener#componentResized的y坐标。

也许另一个选择是覆盖ScrollablePanel#doLayout()方法:

private static class ScrollablePanel extends JPanel implements Scrollable {
  public ScrollablePanel( LayoutManager layout ) {
    super( layout );
  }

  @Override public void doLayout() {
    Container p = SwingUtilities.getAncestorOfClass(JViewport.class,this);
    if (!(p instanceof JViewport)) {
        super.doLayout();
        return;
      }
      JViewport vport = (JViewport) p;
      Rectangle vrect = vport.getViewRect();

      // search the message bubble that is at the top
      Component tgt = null;
      for (Component c: getComponents()) {
        // not considered if the message bubble height is greater than the viewport height.
        if (vrect.contains(c.getLocation())) {
          tgt = c;
          break;
        }
      }

      // causes this container to lay out its components
      super.doLayout();

      // keep the message bubble that is at the top
      if (tgt != null) {
        Point vp = vport.getViewPosition();
        vp.y = tgt.getY();
        vport.setViewPosition(vp);
      }
    }
// ...

Main2.java

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;

import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;

public class Main2
{
  public static void main( String[] args ) throws Exception
  {
    final JPanel layout = new ScrollablePanel( new GridBagLayout() );
    GridBagConstraints constraints = new GridBagConstraints();
    constraints.gridx = 0;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.weightx = 1.0;
    for ( int i = 0; i < 20; i++ )
    {
      layout.add( createMessage( "Marcel: " + i,"Lorem mauris sea aliquam ut justo splendide rhoncus ipsum leo ipsum impedit duo graeci insolens est mea dicunt kasd mus nullam elementum ei tincidunt ullamcorper cetero et aliquyam uonsetetur imperdiet kasd at adipisci nec justo amet duo aliquam at rhoncus nullam splendide facilisi invidunt antiopam duo et splendide amet te vitae partiendo at per inimicus imperdiet rhoncus labore usu vel assentior cursus kasd kasd semper duo vitae mauris his qui aliquyam uonsetetur dicunt eu in habeo takimata definiebas splendide duo kasd qui duo et ullamcorper dicunt Vulputate uonsetetur ullamcorper mauris sea eleifend duo ei definiebas kasd vitae graeci labore inimicus usu vis semper assentior ne odio elementum elementum imperdiet temporibus habeo est ullamcorper semper odio arcu cetero partiendo his eteu iusto corrumpit mus eteu corpora penatibus ut qui pretium te corrumpit his aenean voluptua ipsum his Vulputate usu est insolens assentior arcu et sea aliquyam dicunt inimicus ut nullam ei mauris vis semper duo insolens repudiandae vitae mauris repudiandae definiebas est nec ius labore iusto nec usu dicta ullamcorper in tincidunt mauris voluptua ipsum ut Ut ne dicta aenean eam insolens elementum vitae elementum officiis imperdiet assentior ut ut aliquyam rhoncus vis his invidunt eos est eteu temporibus ei temporibus","20.19.2019",false ),constraints,0 );
    }

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane()
        .add( new JScrollPane( layout,ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER ) );
    frame.setSize( 400,300 );
    frame.setVisible( true );
  }

  private static Component createMessage( String author,String message,String date,boolean left )
  {
    JPanel messagePanel = new JPanel( new GridBagLayout() )
    {
      @Override
      public Dimension getMinimumSize()
      {
        //Making sure that the panel can shrink and not only grow.
        final Dimension minimumSize = super.getMinimumSize();
        minimumSize.width = 0;
        return minimumSize;
      }
    };

    final JLabel authorLabel = new JLabel( author );
    final JLabel dateLabel = new JLabel( date );
    final JTextArea messageText = new JTextArea( message );
    messageText.setEditable( false );
    messageText.setLineWrap( true );

    GridBagConstraints constraints = new GridBagConstraints();
    constraints.gridx = 0;
    constraints.gridy = 0;
    messagePanel.add( authorLabel,constraints );
    constraints.gridx = 1;
    constraints.anchor = GridBagConstraints.EAST;
    messagePanel.add( dateLabel,constraints );
    constraints.gridx = 0;
    constraints.gridy = 1;
    constraints.gridwidth = 2;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.weightx = 1.0;
    messagePanel.add( messageText,constraints );

    final Box box = Box.createHorizontalBox();
    final Box.Filler filler = new Box.Filler( new Dimension( 20,0 ),new Dimension( 100,new Dimension( 200,0 ) );
    box.add( left ? messagePanel : filler );
    box.add( Box.createHorizontalGlue() );
    box.add( left ? filler : messagePanel );
    box.add( Box.createHorizontalGlue() );
    return box;
  }

  private static class ScrollablePanel extends JPanel implements Scrollable
  {
    public ScrollablePanel( LayoutManager layout )
    {
      super( layout );
    }

    @Override public void doLayout() {
      Container p = SwingUtilities.getAncestorOfClass(JViewport.class,this);
      if (!(p instanceof JViewport)) {
        super.doLayout();
        return;
      }
      JViewport vport = (JViewport) p;
      Rectangle vrect = vport.getViewRect();

      Component tgt = null;
      for (Component c: getComponents()) {
        if (vrect.contains(c.getLocation())) {
          tgt = c;
          break;
        }
      }
      super.doLayout();
      if (tgt != null) {
        Point vp = vport.getViewPosition();
        vp.y = tgt.getY();
        vport.setViewPosition(vp);
      }
    }

    @Override
    public Dimension getPreferredScrollableViewportSize()
    {
      return getLayout().preferredLayoutSize( this );
    }

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

    @Override
    public int getScrollableBlockIncrement( final Rectangle visibleRect,final int direction )
    {
      return 20;
    }

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

    @Override
    public boolean getScrollableTracksViewportHeight()
    {
      return false;
    }
  }
}
本文链接:https://www.f2er.com/3118692.html

大家都在问