AbstractBorder 在 JTabbedPane 上绘制
AbstractBorder paints over JTabbedPane
所以我正在使用 Swing 并尝试使用 JTabbedPane 来包含多个 JPanel 和 JScrollPanes 以滚动浏览 JPanel 列表。出现的问题是每当我更改选项卡时,除其他外,我在滚动窗格内的 JPanels 中拥有的自定义边框功能导致组件在 JTabbedPane header 顶部绘制,我不知道如何要解决此问题: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, 0, 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,0,width, height);
Area borderRegion = new Area(rect);
borderRegion.subtract(area);
g2.setClip(borderRegion);
g2.setColor(background);
g2.fillRect(0, 0, width, 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, 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, 0, width, height);
g2d.dispose();
}
所以我正在使用 Swing 并尝试使用 JTabbedPane 来包含多个 JPanel 和 JScrollPanes 以滚动浏览 JPanel 列表。出现的问题是每当我更改选项卡时,除其他外,我在滚动窗格内的 JPanels 中拥有的自定义边框功能导致组件在 JTabbedPane header 顶部绘制,我不知道如何要解决此问题: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, 0, 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,0,width, height);
Area borderRegion = new Area(rect);
borderRegion.subtract(area);
g2.setClip(borderRegion);
g2.setColor(background);
g2.fillRect(0, 0, width, 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, 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, 0, width, height);
g2d.dispose();
}