2016-01-22 125 views
2

在写这个问题时,我已经能够找到一种方法让它按照我想要的方式行事。根据this,我仍然发布该问题,因为其他人可能会面临类似的问题。JTabbedPane和固定高度内容的尺寸问题

对于用于横向伸展但具有固定高度的内容的JTabbedPane的大小,我有以下问题。 setTabLayoutPolicy()的两个选项似乎都会改变内容的高度,并且不会始终将其显示在首选或最低高度。

在默认WRAP_TAB_LAYOUT,标签窗格不考虑翼片是否实际上堆叠或此刻彼此相邻显示,如所讨论herehere和在this bug report的优选大小。如果基于堆叠的选项卡布置选项卡式窗格,则在有足够的空间让选项卡相互显示时,每增加一个选项卡,内容的高度就会增加约20个像素(一个选项卡的高度)。如果基于彼此相邻显示的选项卡布置选项卡式窗格,则必须堆叠选项卡时,内容高度会降低。

当策略设置为SCROLL_TAB_LAYOUT时,标签栏的高度是固定的,并且布局大部分是正确的。但是,根据外观的不同,标签内容的大小会减少几个像素。我已经能够发现这是由于L & F定义的选项卡区域的插页造成的,这些选项并未纳入选项卡窗格的首选大小计算(请参阅this bug report)。设置UIManager.getDefaults().put("TabbedPane.tabAreaInsets", new Insets(0,0,0,0))适用于某些L & F(例如金属),但不适用于其他(例如Nimbus)。

似乎只有以下选项:

  • 使用堆叠标签,并有额外的高度添加到内容
  • 使用堆叠标签,并有覆盖的内容时,没有足够的空间
  • 使用滚动选项卡并将几个像素添加到选项卡内容的最小/首选大小,使其看起来与每个L都有所不同(但至少内容不应该被截断)
  • 使用滚动的选项卡和设置UI o F中的选项卡面板到一个新的BasicTabbedPaneUI不看,伟大的

有没有干净的方式强制执行该选项卡窗格的内容是在一个固定的HEIGH始终显示?

下面的代码和屏幕截图说明问题

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JTabbedPane; 
import javax.swing.UIManager; 

public class TabbedPaneTest extends JFrame { 

    TabbedPaneTest() { 

     JPanel mainPanel = new JPanel(); 
     mainPanel.setBackground(Color.white); 

     JTabbedPane tabs = new JTabbedPane(); 
     //tabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); // content cut off by a few pixels 
     tabs.setTabPlacement(JTabbedPane.BOTTOM); 

     Dimension min = new Dimension(100,200); 
     Dimension max = new Dimension(Short.MAX_VALUE,Short.MAX_VALUE); 
     //Dimension pref = new Dimension(Short.MAX_VALUE,200); // content cut off when small 
     Dimension pref = new Dimension(0,200); // content gets extra space when large 

     int tabCount = 3; 
     for (int i = 0; i < tabCount; i++) { 
      JLabel content = new JLabel(); 
      content.setMinimumSize(min); 
      content.setMaximumSize(max); 
      content.setPreferredSize(pref); 
      tabs.addTab("lorem ipsum dolor sit amet", content); 
     } 

     // set up and render window 
     getContentPane().add(mainPanel, BorderLayout.CENTER); 
     getContentPane().add(tabs, BorderLayout.PAGE_END); 
     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
     setTitle("JScrollPane Test"); 
     pack(); 
     setSize(700,400); 

     tabs.addComponentListener(new ComponentAdapter() { 
      @Override 
      public void componentResized(ComponentEvent e) { 
       JTabbedPane tabbedPane = (JTabbedPane) e.getComponent(); 
       int tabCount = tabbedPane.getTabCount(); 
       for (int i = 0; i < tabCount; i++) { 
        Component c = tabbedPane.getComponentAt(i); 
        ((JLabel) c).setText("<html>" 
          + getSizes(c, "content") 
          + getSizes(tabbedPane, "tabs") 
          + "</html>"); 
       } 
      } 
     }); 
    } 

    private static String getSizes(Component c, String name) { 
     return "<p>" + name + " - " 
       + " minimum:" + Integer.toString(c.getMinimumSize().width) 
         + "x" + Integer.toString(c.getMinimumSize().height) 
       + " maximum:" + Integer.toString(c.getMaximumSize().width) 
         + "x" + Integer.toString(c.getMaximumSize().height) 
       + " preferred:" + Integer.toString(c.getPreferredSize().width) 
         + "x" + Integer.toString(c.getPreferredSize().height) 
       + " actual:" + Integer.toString(c.getSize().width) 
         + "x" + Integer.toString(c.getSize().height) 
       + "</p>"; 
    } 

    public static void main(String args[]) { 

     /* Set the Nimbus look and feel */ 
     //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> 
     /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. 
     * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */ 
     try { 
      for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { 
       if ("Nimbus".equals(info.getName())) { 
        javax.swing.UIManager.setLookAndFeel(info.getClassName()); 
        break; 
       } 
      } 
     } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) { 
      java.util.logging.Logger.getLogger(TabbedPaneTest.class 
        .getName()).log(java.util.logging.Level.SEVERE, null, ex); 
     } 
     //</editor-fold> 

     /* Create and display the form */ 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      @Override public void run() { 
       new TabbedPaneTest().setVisible(true); 
      } 
     }); 
    } 

} 

随着滚动制表符,内容是由几个像素切断(的193px代替200像素这里):

screenshot with scrolled tabs

使用堆叠的制表符和宽广的内容,当窗口较小(此处为160px而不是200px)时,内容会被切断:

enter image description here

具有堆叠的标签和窄内容时,内容变大时,窗口大(的200像素240像素,而不是在这里):

enter image description here

回答

2

阅读更多有关的方式的优选大小后计算标签窗格,我已经能够为WRAP_TAB_LAYOUT案例提出以下解决方案。

问题是,对于选项卡式窗格,首选的高度和宽度是耦合的。首选高度是针对首选宽度计算的,而不是针对实际当前宽度计算的。如果父级的布局管理器尊重首选高度而不是首选宽度,则这是有问题的。

我想出的解决方案是设置一个侦听器,将每个标签内容的首选宽度设置为其当前宽度。这样,选项卡式窗格就可以正确地计算出其首选高度,并且可以将其布置与BorderLayout。

tabs.addComponentListener(new ComponentAdapter() { 
    @Override 
    public void componentResized(ComponentEvent e) { 
     JTabbedPane tabbedPane = (JTabbedPane) e.getComponent(); 
     int tabCount = tabbedPane.getTabCount(); 
     for (int i = 0; i < tabCount; i++) { 
      Component c = tabbedPane.getComponentAt(i); 
      c.setPreferredSize(new Dimension(c.getSize().width, c.getPreferredSize().height)); 
     } 
    } 
}); 

我一直没能找到一个令人满意的解决SCROLL_TAB_LAYOUT情况下还,所以如果任何人有一个想法,我们将不胜感激。