问题描述
所以我正在使用 Swing 并尝试使用 JTabbedPane 来包含多个 JPanel 和 JScrollPanes 以滚动浏览 JPanel 列表。出现的问题是每当我更改选项卡时,我在滚动窗格内的 JPanels 中的自定义边框功能会导致组件在 JTabbedPane 标题的顶部绘制,我不知道如何解决这个问题:AbstractBorder paints over JTabbedPane header。我提供了模仿我在下面尝试做的事情的代码。要复制该问题,请在一个选项卡上向下滚动一些,直到其中一个勾勒出的面板在顶部一半可见。然后,切换到不同的选项卡,然后返回。然后,再滚动一些,问题就会出现在 JTabbedPane 的顶部
public class Example extends JFrame {
private final JTabbedPane tabbedPane;
public Example() {
setTitle("MIN Example");
setSize(600,700);
setLayout(new BorderLayout());
setLocationRelativeto(null);
setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
setBackground(Color.BLACK);
setExtendedState(JFrame.MAXIMIZED_BOTH);
tabbedPane = new JTabbedPane();
tabbedPane.setBorder(BorderFactory.createEmptyBorder());
tabbedPane.setFocusable(false);
add(tabbedPane,BorderLayout.CENTER);
createTabs();
setVisible(true);
}
private void createTabs() {
// Get the list of guilds
List<String> tabs = new ArrayList<>(Arrays.asList("Tab 1","Tab 2","Tab 3"));
// Iterate through the tabs and create the tab
for (String tab : tabs) {
// Initialize the list JPanel and formatting
JPanel panelList = new JPanel();
panelList.setLayout(new GridBagLayout());
// House the list panel inside a JScrollPane
JScrollPane listScroll = new JScrollPane(panelList);
listScroll.setBorder(BorderFactory.createEmptyBorder());
// Create tab and formatting
tabbedPane.addTab(tab,listScroll);
populateList(panelList);
}
}
private void populateList(JPanel tab) {
// Create GBC for formatting
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.weighty = 1;
// Remove all components from the JPanel
tab.removeAll();
// Add filler JPanel
JPanel filler = new JPanel();
filler.setopaque(false);
tab.add(filler,gbc);
// Update GBC constraints
gbc.insets = new Insets(10,10,10);
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weighty = GridBagConstraints.RELATIVE;
// Go through the tabs and add JPanels
for (int i = 10; i >= 0; i--) {
JPanel tempPanel = new JPanel();
tempPanel.setBorder(new RoundedBorder(Color.BLACK,6,16));
tab.add(tempPanel,gbc,0);
tempPanel.setPreferredSize(new Dimension(0,100));
}
// Refresh the console to display updated lists
validate();
repaint();
}
}
public class RoundedBorder extends AbstractBorder {
private final Color color;
private final int thickness;
private final int radii;
private final Insets insets;
private final Basicstroke stroke;
private final int strokePad;
RenderingHints hints;
/**
* Creates the rounded border
*
* @param color The color of the border outline
* @param thickness The thickness of the border outline
* @param radii The radius of the rounded border
*/
public RoundedBorder(Color color,int thickness,int radii) {
this.thickness = thickness;
this.radii = radii;
this.color = color;
stroke = new Basicstroke(thickness);
strokePad = thickness / 2;
hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int bottomPad = pad + strokePad;
insets = new Insets(pad,pad,bottomPad,pad);
}
@Override
public Insets getBorderInsets(Component c) {
return insets;
}
@Override
public Insets getBorderInsets(Component c,Insets insets) {
return getBorderInsets(c);
}
@Override
public void paintBorder(Component c,Graphics g,int x,int y,int width,int height) {
Graphics2D g2 = (Graphics2D) g;
int bottomLineY = height - thickness;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(strokePad,strokePad,width - thickness,bottomLineY,radii,radii);
Area area = new Area(bubble);
g2.setRenderingHints(hints);
// Paint the background color of the parent
Component parent = c.getParent();
if (parent != null) {
Color background = parent.getBackground();
Rectangle rect = new Rectangle(0,width,height);
Area borderRegion = new Area(rect);
borderRegion.subtract(area);
g2.setClip(borderRegion);
g2.setColor(background);
g2.fillRect(0,height);
g2.setClip(null);
}
g2.setColor(color);
g2.setstroke(stroke);
g2.draw(area);
}
}
我试图解决此问题的唯一方法是更改添加 JTabbedPane(在选项卡填充面板之前添加)的顺序,但无济于事。非常感谢您的帮助,谢谢。
解决方法
将来,MRE 应包括:
- 导入语句
- main() 方法
在原始代码中,Graphics 的“clip”被设置为 null,因此面板的整个 Rectangle 看起来都被绘制了。
我修改了父级的绘制以使用单独的 Graphics 对象,因此原始“剪辑”区域不受影响:
// Paint the background color of the parent
Component parent = c.getParent();
if (parent != null) {
Graphics2D g2d = (Graphics2D)g2.create();
Color background = parent.getBackground();
//Rectangle rect = new Rectangle(0,width,height);
Rectangle rect = g2d.getClip().getBounds();
Area borderRegion = new Area(rect);
borderRegion.subtract(area);
g2d.setClip(borderRegion);
g2d.setColor(background);
g2d.fillRect(0,height);
g2d.dispose();
}