Thu*_*rge 10 java swing jscrollpane
我在同一个窗口中有两个JScrollPanes.左侧的那个足够大,可以显示所包含面板的内容.右边的那个不够大,无法显示其内容,因此需要创建一个垂直滚动条.

但正如您所看到的,问题是当出现垂直滚动条时,滚动条会出现在JScrollPane 的内部.它覆盖了内部包含的内容,因此需要水平滚动条来显示所有内容.我想要那个固定的.
我意识到我可以一直打开垂直滚动条,但出于美观原因,我只希望它在必要时出现,而不需要出现水平滚动条.
编辑:我的启动代码很简单:
JScrollPane groupPanelScroller = new JScrollPane(groupPanel);
this.add(groupPanelScroller, "align center");
Run Code Online (Sandbox Code Playgroud)
我正在使用MigLayout(MigLayout.com),但无论我使用什么版面管理器,这个问题似乎都会出现.此外,如果我缩小窗口以使左面板不再大到足以显示所有内容,则会出现与右面板相同的行为.
kle*_*tra 11
第一:永远不要调整组件级别的大小提示.特别是当你有一个强大的LayoutManager,比如MigLayout,它支持在管理器级别进行调整时.
在代码中,调整任何内容的pref大小:
// calculate some width to add to pref, f.i. to take the scrollbar width into account
final JScrollPane pane = new JScrollPane(comp);
int prefBarWidth = pane.getVerticalScrollBar().getPreferredSize().width;
// **do not**
comp.setPreferredSize(new Dimension(comp.getPreferredSize().width + prefBarWidth, ...);
// **do**
String pref = "(pref+" + prefBarWidth + "px)";
content.add(pane, "width " + pref);
Run Code Online (Sandbox Code Playgroud)
这就是说:基本上,你在ScrollPaneLayout中遇到了一个(可论证的)错误.虽然它看起来像考虑滚动条宽度,但它实际上并非在所有情况下.来自preferredLayoutSize的相关片段
// filling the sizes used for calculating the pref
Dimension extentSize = null;
Dimension viewSize = null;
Component view = null;
if (viewport != null) {
extentSize = viewport.getPreferredSize();
view = viewport.getView();
if (view != null) {
viewSize = view.getPreferredSize();
} else {
viewSize = new Dimension(0, 0);
}
}
....
// the part trying to take the scrollbar width into account
if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
prefWidth += vsb.getPreferredSize().width;
}
else if ((viewSize != null) && (extentSize != null)) {
boolean canScroll = true;
if (view instanceof Scrollable) {
canScroll = !((Scrollable)view).getScrollableTracksViewportHeight();
}
if (canScroll &&
// following condition is the **culprit**
(viewSize.height > extentSize.height)) {
prefWidth += vsb.getPreferredSize().width;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是罪魁祸首,因为
结果就是你所看到的:滚动条与视图重叠(在切断一些宽度的意义上).
黑客攻击是一个自定义ScrollPaneLayout,如果视图的高度小于实际视口高度,则会添加滚动条宽度,这是一个粗略的示例(注意:不是生产质量)
public static class MyScrollPaneLayout extends ScrollPaneLayout {
@Override
public Dimension preferredLayoutSize(Container parent) {
Dimension dim = super.preferredLayoutSize(parent);
JScrollPane pane = (JScrollPane) parent;
Component comp = pane.getViewport().getView();
Dimension viewPref = comp.getPreferredSize();
Dimension port = pane.getViewport().getExtentSize();
// **Edit 2** changed condition to <= to prevent jumping
if (port.height < viewPref.height) {
dim.width += pane.getVerticalScrollBar().getPreferredSize().width;
}
return dim;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑
嗯...看到跳跃(在显示与不显示垂直滚动条之间,如评论中所述):当我将示例中的文本字段替换为另一个scrollPane时,然后调整"靠近"它的pref宽度显示问题.所以hack不够好,可能是因为询问视口的范围是不正确的(在布局过程中).目前不知道,如何做得更好.
编辑2
暂时跟踪:当逐像素宽度改变时,感觉就像一次性错误.从改变条件<来<=似乎解决跳跃-在一直在增加的滚动条宽度的价格.总的来说,这导致第一步有更广泛的尾随插入;-)同时相信scollLlayout的整个逻辑需要改进......
总结您的选择:
下面是代码示例:
// adjust the pref width in the component constraint
MigLayout layout = new MigLayout("wrap 2", "[][]");
final JComponent comp = new JPanel(layout);
for (int i = 0; i < 10; i++) {
comp.add(new JLabel("some item: "));
comp.add(new JTextField(i + 5));
}
MigLayout outer = new MigLayout("wrap 2",
"[][grow, fill]");
JComponent content = new JPanel(outer);
final JScrollPane pane = new JScrollPane(comp);
int prefBarWidth = pane.getVerticalScrollBar().getPreferredSize().width;
String pref = "(pref+" + prefBarWidth + "px)";
content.add(pane, "width " + pref);
content.add(new JTextField("some dummy") );
Action action = new AbstractAction("add row") {
@Override
public void actionPerformed(ActionEvent e) {
int count = (comp.getComponentCount() +1)/ 2;
comp.add(new JLabel("some Item: "));
comp.add(new JTextField(count + 5));
pane.getParent().revalidate();
}
};
frame.add(new JButton(action), BorderLayout.SOUTH);
frame.add(content);
frame.pack();
frame.setSize(frame.getWidth()*2, frame.getHeight());
frame.setVisible(true);
// use a custom ScrollPaneLayout
MigLayout layout = new MigLayout("wrap 2", "[][]");
final JComponent comp = new JPanel(layout);
for (int i = 0; i < 10; i++) {
comp.add(new JLabel("some item: "));
comp.add(new JTextField(i + 5));
}
MigLayout outer = new MigLayout("wrap 2",
"[][grow, fill]");
JComponent content = new JPanel(outer);
final JScrollPane pane = new JScrollPane(comp);
pane.setLayout(new MyScrollPaneLayout());
content.add(pane);
content.add(new JTextField("some dummy") );
Action action = new AbstractAction("add row") {
@Override
public void actionPerformed(ActionEvent e) {
int count = (comp.getComponentCount() +1)/ 2;
comp.add(new JLabel("some Item: "));
comp.add(new JTextField(count + 5));
pane.getParent().revalidate();
}
};
frame.add(new JButton(action), BorderLayout.SOUTH);
frame.add(content);
frame.pack();
frame.setSize(frame.getWidth()*2, frame.getHeight());
frame.setVisible(true);
Run Code Online (Sandbox Code Playgroud)