【问题标题】:Empty JTabbedPane清空 JTabbedPane
【发布时间】:2014-08-24 20:53:04
【问题描述】:

我在创建一个空的 JTabbedPane 时遇到问题,其中 GUI 上唯一可见的部分是选项卡行。

每次我添加一个带有“空”组件的新选项卡时,JTabbedPane 的高度都会增加,但为什么呢?

当前的解决方法是覆盖getPreferredSize(),但对我来说似乎很笨拙。注释掉被覆盖的方法,看看我的意思。

我是否遗漏了一些明显的东西?


背景:

我们需要一个 JTabbedPane,其中选项卡式窗格从 2 个选项卡开始,但用户可以根据需要添加更多选项卡,最多 10 个。此外,每个选项卡包含相同的组件,但具有不同的数据。决定伪造 JTabbedPane 的外观,实现一个空的 JTabbedPane 仅用于外观,并使用单个固定的 JPanel,其内容将根据单击的选项卡刷新。

(通常,我可以重新创建 JPanel n 次,但这对于控制 UI 的演示者类来说将是一场噩梦,这超出了我的问题范围。)


import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class CustomTabbedPane implements Runnable
{
  static final int MAX_TABS = 11; // includes the "add" tab

  JPanel pnlTabs;
  JTabbedPane tabbedPane;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new CustomTabbedPane());
  }

  public void run()
  {
    JPanel p = buildPanel();
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(p);
    frame.setSize(800,400);
    frame.setVisible(true);
  }

  private JPanel buildPanel()
  {
    tabbedPane = new JTabbedPane()
    {
      @Override
      public Dimension getPreferredSize()
      {
        Dimension dim = super.getPreferredSize();
        dim.height = getUI().getTabBounds(this, 0).height + 1;
        return dim;
      }
    };

    tabbedPane.addTab("Tab 1", getEmptyComp());
    tabbedPane.addTab("Tab 2", getEmptyComp());
    tabbedPane.addTab("+", new TabCreator());

    tabbedPane.addMouseListener(new MouseAdapter()
    {
      @Override
      public void mouseClicked(MouseEvent e)
      {
        addTab();
      }
    });

    JScrollPane scroll = new JScrollPane(new JTable(5,10));

    JPanel p = new JPanel(new BorderLayout());
    p.add(tabbedPane, BorderLayout.NORTH);
    p.add(scroll,  BorderLayout.CENTER);
    p.setBorder(BorderFactory.createLineBorder(Color.BLUE.darker(), 1));

    return p;
  }

  private void addTab()
  {
    if (tabbedPane.getSelectedComponent() instanceof TabCreator)
    {
      int selIndex = tabbedPane.getSelectedIndex();

      if (tabbedPane.getComponentCount() < MAX_TABS)
      {
        if (selIndex == tabbedPane.getComponentCount()-1)
        {
          String title = "Tab " + (selIndex + 1);
          tabbedPane.insertTab(title, null, getEmptyComp(), "", selIndex);
          tabbedPane.setSelectedIndex(selIndex);

          if (tabbedPane.getComponentCount() == MAX_TABS)
          {
            tabbedPane.setEnabledAt(MAX_TABS-1, false);
          }
        }
      }
    }
  }

  private Component getEmptyComp()
  {
    return Box.createVerticalStrut(1);
  }

  class TabCreator extends JLabel {}
}

【问题讨论】:

标签: java swing jtabbedpane


【解决方案1】:

好问题!但是要知道正在发生的事情是相当简单的。

问题是您的内容没有最小宽度,没有设置首选大小,标签位置是顶部/底部,并且 UI 是默认值。

由于未设置首选大小,因此当重新验证布局时,所需空间的计算将进入BasicTabbedPaneUI 方法Dimension calculateSize(false)

上面写着:

int height = 0;
int width = 0;
<other vars>
// Determine minimum size required to display largest
// child in each dimension
<actual method>

在这里它计算容纳任何孩子的最小尺寸并将其存储到高度/宽度中。在您的情况下,这会产生类似 10,10 的结果(因为我认为是单个标签标签创建者,我没有遵循那个)。

然后神奇的事情发生了:

switch(tabPlacement) {
    case LEFT:
    case RIGHT:
        height = Math.max(height, calculateMaxTabHeight(tabPlacement));
        tabExtent = preferredTabAreaWidth(tabPlacement, height - tabAreaInsets.top - tabAreaInsets.bottom);
        width += tabExtent;
        break;
    case TOP:
    case BOTTOM:
    default:
        width = Math.max(width, calculateMaxTabWidth(tabPlacement));
        tabExtent = preferredTabAreaHeight(tabPlacement, width - tabAreaInsets.left - tabAreaInsets.right);
        height += tabExtent;
}

这里发生的情况是将首选宽度设置为最大标签宽度和最大子宽度中的最大值。在您的情况下,选项卡文本约为 44。然后计算tabExtent 以查看需要多少行选项卡来支持此首选宽度。在您的情况下 - 每个选项卡有 1 个额外的选项卡行。这就是preferredSize().height 中额外高度的来源。本质上是因为对于水平标签放置,它首先关心宽度,然后是高度。

如何解决:

  1. 设置首选尺寸 :) 我知道很多人说不要设置首选尺寸,但在这种情况下,这样就可以了。由于设置了首选大小(通过实际设置,而不是覆盖 getPreferredSize()),代码永远不会计算标签。
  2. 给至少一个孩子一个尺码(通过setPreferredSize 或覆盖getPreferredSize)。如果其中一个孩子的宽度是框架的宽度,或者说,底部的表格,TabbedPane 将不会为每个选项卡分配额外的行,因为一行将适合所有内容。
  3. 为选项卡式窗格制作您自己的 UI。制作自己的选项卡式窗格可能更容易,虽然我从来没有这样做过。

编辑:

在考虑了更多之后,我意识到解决方案编号 1 AND 您自己的解决方案存在以下缺陷:如果选项卡式窗格确实需要多行选项卡(你好框架调整大小),坏事就会发生。不要使用它。

【讨论】:

  • +1 好信息。到目前为止(在阅读了您的编辑之后),我对 OP 中的解决方案没有任何问题,可能是因为我只能创建少量固定数量的选项卡。下周我会更深入地研究它。谢谢。
  • @splungebob 我遇到了一个问题,我打开了 6 个标签,然后将窗口设置得足够小,以至于标签无法水平放置。然后它只显示最后 3 个标签
  • @splungebob 我敢肯定,这里有几次“如何在不使用 JTabbedPane 的情况下模拟/绘制 JTabbedPane”,或者在 Coreranch(作者 Walter Laan、Michael Dunn、aterai)
  • @Ordous +1 用于触及问题,不同意 BasicsTabbedPaneUI 中的 setXxxSize,可能对平台和 L&F 敏感,可能对 Nimbus 和 WindowsClassicsL&F 有问题
  • @mKorbel 事实上,正如我在编辑中所说的那样 - setXxxSize 不是解决这个问题的好方法。本质上,这是一个基本 UI/L&F 允许多个选项卡行的问题 - 因此选项卡面板不应比子面板更宽。鉴于您不知道您将被分配的宽度,我看不到不保留几行的方法。一个好的解决方案是像 Firefox 中的可滚动标签(单行,但您可以左右滚动标签),但我不知道有一个 L&F 可以做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 2011-10-11
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 2023-03-16
相关资源
最近更新 更多