自定义JScrollPane。在ScrollBar行上添加组件

时间:2012-04-25 20:11:30

标签: java swing jscrollpane jlabel jscrollbar

这就是我想要实现的目标:

enter image description here

如您所见,水平滚动已更改,并且JLabel(" text")应添加到同一行中。目前我找到了改变水平滚动的方法(比如在图像上),但我找不到任何方法在地方放置JLabel(" text"),它放在图像上。

有什么建议吗?提前谢谢!

import java.awt.Component;
import java.awt.Container;
import java.awt.Point;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneLayout;
import javax.swing.WindowConstants;

public class Test {

    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.setSize(300, 300);

        JPanel myPanel = new JPanel();
        myPanel.add(new JLabel("Check Check Check Check Check Check Check Check"));
        MyScrollPane scrollPane = new MyScrollPane(myPanel);

        jFrame.add(scrollPane);
        jFrame.setVisible(true);
        jFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

}

class MyScrollPane extends JScrollPane {

    JLabel label = new JLabel("text");

    public MyScrollPane(Component view) {
        super(view, VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_ALWAYS);
        this.setLayout(new MyLayout(label));
        add(label);
    }
}

class MyLayout extends ScrollPaneLayout {

    JLabel label;

    public MyLayout(JLabel aLabel) {
        super();
        label = aLabel;
    }

    public void layoutContainer(Container parent) {
        super.layoutContainer(parent);

        hsb.setSize(hsb.getWidth() - 100, hsb.getHeight()); // drift
        Point location = hsb.getLocation();
        label.setLocation(location.x + 12, location.y - 12);
    }
}

3 个答案:

答案 0 :(得分:3)

您可能需要考虑自己实现JScrollPane。这可能听起来很可怕,但实质上所有的JScrollPane都是2个JScrollBars和一些调用g.translate()的图形逻辑如果你玩g.translate,你会发现滚动你自己的东西非常容易。

制作自己的组件的好处是您可以完全控制布局,显示和事件。如果我在你的位置,这就是我要走的路。

答案 1 :(得分:2)

这是我的尝试:

import java.awt.*;
import java.awt.font.*;
import javax.swing.*;
import javax.swing.border.*;

public class Test2 {
  public JComponent makeUI() {
    JPanel myPanel = new JPanel();
    myPanel.add(new JLabel("Check Check Check Check Check Check Check Check"));
    JScrollPane scrollPane = new JScrollPane(myPanel,
        JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
        JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    JScrollBar hsb = scrollPane.getHorizontalScrollBar();
    hsb.setBorder(new StringBorder(hsb, "Test"));
    JPanel p = new JPanel(new BorderLayout());
    p.add(scrollPane);
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new Test2().makeUI());
    f.setSize(300, 300);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
class StringBorder implements Border {
  private final JComponent parent;
  private final Insets insets;
  private final Rectangle rect;
  private final String str;
  public StringBorder(JComponent parent, String str) {
    this.parent = parent;
    this.str = str;
    FontRenderContext frc = new FontRenderContext(null, true, true);
    rect = parent.getFont().getStringBounds(str, frc).getBounds();
    rect.width = Math.max(rect.width, 100);
    insets = new Insets(0,5,0,rect.width);
  }
  @Override public Insets getBorderInsets(Component c) {
    return insets;
  }
  @Override public boolean isBorderOpaque() {
    return false;
  }
  @Override public void paintBorder(
      Component c, Graphics g, int x, int y, int width, int height) {
    Graphics2D g2 = (Graphics2D)g;
    float tx = x + width - insets.right + insets.left;
    float ty = y - rect.y + (height - rect.height)/2;
    g2.setPaint(Color.BLACK);
    g2.drawString(str, tx, ty);
  }
}

答案 2 :(得分:0)

实现此类目标的最佳方式可能是使用您自己的布局JScrollPane。这是一个允许任何组件作为左下角组件的示例:

public class CustomScrollPaneLayout extends ScrollPaneLayout {
    @Override
    public void layoutContainer(Container parent) {
        super.layoutContainer(parent);

        JScrollBar scrollBar = getHorizontalScrollBar();
        if (lowerLeft == null || !lowerLeft.isVisible() || scrollBar == null)
            return;

        Dimension size = lowerLeft.getPreferredSize();
        Rectangle bounds = lowerLeft.isVisible()
                ? lowerLeft.getBounds() : scrollBar.getBounds();
        if (size.width > bounds.getWidth()) {
            int right = scrollBar.getX()+scrollBar.getWidth();
            if (size.width + scrollBar.getMinimumSize().width > right)
                size.width = right - scrollBar.getMinimumSize().width;
            if (bounds.x + size.width < scrollBar.getX())
                size.width = scrollBar.getX() - bounds.x;

            lowerLeft.setBounds(bounds.x, bounds.y, size.width, bounds.height);
            int x = bounds.x + size.width;
            scrollBar.setBounds(x, bounds.y, right - x, bounds.height);
        }
        lowerLeft.setVisible(true);
    }
}

请注意,如果您希望控件始终可见,则需要使用ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS的水平滚动条策略。