【问题标题】:Custom JScrollPane. Add a Component on a ScrollBar line自定义 JScrollPane。在 ScrollBar 行上添加组件
【发布时间】:2023-03-07 02:48:02
【问题描述】:

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

如您所见,水平滚动已更改,应在同一行添加 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);
    }
}

【问题讨论】:

  • 我想指出,'hsb' 的宽度没有考虑到标签的位置。您需要将宽度与 12 一起添加。
  • 是的,你是对的,但事实并非如此,位置不是问题。看起来根本没有添加标签,或者它放在其他组件后面,所以我们看不到它。

标签: java swing jscrollpane jlabel jscrollbar


【解决方案1】:

您可能需要考虑自己实现 JScrollPane。听起来可能很吓人,但本质上,一个 JScrollPane 就是 2 个 JScrollBars 和一些调用 g.translate() 的图形逻辑>

制作自己的组件的好处是您可以完全控制布局、显示和事件。如果我处于你的位置,这就是我会采取的路线。

【讨论】:

    【解决方案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);
      }
    }
    

    【讨论】:

    • 非常感谢,这真的很酷!我没有想过这种解决问题的方法。是否可以在滚动条附近添加一个 JComponent(JLabel("Text") 只是一些抽象 JComponent 的一个例子)?实际上,我想在那里添加一个带有放大/缩小按钮的 JPanel
    • @Stas 试试这个链接:Component Border « Java Tips Weblog
    【解决方案3】:

    可能实现此类目标的最佳方法是将您自己的布局与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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多