簡體   English   中英

使用Nimbus外觀在JTable中水平滾動

[英]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的正常行為,還是可以更改它? 如果是這樣,怎么樣? 或者我應該嘗試不同的外觀和感覺?

編輯:

我發現了兩件事:

  1. 我創建了一個擴展JTable的新類來測試它。 我從JTable源復制了getScrollableUnitIncrement的代碼,並添加了print語句。 傳遞的方向似乎總是SwingConstants.VERTICAL ,而在默認的外觀(Mac Aqua或其他)中,水平和垂直滾動都有效。 我不知道為什么會這樣。

  2. 該項目的另一部分還依賴於水平滾動。 我用兩個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM