Java 选项卡在自定义JTabbedPane中的呈现顺序
大家好,我在2017年的第一篇帖子里祝大家新年快乐!:) 问题解释 我目前正在编写一个定制的Java 选项卡在自定义JTabbedPane中的呈现顺序,java,swing,tabs,rendering,jtabbedpane,Java,Swing,Tabs,Rendering,Jtabbedpane,大家好,我在2017年的第一篇帖子里祝大家新年快乐!:) 问题解释 我目前正在编写一个定制的JTabbedPane,一切正常,但在呈现选项卡时,我遇到了一个意想不到的(对我来说)设计问题 问题是,所有未选择的选项卡都从左到右渲染,并且由于我使用GeneralPath类自定义的形状超出了默认选项卡边界,因此渲染的每个选项卡都与左侧选项卡的一部分重叠。您可以在下图中进行检查: 如您所见,选定的选项卡与右侧的任何选项卡重叠,但未选定的选项卡重叠,如命名的“CustomPanel2”在下一个选项卡之前
JTabbedPane
,一切正常,但在呈现选项卡时,我遇到了一个意想不到的(对我来说)设计问题
问题是,所有未选择的选项卡都从左到右渲染,并且由于我使用GeneralPath
类自定义的形状超出了默认选项卡边界,因此渲染的每个选项卡都与左侧选项卡的一部分重叠。您可以在下图中进行检查:
如您所见,选定的选项卡与右侧的任何选项卡重叠,但未选定的选项卡重叠,如命名的“CustomPanel2”在下一个选项卡之前呈现,依此类推
问题:
我在一篇帖子中看到,我正在使用BasicTabbedPaneUI
类中的paintTab
方法,但我不知道如何实现这一点,因此我希望您向我展示渲染选项卡的正确方法,以便在Google Chrome中获得类似选项卡的内容,如下所示:
提前谢谢你,祝你度过愉快的一天!;)
PD:我认为没有相关的代码可以添加。如果您需要它,请向我索要。如何尝试将未选中的选项卡形状设置为五角大楼 注意:当设置了
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);
});
}
}
如果尝试将未选中的选项卡形状设置为五边形,会怎么样 注意:当设置了
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);
});
}
}
好的,我最终通过重写
basictabedpaneui
类中的paintTabArea
方法找到了解决方案
默认代码为:
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);
}
}
protectedvoid paintTabArea(图形g、int-tabplace、int-selectedIndex){
int tabCount=tabPane.getTabCount();
矩形iconRect=新矩形(),
textRect=新矩形();
矩形clipRect=g.getClipBounds();
对于(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);
对于(int j=start;j=0&&rects[selectedIndex]。相交(clipRect)){
paintTab(g、tabPlacement、rects、selectedIndex、iconRect、textRect);
}
}
在第二个for
语句中,您可以看到条件:(int j=start;j=start;j--)
好吧,我最终通过重写basictabedpaneui
类中的paintTabArea
方法找到了解决方案
默认代码为:
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);
}
}
protectedvoid paintTabArea(图形g、int-tabplace、int-selectedIndex){
int tabCount=tabPane.getTabCount();
矩形iconRect=新矩形(),
textRect=新矩形();
矩形clipRect=g.getClipBounds();
对于(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);
对于(int j=start;j=0&&rects[selectedIndex]。相交(clipRect)){
paintTab(g、tabPlacement、rects、selectedIndex、iconRect、textRect);
}
}
在第二个for
语句中,您可以看到条件:(int j=start;j=start;j--)
也许你应该看看basictabedpaneui
中paintTabArea
和paintTab
方法的源代码。谢谢@explv。我一直在努力学习这个类,也许我被卡住了,但我不明白它到底是如何工作的。为了把事情做好,我只是在寻找合适的步骤也许你应该看看basictabedpaneui
Thank you@explv中paintTabArea
和paintTab
方法的源代码。我一直在努力学习这个类,也许我被卡住了,但我不明白它到底是如何工作的。为了把事情做好,我只是在寻找suita这可能是一个很好的解决方案,但我的老板让我做那个具体的形状(如问题的第一张图片所示),因此,尝试表示这样的形状可能更难,效率也不高,我想是的。我想找到一种方法来编辑渲染顺序或类似的东西会很好。嗨!谢谢@aterai。这可能是一个很好的解决方案,但我的老板让我做那个具体的形状(如问题的第一张图片所示),因此,尝试表示这样的形状可能更难,效率也不高,我想是的。我想找到一种方法来编辑渲染顺序或类似的东西会很好。