嗨大家好,祝你2017年第一篇文章新年快乐! :)
我目前正在编写自定义JTabbedPane
并且一切正常,但在呈现标签时,我遇到了一个意外(对我来说)设计问题。
问题是所有未选中的选项卡都是从左到右渲染的,因为我使用GeneralPath
类自定义的形状超出了默认的选项卡边界,所以每个选项卡都会重叠其左侧选项卡的一部分。您可以在下图中查看它:
正如您所看到的,选定的选项卡与来自右侧的任何选项卡重叠,但未选中的选项卡,如命名的" CustomPanel2"在下一个标签之前呈现,依此类推。
我看到一篇帖子讨论了来自paintTab
课程的BasicTabbedPaneUI
方法,这是我正在使用的方法,但我无法实现如何做,所以我希望你能展示我是正确的方式来呈现标签,以获得谷歌浏览器中的标签,如下所示:
提前感谢您,祝您有个愉快的一天! ;)
PD:我认为没有相关的代码可以添加。如果您需要,请向我询问。答案 0 :(得分:3)
如何设计未选中五边形的标签?
注意:此示例不会在设置JTabbedPane#setTabLayoutPolicy (JTabbedPane.WRAP_TAB_LAYOUT)
或JTabbedPane#setTabPlacement (JTabbedPane.BOTTOM)
时进行测试:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.plaf.basic.*;
public class TabsOverlapTest {
private JComponent makeUI() {
Color selectedTabColor = UIManager.getColor("TabbedPane.selected");
Color tabBackgroundColor = Color.LIGHT_GRAY;
Color tabBorderColor = Color.GRAY;
UIManager.put("TabbedPane.highlight", tabBorderColor);
JTabbedPane tabs = new JTabbedPane();
tabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
tabs.setUI(new BasicTabbedPaneUI() {
@Override protected void paintTabBorder(
Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected) {
}
@Override protected void paintFocusIndicator(
Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex,
Rectangle iconRect, Rectangle textRect, boolean isSelected) {
}
@Override protected void paintContentBorderTopEdge(
Graphics g, int tabPlacement, int selectedIndex,
int x, int y, int w, int h) {
super.paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
Rectangle selRect = getTabBounds(selectedIndex, calcRect);
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(selectedTabColor);
g2.drawLine(selRect.x - 2, y, selRect.x + selRect.width + 2, y);
g2.dispose();
}
@Override protected void paintTabBackground(
Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h,
boolean isSelected) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int a = isSelected ? 0 : 1;
GeneralPath shape = new GeneralPath();
shape.moveTo(x - 3, y + h);
shape.lineTo(x + 3, y + a);
shape.lineTo(x + w - 3, y + a);
shape.lineTo(x + w + 3, y + h);
shape.closePath();
g2.setColor(isSelected ? selectedTabColor : tabBackgroundColor);
g2.fill(shape);
GeneralPath border = new GeneralPath();
if (isSelected || tabIndex == 0) {
border.moveTo(x - 3, y + h - 1);
} else {
border.moveTo(x + 3, y + h - 1);
border.lineTo(x, (y + h - 1) / 2);
}
border.lineTo(x + 3, y + a);
border.lineTo(x + w - 3, y + a);
border.lineTo(x + w + 3, y + h - 1);
g2.setColor(tabBorderColor);
g2.draw(border);
g2.dispose();
}
});
tabs.addTab("JTextArea", new JScrollPane(new JTextArea()));
tabs.addTab("JTree", new JScrollPane(new JTree()));
tabs.addTab("JButton", new JButton("button"));
tabs.addTab("JSplitPane", new JSplitPane());
return tabs;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TabsOverlapTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
答案 1 :(得分:1)
好吧,我终于通过覆盖paintTabArea
类的BasicTabbedPaneUI
方法找到了解决方案。
默认代码为:
protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex) {
int tabCount = tabPane.getTabCount();
Rectangle iconRect = new Rectangle(),
textRect = new Rectangle();
Rectangle clipRect = g.getClipBounds();
for (int i = runCount - 1; i >= 0; i--) {
int start = tabRuns[i];
int next = tabRuns[(i == runCount - 1)? 0 : i + 1];
int end = (next != 0? next - 1: tabCount - 1);
for (int j = start; j <= end; j++) {
if (j != selectedIndex && rects[j].intersects(clipRect)) {
paintTab(g, tabPlacement, rects, j, iconRect, textRect);
}
}
}
if (selectedIndex >= 0 && rects[selectedIndex].intersects(clipRect)) {
paintTab(g, tabPlacement, rects, selectedIndex, iconRect, textRect);
}
}
在第二个for
声明中,您会看到以下情况:
(int j = start; j <= end; j++)
要切换标签呈现顺序,您只需将该条件更改为:
(int j = end; j >= start; j--)