我有一个比它所包含的JScrollPane宽的JTable(基本上是这样定义的):
JTable table = new JTable(model);
// I change some things like disallowing reordering, resizing,
// disable column selection, etc.
// I set the default renderer to a DefaultTableCellRenderer
// getTableCellRendererComponent, and then changes the color
// of the cell text depending on the cell value
JPanel panel = new JPanel(new BorderLayout(0, 5));
panel.add(new JScrollPane(table), BorderLayout.CENTER);
// add other stuff to the panel
this.add(panel, BorderLayout.CENTER);
在我将默认的外观改为Nimbus之前,我能够在JTable中左右滚动。 (我喜欢Mac LaF,但它在Windows上不受支持,而且我认为Windows LaF很丑陋),
我直接从Java教程中获取了以下代码:
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// If Nimbus is not available, you can set the GUI to another look
// and feel.
}
我重新编译并运行代码而不更改上面的任何表定义,我无法再在JTable中水平滚动。
我似乎无法找到导致此问题的任何内容。这是Nimbus的正常行为,还是可以更改它?如果是这样,怎么样?或者我应该尝试不同的外观和感觉?
修改
我发现了两件事:
我创建了一个扩展JTable的新类来测试它。我从JTable源复制了getScrollableUnitIncrement
的代码,并添加了print语句。传递的方向似乎始终为SwingConstants.VERTICAL
,而在默认的外观(Mac Aqua或其他)中,水平和垂直滚动都有效。我不知道为什么会这样。
该项目的另一部分还依赖于水平滚动。我用两个LaF进行了测试,它在默认情况下运行良好,但Nimbus也不允许我水平滚动。
这可能是Nimbus的错误吗?
无论哪种方式,我想我会使用不同的外观......
编辑#2:
我之前应该提到这一点。我我能够使用窗口中的滚动条水平滚动,但不能使用我的鼠标上的滚轮或滚轮。
答案 0 :(得分:3)
(注意:写完之后,我找到了一个解决方案,该解决方案出现在本文的附录中。)
要重现此问题,您需要制作所需的滚动条。 (这就是为什么有些人在重现这个bug时遇到麻烦。)这意味着明显的解决方法是让你的水平滚动条可选。 (这并不总是实用的。)
当您将窗口的宽度拖动到超过1200像素左右时,您才会看到错误。在此之前,滚动条将正常工作。
问题只出现在Nimbus上。 (它可能出现在SynthLookAndFeel创建的其他L& Fs中,但我还没有调查过。)
我发现当你不需要滚动时,虚假的滚动条拇指只显示出来,所以它只是一个视觉错误。当您需要滚动时,滚动条拇指将出现并且将正常工作,尽管它可能不是正确的尺寸。这可能就是它尚未修复的原因。
这是一个可以比较不同L& Fs的例子。在此示例中,选择Nimbus,然后向内拖动宽度并观察滚动条的大小如何变化。如果您比背景图像宽,则可以看到虚假滚动条。一旦变窄,就会出现一个有效的滚动条拇指,但它会有点太小。当你变小时,滚动条拇指将保持一个恒定的大小,直到你到达某个点,(在视口宽度为1282像素)然后它将开始变小,就像它应该的那样。
对于任何其他L& F,只要你比背景图像更窄,就会出现一个几乎填满其空间的拇指。随着窗口变小,它变得越来越小,就像它应该的那样。
(此练习还将揭示Nimbus如何比任何其他L& F慢得多。)
通过缩小图标,您可以观察到不同但仍然不正确的行为。尝试800 x 450.当视口宽度> 1时,将出现虚假滚动条。 1035.(视口大小显示在窗口底部。)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* NimbusScrollBug
* <p/>
* @author Miguel Muñoz
*/
public class NimbusScrollBug extends JPanel {
private static final long serialVersionUID = -4235866781219951631L;
private static JFrame frame;
private static boolean firstTime = true;
private static Point location;
private static final UIManager.LookAndFeelInfo[] INFOS
= UIManager.getInstalledLookAndFeels();
private final JLabel viewPortLabel = new JLabel();
public static void main(final String[] args) {
makeMainFrame(new NimbusScrollBug(), "System");
}
public static void makeMainFrame(final NimbusScrollBug mainPanel,
final String name) {
if (firstTime) {
installLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
frame = new JFrame(name);
final Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(mainPanel, BorderLayout.CENTER);
contentPane.add(makeButtonPane(mainPanel), BorderLayout.LINE_START);
frame.setLocationByPlatform(firstTime);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setVisible(true);
if (firstTime) {
location = frame.getLocation();
} else {
frame.setLocation(location);
}
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentMoved(final ComponentEvent e) {
location = e.getComponent().getLocation();
}
});
firstTime = false;
}
private static JPanel makeButtonPane(final NimbusScrollBug mainPanel) {
JPanel innerButtonPanel = new JPanel(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.gridx = 0; // forces vertical layout.
for (final UIManager.LookAndFeelInfo lAndF : INFOS) {
final JButton button = new JButton(lAndF.getName());
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
frame.dispose();
installLookAndFeel(lAndF.getClassName());
makeMainFrame(new NimbusScrollBug(), lAndF.getName());
}
});
innerButtonPanel.add(button, constraints);
}
final String version = System.getProperty("java.version");
JLabel versionLabel = new JLabel("Java Version " + version);
innerButtonPanel.add(versionLabel, constraints);
JPanel outerButtonPanel = new JPanel(new BorderLayout());
outerButtonPanel.add(innerButtonPanel, BorderLayout.PAGE_START);
return outerButtonPanel;
}
private static void installLookAndFeel(final String className) {
//noinspection OverlyBroadCatchBlock
try {
UIManager.setLookAndFeel(className);
} catch (Exception e) {
//noinspection ProhibitedExceptionThrown
throw new RuntimeException(e);
}
}
private NimbusScrollBug() {
Icon icon = new Icon() {
@Override
public void paintIcon(final Component c, final Graphics g,
final int x, final int y) {
Graphics2D g2 = (Graphics2D) g;
g2.translate(x, y);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Stroke lineStroke = new BasicStroke(6.0f);
g2.setStroke(lineStroke);
g2.setColor(Color.white);
g2.fillRect(0, 0, getIconWidth(), getIconHeight());
g2.setColor(Color.RED);
g2.drawLine(0, 0, getIconWidth(), getIconHeight());
g2.drawLine(0, getIconHeight(), getIconWidth(), 0);
g2.dispose();
}
@Override
public int getIconWidth() {
return 1600;
}
@Override
public int getIconHeight() {
return 900;
}
};
JLabel label = new JLabel(icon);
setLayout(new BorderLayout());
final JScrollPane scrollPane = new JScrollPane(label,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
label.addHierarchyBoundsListener(new HierarchyBoundsAdapter() {
@Override
public void ancestorResized(final HierarchyEvent e) {
viewPortLabel.setText("ViewPort Size: "
+ scrollPane.getViewport().getSize());
}
});
add(scrollPane, BorderLayout.CENTER);
add(viewPortLabel, BorderLayout.PAGE_END);
}
}
附录: 进一步调查发现了这个问题。 NimbusDefaults类为Nimbus创建了UIDefaults实例,它有这一行:
d.put("ScrollBar.maximumThumbSize", new DimensionUIResource(1000, 1000));
任何其他外观对两个值都使用4096(因此,对于非常大的显示器,它们将显示相同的行为)。
以下方法可用于安装任何外观,将解决此问题:
private static void installLookAndFeel(final String className) {
//noinspection OverlyBroadCatchBlock
try {
Class<?> lnfClass = Class.forName(className, true,
Thread.currentThread().getContextClassLoader());
final LookAndFeel lAndF;
lAndF = (LookAndFeel) lnfClass.getConstructor().newInstance();
// Reset the defaults after instantiating, but before
// calling UIManager.setLookAndFeel(). This fixes the Nimbus bug
DimensionUIResource dim = new DimensionUIResource(4096, 4096);
lAndF.getDefaults().put("ScrollBar.maximumThumbSize", dim);
UIManager.setLookAndFeel(lAndF);
} catch (Exception e) {
final String systemName = UIManager.getSystemLookAndFeelClassName();
// Prevents an infinite recursion that's not very likely...
// (I like to code defensively)
if (!className.equals(systemName)) {
installLookAndFeel(systemName);
} else {
// Feel free to handle this any other way.
//noinspection ProhibitedExceptionThrown
throw new RuntimeException(e);
}
}
}
当然,您可以使用更大的值来解决真正大型显示器的问题。
我确认垂直滚动条有完全相同的问题,但仅在窗口垂直变大时才能看到。这就是为什么这个问题通常只能在水平滚动条中看到的原因。
答案 1 :(得分:0)
根据您提供的信息,我无法重新创建您的问题(因此无法帮助您找出问题所在)。这是一个适合我的sscce。你能用这个例子重现这个问题吗?也许问题是从应用程序的不同部分逐渐消失。
public static void main(String[] args){
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// If Nimbus is not available, you can set the GUI to another look and feel.
}
//Create Frame
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create Table
JTable table = new JTable(0, 2);
((DefaultTableModel) table.getModel()).addRow(new Object[]{"Sample Text", "Hi Mom!"});
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// Wrap table in Scroll pane and add to frame
frame.add(new JScrollPane(table), BorderLayout.CENTER);
// Finish setting up the frame and display
frame.setBounds(0, 0, 600,400);
frame.setPreferredSize(new Dimension(600, 400));
frame.pack();
frame.setVisible(true);
}