【发布时间】:2023-03-30 01:08:01
【问题描述】:
我目前正在尝试实现聊天视图。该聊天具有类似于 WhatsApp 或您习惯的其他任何内容的消息气泡。所有消息都在JPanel 内,而JScrollPane 又在JScrollPane 内。消息长度可变,位于JTextArea 中,因此高度和宽度可变。每当JScrollPane 的宽度发生变化时,JViewPort 的大小就会发生变化。由于 y 坐标保持不变,但消息的高度不变,它们在可见视口内移动。在更改JScrollPane 的大小时,是否可以简单地将顶部的消息保留在原处?
我的第一个想法是通过在JScrollPane 的垂直JScrollBar 上添加AdjustmentListener 来跟踪顶部的组件,然后使用ComponentListener#componentResized 调整JScrollPane 的y 坐标。但是,这种方法对我来说似乎有点 hacky,我想知道最干净的方法是什么。也许我想多了,但我希望这是一个相对正常的用例,因此有一个简单的方法可以解决。
这是我的用例的一个最小示例:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.LayoutManager;
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.ScrollPaneConstants;
import javax.swing.Scrollable;
public class Main
{
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",
"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.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, 0 ), 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 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 orientation, final int direction )
{
return 20;
}
@Override
public boolean getScrollableTracksViewportWidth()
{
return true;
}
@Override
public boolean getScrollableTracksViewportHeight()
{
return false;
}
}
}
【问题讨论】:
-
我的第一个想法是…… - 对我来说听起来很合理。我不知道有任何内置的 API 支持这样的东西。
-
感谢您的想法 :)
标签: java swing scroll resize responsive