JTabbedPane 和固定高度内容的大小问题

msc*_*sch 4 java swing jtabbedpane preferredsize

在写这个问题时,我已经找到了一种方法让它按照我想要的方式运行。基于,我仍然发布这个问题,因为其他人可能会遇到类似的问题。

\n\n

对于用于水平拉伸但具有固定高度的内容的 JTabbedPane 的大小调整,我遇到以下问题。这两个选项setTabLayoutPolicy()似乎都会改变内容的高度,并且不会\xe2\x80\x99t始终以其首选或最小高度显示它。

\n\n

在默认情况下WRAP_TAB_LAYOUT,选项卡窗格的首选大小不会考虑选项卡当前是否实际堆叠或彼此相邻显示,如此处此处错误报告中所述。如果选项卡式窗格基于堆叠选项卡进行布局,则当有足够的空间让选项卡彼此相邻显示时,每添加一个选项卡,内容的高度就会增加大约 20 像素(一个选项卡的高度)。如果选项卡式窗格是基于彼此相邻显示的选项卡进行布局的,则当选项卡必须堆叠时,内容高度会降低。

\n\n

当策略设置为 时SCROLL_TAB_LAYOUT,选项卡栏的高度是固定的,布局基本正确。但是,根据外观和感觉,选项卡内容的大小会减少几个像素。我发现这是由于 L&F 定义的选项卡区域的插入导致的,这些插入没有考虑到选项卡窗格的首选大小计算中(请参阅此错误报告)。设置UIManager.getDefaults().put("TabbedPane.tabAreaInsets", new Insets(0,0,0,0))适用于某些 L&F(例如 Metal),但不适用于其他 L&F(例如 Nimbus)。

\n\n

好像只有以下几个选项:

\n\n
    \n
  • 使用堆叠选项卡并为内容添加额外的高度
  • \n
  • 使用堆叠选项卡,并在空间不足时覆盖内容
  • \n
  • 使用滚动选项卡并向选项卡内容的最小/首选大小添加一些像素,使其在每个 L&F 中看起来有点不同(但至少内容不应该被切断)
  • \n
  • 使用滚动选项卡并将选项卡式窗格的 UI 设置为新的,BasicTabbedPaneUI这看起来不太好
  • \n
\n\n

是否有一种干净的方法来强制选项卡式窗格的内容始终以固定高度显示?

\n\n

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

\n\n
import java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Component;\nimport java.awt.Dimension;\nimport java.awt.event.ComponentAdapter;\nimport java.awt.event.ComponentEvent;\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.JTabbedPane;\nimport javax.swing.UIManager;\n\npublic class TabbedPaneTest extends JFrame {\n\n    TabbedPaneTest() {\n\n        JPanel mainPanel = new JPanel();\n        mainPanel.setBackground(Color.white);\n\n        JTabbedPane tabs = new JTabbedPane();\n        //tabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); // content cut off by a few pixels\n        tabs.setTabPlacement(JTabbedPane.BOTTOM);\n\n        Dimension min  = new Dimension(100,200);\n        Dimension max = new Dimension(Short.MAX_VALUE,Short.MAX_VALUE);\n        //Dimension pref = new Dimension(Short.MAX_VALUE,200); // content cut off when small\n        Dimension pref = new Dimension(0,200); // content gets extra space when large\n\n        int tabCount = 3;\n        for (int i = 0; i < tabCount; i++) {\n            JLabel content = new JLabel();\n            content.setMinimumSize(min);\n            content.setMaximumSize(max);\n            content.setPreferredSize(pref);\n            tabs.addTab("lorem ipsum dolor sit amet", content);\n        }\n\n        // set up and render window\n        getContentPane().add(mainPanel, BorderLayout.CENTER);\n        getContentPane().add(tabs, BorderLayout.PAGE_END);\n        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);\n        setTitle("JScrollPane Test");\n        pack();\n        setSize(700,400);\n\n        tabs.addComponentListener(new ComponentAdapter() {\n            @Override\n            public void componentResized(ComponentEvent e) {\n                JTabbedPane tabbedPane = (JTabbedPane) e.getComponent();\n                int tabCount = tabbedPane.getTabCount();\n                for (int i = 0; i < tabCount; i++) {\n                    Component c = tabbedPane.getComponentAt(i);\n                    ((JLabel) c).setText("<html>"\n                            + getSizes(c, "content")\n                            + getSizes(tabbedPane, "tabs")\n                            + "</html>");\n                }\n            }\n        });\n    }\n\n    private static String getSizes(Component c, String name) {\n        return "<p>" + name + " - "\n                + "  minimum:" + Integer.toString(c.getMinimumSize().width)\n                         + "x" + Integer.toString(c.getMinimumSize().height)\n                + "  maximum:" + Integer.toString(c.getMaximumSize().width)\n                         + "x" + Integer.toString(c.getMaximumSize().height)\n                + "  preferred:" + Integer.toString(c.getPreferredSize().width)\n                         + "x" + Integer.toString(c.getPreferredSize().height)\n                + "  actual:" + Integer.toString(c.getSize().width)\n                         + "x" + Integer.toString(c.getSize().height)\n                + "</p>";\n    }\n\n    public static void main(String args[]) {\n\n        /* Set the Nimbus look and feel */\n        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">\n        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.\n         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html\n         */\n        try {\n            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {\n                if ("Nimbus".equals(info.getName())) {\n                    javax.swing.UIManager.setLookAndFeel(info.getClassName());\n                    break;\n                }\n            }\n        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {\n            java.util.logging.Logger.getLogger(TabbedPaneTest.class\n                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);\n        }\n        //</editor-fold>\n\n        /* Create and display the form */\n        java.awt.EventQueue.invokeLater(new Runnable() {\n            @Override public void run() {\n                new TabbedPaneTest().setVisible(true);\n            }\n        });\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用滚动选项卡时,内容会被切断几个像素(此处为 193 像素,而不是 200 像素):

\n\n

带有滚动选项卡的屏幕截图

\n\n

对于堆叠的选项卡和宽内容,当窗口很小时内容会被切断(这里是 160px 而不是 200px):

\n\n

在此输入图像描述

\n\n

通过堆叠选项卡和狭窄内容,当窗口较大时,内容会变大(此处为 240 像素,而不是 200 像素):

\n\n

在此输入图像描述

\n

msc*_*sch 5

在详细了解了选项卡式窗格的首选大小的计算方式之后,我已经能够针对该案例提出以下解决方案WRAP_TAB_LAYOUT

\n\n

问题在于,对于选项卡式窗格,首选高度和宽度是耦合的。首选高度是根据首选宽度计算的,而不是根据实际的当前宽度计算的。如果父级的布局管理器遵循首选高度而不是首选宽度,则会出现问题。

\n\n

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

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

我还没有\xe2\x80\x99t 能够找到一个令人满意的解决方案来解决这个SCROLL_TAB_LAYOUT问题,所以如果有人有想法,我们将不胜感激。

\n