[英]Scroll horizontally in JTable with Nimbus look and feel
我有一個比它包含的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:
我之前應該提到這一點。 我能夠在窗口滾動條水平滾動,但不符合我的跟蹤墊或在我的鼠標滾輪。
(注意:寫完之后,我找到了一個解決方案,該解決方案出現在本文的附錄中。)
要重現該問題,您需要使滾動條成為必需。 (這就是為什么有些人在重現這個bug時遇到麻煩。)這意味着明顯的解決方法是讓你的水平滾動條可選。 (這並不總是實用的。)
將窗口寬度拖動到1200像素左右時,您只會看到錯誤。 在此之前,滾動條將正常工作。
而這個問題只出現在Nimbus上。 (它可能出現在從SynthLookAndFeel創建的其他L&F中,但我還沒有調查過。)
我發現當你不需要滾動時,虛假的滾動條拇指只顯示出來,所以這只是一個視覺錯誤。 當您需要滾動時,滾動條拇指將出現並且將正常工作,盡管它可能不是正確的尺寸。 這可能是它尚未修復的原因。
這是一個可以比較不同L&F的例子。 在此示例中,選擇Nimbus,然后向內拖動寬度並觀察滾動條的大小如何變化。 當您比背景圖像寬時,將顯示虛假滾動條。 一旦變窄,就會出現一個有效的滾動條拇指,但它會有點太小。 當你變小時,滾動條拇指將保持恆定的大小,直到你到達某個點,(在視口寬度為1282像素)然后它將開始變小,就像它應該的那樣。
對於任何其他L&F,只要你比背景圖像更窄,就會出現一個幾乎填滿其空間的拇指。 隨着窗口變小,它變得越來越小,就像它應該的那樣。
(這項練習還將揭示Nimbus如何比任何其他L&F吸引得慢得多。)
您可以通過縮小圖標來觀察不同但仍然不正確的行為。 嘗試800 x 450.當視口寬度> 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);
}
}
附錄:進一步調查顯示了這個問題。 為Nimbus創建UIDefaults實例的NimbusDefaults類具有以下特性:
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);
}
}
}
當然,您可以通過使用更大的值來解決真正大型顯示器的問題。
我確認垂直滾動條有完全相同的問題,但僅在窗口垂直變大時才能看到。 這就是為什么這個問題通常只能在水平滾動條中看到的原因。
根據您提供的信息,我無法重新創建您的問題(因此無法幫助您弄清楚出了什么問題)。 這是一個適合我的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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.