2012-07-15 60 views
4

我已經一個JTable比它包含在JScrollPane的更廣泛的(基本上是這樣定義):水平滾動在JTable中與Nimbus外觀

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中左右滾動。 (我喜歡蘋果的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的正常行爲,還是我可以改變它?如果是這樣,怎麼樣?或者我應該嘗試一種不同的外觀和感覺?

編輯:

我發現了兩件事情:

  1. 我做了擴展JTable中測試這個新類。我從JTable源複製了代碼getScrollableUnitIncrement,並添加了打印語句。傳遞的方向似乎總是SwingConstants.VERTICAL,而在默認的外觀和感覺(Mac Aqua或其他)中,水平和垂直滾動都可以工作。我不知道這是爲什麼。

  2. 該項目的另一部分也依賴於水平滾動。我測試了兩個LaF,並且它在默認情況下運行良好,但Nimbus不允許我水平滾動。

這可能是Nimbus的錯誤嗎?

無論哪種方式,我想我會使用不同的外觀和感覺...

編輯#2:

我之前提到這一點。 I am能夠使用窗口中的滾動條水平滾動,但不能使用我的軌跡板或鼠標滾輪。

回答

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); 
} 
+0

呵呵。不,我無法使用此代碼重現此問題。我不得不添加一堆列,以便JTable從面板延伸出來。當我這樣做,它正確滾動。我會繼續玩。另外,請參閱我的第二次編輯..我應該在之前提到它。 – 2012-07-16 20:13:29

+0

好的,我有你的代碼去做。添加足夠多的列,以便行橫向伸出滾動窗格,並添加足夠的行,以便它也垂直伸展。我做到了,現在它只會垂直滾動。 – 2012-07-16 22:45:15

3

(注:寫這篇文章,我找到了解決辦法,這似乎在這篇文章的附錄)

要重現該問題,您需要所需的滾動條。 (這就是爲什麼有些人在重現這個bug方面有困難。)這意味着顯而易見的解決方法是讓您的水平滾動條成爲可選項。 (這並不總是實用。)

當您將窗口的寬度拖出超過1200像素左右時,您只會看到該錯誤。在此之前,滾動條會正常工作。

而這個問題只出現在Nimbus中。 (它可能出現在SynthLookAndFeel創建的其他L & F中,但我還沒有調查過。)

我發現虛假滾動條的拇指只顯示在您不需要滾動時,所以它只是一個視覺錯誤。當你需要滾動時,滾動條的大拇指會出現並能正常工作,雖然它可能不是合適的尺寸。這可能是它尚未修復的原因。

下面是一個例子,您可以比較不同的L & F。在本例中,選擇Nimbus,然後向內拖動寬度並觀察滾動條大小如何變化。當您比背景圖像更寬時,虛假滾動條將會顯示。一旦變窄,就會出現一個有效的滾動條大拇指,但它會有點過小。當你變小時,滾動條的大拇指會保持一個不變的大小,直到達到某個點(視口寬度爲1282像素),那麼它會開始變小,就像它應該的那樣。

隨着任何其他L & F,只要你比背景圖像窄,拇指會出現,幾乎填滿其空間。隨着窗戶變小,它變得越來越小,就像它應該的那樣。

通過使圖標更小(這一鍛鍊還可將揭示雨雲如何繪製比任何其它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); 
    } 
} 

附錄(視域大小在所述窗口的底部示出。):進一步調查顯示的問題。該NimbusDefaults類,這對於雨雲創建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); 
    } 
    } 
} 

當然,你也可以解決該問題通過使用一個更大的價值非常大的顯示器。

我確認垂直滾動條有完全相同的問題,但只有當窗口垂直方向變得很大時纔會出現。這就是爲什麼這個問題通常只能在水平滾動條上看到的原因。

+0

我剛剛在另一個基於Synth的外觀(Synthetica)中測試了它,它工作正常。所以問題似乎是Nimbus而不是Synth。 (當然,編寫Synthetica的人可能會發現問題並修復它,所以我不能確定。) – 2015-02-05 02:51:38

+0

進一步的測試顯示BoundedRangeModel(JScrollBar的數據模型)具有正確的值並似乎正常工作。我想知道這是否是問題,但現在看起來不是這樣。 – 2015-02-05 19:58:32