-
Bug
-
Resolution: Fixed
-
P3
-
7, 8, 9, 10, 11, 12
-
b14
-
x86_64
-
windows_10
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8244168 | 11.0.9-oracle | Prasanta Sadhukhan | P3 | Resolved | Fixed | b01 |
JDK-8235923 | 11.0.7 | Prasanta Sadhukhan | P3 | Resolved | Fixed | b01 |
ADDITIONAL SYSTEM INFORMATION :
Windows 10 Pro, 64 bit
Tested on:
JDK 1.8.0_192, 64 bit
JDK 1.9.0_01, 64 bit
JDK 1.10.0_02, 64 bit
JDK 1.11.0_01, 64 bit
A DESCRIPTION OF THE PROBLEM :
I would like to reopen "JDK-7151452 : JTabbedPane preferred size calculation
is wrong for SCROLL_TAB_LAYOUT"
(https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7151452).
I am still experiencing the same problem, so as suggested in a comment to the
original report, I am reopening it under a new version. It was suggested
to specify 9 as the affected version, but that's not possible anymore, so I
used 10, but I experience the same problem in versions 8, 9, and 11.
Also, I found where the problem is in the code and how to fix it.
Namely, the problem is in the following methods of the
BasicTabbedPaneUI.TabbedPaneScrollLayout inner class:
protected int preferredTabAreaHeight(int tabPlacement, int width) {
return calculateMaxTabHeight(tabPlacement);
}
protected int preferredTabAreaWidth(int tabPlacement, int height) {
return calculateMaxTabWidth(tabPlacement);
}
These methods are defined in the superclass, BasicTabbedPaneUI.TabbedPaneLayout,
and overridden here. While in the superclass these methods take into account the
tab area insents, the overridden methods don't, and so they break the implicit
contract and yield a number that is too small.
Therefore, the solution is to add the correct insets in the overridden methods
to the result before returning it. There are two ways of doing this. One is to
do it manually in these methods, like:
protected int preferredTabAreaHeight(int tabPlacement, int width) {
Insets tabAreaInsets = getTabAreaInsets(tabPlacements);
return calculateMaxTabHeight(tabPlacement) + tabAreaInsets.top + tabAreaInsets.bottom;
}
protected int preferredTabAreaWidth(int tabPlacement, int height) {
Insets tabAreaInsets = getTabAreaInsets(tabPlacements);
return calculateMaxTabWidth(tabPlacement) + tabAreaInsets.left + tabAreaInsets.right;
}
The other solution is to use calculateTabAreaHeight() and
calculateTabAreaWidth(), respectively:
protected int preferredTabAreaHeight(int tabPlacement, int width) {
return calculateTabAreaHeight(tabPlacement, 1, calculateMaxTabHeight(tabPlacement));
}
protected int preferredTabAreaWidth(int tabPlacement, int height) {
return calculateTabAreaWidth(tabPlacement, 1, calculateMaxTabWidth(tabPlacement));
}
I find the second solution cleaner since we are reusing the existing methods for
calculating the size instead of repeating the logic. These methods are also used
for calculating the size for the WRAP_TAB_LAYOUT, only that there the number of
rows/columns need to be calculated first, whereas here we can simply pass 1.
On the other hand, the first solution might have some slight performance benefit,
but maybe that's not significant.
Anyway, I provide both solutions so you can choose the one you prefer.
Finally, I wanted to add that while the original issue is only about preferred size, both the
problem and the fix apply to minimum size as well.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the original example (copied here for convenience), and compare the two frames.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Both frames should have the same size and show the full content.
ACTUAL -
Only the frame using WRAP_TAB_LAYOUT shows the full content, whereas the height of the one using SCROLL_TAB_LAYOUT is too small and thus does not show the full content.
---------- BEGIN SOURCE ----------
// This is copied from the original issue for convenience
package tabprob;
import java.awt.*;
import javax.swing.*;
public class TabProb extends JFrame {
class FixLayout implements LayoutManager {
@Override
public void layoutContainer(Container C) {
Insets in = C.getInsets();
int w = 200 - in.left - in.right;
int h = 100 - in.top - in.bottom;
C.getComponents()[0].setBounds(in.top, in.left, w, h);
}
@Override
public Dimension minimumLayoutSize(Container C) {
return new Dimension(200, 100);
}
@Override
public Dimension preferredLayoutSize(Container C) {
return new Dimension(200, 100);
}
@Override
public void removeLayoutComponent(Component c) {
}
@Override
public void addLayoutComponent(String s, Component c) {
}
}
public TabProb(int layoutPolicy) {
JTabbedPane tabpanel = new JTabbedPane();
tabpanel.setTabPlacement(JTabbedPane.TOP);
tabpanel.setTabLayoutPolicy(layoutPolicy);
JPanel panel = new JPanel(new FixLayout());
JLabel label = new JLabel("TEST");
label.setBorder(BorderFactory.createLineBorder(Color.green, 3));
panel.add(label);
tabpanel.add("TEST", panel);
add(tabpanel, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String[] args) {
try {
//UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch(Exception e) {
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
TabProb tb1 = new TabProb(JTabbedPane.SCROLL_TAB_LAYOUT);
tb1.pack();
tb1.setVisible(true);
TabProb tb2 = new TabProb(JTabbedPane.WRAP_TAB_LAYOUT);
tb2.pack();
tb2.setVisible(true);
}
});
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
From the original report:
1) Set a large enough inset for the contentpanel, or
2) Set TabbedPane.tabAreaInsets to Insets(0,0,0,0)
FREQUENCY : always
Windows 10 Pro, 64 bit
Tested on:
JDK 1.8.0_192, 64 bit
JDK 1.9.0_01, 64 bit
JDK 1.10.0_02, 64 bit
JDK 1.11.0_01, 64 bit
A DESCRIPTION OF THE PROBLEM :
I would like to reopen "
is wrong for SCROLL_TAB_LAYOUT"
(https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7151452).
I am still experiencing the same problem, so as suggested in a comment to the
original report, I am reopening it under a new version. It was suggested
to specify 9 as the affected version, but that's not possible anymore, so I
used 10, but I experience the same problem in versions 8, 9, and 11.
Also, I found where the problem is in the code and how to fix it.
Namely, the problem is in the following methods of the
BasicTabbedPaneUI.TabbedPaneScrollLayout inner class:
protected int preferredTabAreaHeight(int tabPlacement, int width) {
return calculateMaxTabHeight(tabPlacement);
}
protected int preferredTabAreaWidth(int tabPlacement, int height) {
return calculateMaxTabWidth(tabPlacement);
}
These methods are defined in the superclass, BasicTabbedPaneUI.TabbedPaneLayout,
and overridden here. While in the superclass these methods take into account the
tab area insents, the overridden methods don't, and so they break the implicit
contract and yield a number that is too small.
Therefore, the solution is to add the correct insets in the overridden methods
to the result before returning it. There are two ways of doing this. One is to
do it manually in these methods, like:
protected int preferredTabAreaHeight(int tabPlacement, int width) {
Insets tabAreaInsets = getTabAreaInsets(tabPlacements);
return calculateMaxTabHeight(tabPlacement) + tabAreaInsets.top + tabAreaInsets.bottom;
}
protected int preferredTabAreaWidth(int tabPlacement, int height) {
Insets tabAreaInsets = getTabAreaInsets(tabPlacements);
return calculateMaxTabWidth(tabPlacement) + tabAreaInsets.left + tabAreaInsets.right;
}
The other solution is to use calculateTabAreaHeight() and
calculateTabAreaWidth(), respectively:
protected int preferredTabAreaHeight(int tabPlacement, int width) {
return calculateTabAreaHeight(tabPlacement, 1, calculateMaxTabHeight(tabPlacement));
}
protected int preferredTabAreaWidth(int tabPlacement, int height) {
return calculateTabAreaWidth(tabPlacement, 1, calculateMaxTabWidth(tabPlacement));
}
I find the second solution cleaner since we are reusing the existing methods for
calculating the size instead of repeating the logic. These methods are also used
for calculating the size for the WRAP_TAB_LAYOUT, only that there the number of
rows/columns need to be calculated first, whereas here we can simply pass 1.
On the other hand, the first solution might have some slight performance benefit,
but maybe that's not significant.
Anyway, I provide both solutions so you can choose the one you prefer.
Finally, I wanted to add that while the original issue is only about preferred size, both the
problem and the fix apply to minimum size as well.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the original example (copied here for convenience), and compare the two frames.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Both frames should have the same size and show the full content.
ACTUAL -
Only the frame using WRAP_TAB_LAYOUT shows the full content, whereas the height of the one using SCROLL_TAB_LAYOUT is too small and thus does not show the full content.
---------- BEGIN SOURCE ----------
// This is copied from the original issue for convenience
package tabprob;
import java.awt.*;
import javax.swing.*;
public class TabProb extends JFrame {
class FixLayout implements LayoutManager {
@Override
public void layoutContainer(Container C) {
Insets in = C.getInsets();
int w = 200 - in.left - in.right;
int h = 100 - in.top - in.bottom;
C.getComponents()[0].setBounds(in.top, in.left, w, h);
}
@Override
public Dimension minimumLayoutSize(Container C) {
return new Dimension(200, 100);
}
@Override
public Dimension preferredLayoutSize(Container C) {
return new Dimension(200, 100);
}
@Override
public void removeLayoutComponent(Component c) {
}
@Override
public void addLayoutComponent(String s, Component c) {
}
}
public TabProb(int layoutPolicy) {
JTabbedPane tabpanel = new JTabbedPane();
tabpanel.setTabPlacement(JTabbedPane.TOP);
tabpanel.setTabLayoutPolicy(layoutPolicy);
JPanel panel = new JPanel(new FixLayout());
JLabel label = new JLabel("TEST");
label.setBorder(BorderFactory.createLineBorder(Color.green, 3));
panel.add(label);
tabpanel.add("TEST", panel);
add(tabpanel, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String[] args) {
try {
//UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch(Exception e) {
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
TabProb tb1 = new TabProb(JTabbedPane.SCROLL_TAB_LAYOUT);
tb1.pack();
tb1.setVisible(true);
TabProb tb2 = new TabProb(JTabbedPane.WRAP_TAB_LAYOUT);
tb2.pack();
tb2.setVisible(true);
}
});
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
From the original report:
1) Set a large enough inset for the contentpanel, or
2) Set TabbedPane.tabAreaInsets to Insets(0,0,0,0)
FREQUENCY : always
- backported by
-
JDK-8235923 JTabbedPane preferred size calculation is wrong for SCROLL_TAB_LAYOUT
- Resolved
-
JDK-8244168 JTabbedPane preferred size calculation is wrong for SCROLL_TAB_LAYOUT
- Resolved
- duplicates
-
JDK-8046209 See JDK-7151452: JTabbedPane -> SCROLL_TAB_LAYOUT -> minimum/preferred size
- Closed
-
JDK-7151452 JTabbedPane preferred size calculation is wrong for SCROLL_TAB_LAYOUT
- Closed
- relates to
-
JDK-8046209 See JDK-7151452: JTabbedPane -> SCROLL_TAB_LAYOUT -> minimum/preferred size
- Closed