自定义边框外的组件绘制
在此自定义边框类中,我定义了一个 RoundRectangle2D 形状。该对象用于绘制边框。不幸的是,由于 JComponent
的 paint
方法在 paintBorder
之前调用 paintComponent
,因此设置 Graphics 剪辑到
RoundRectangle2D
形状没有效果;即使我发出重绘
。因此,该组件将在其边界之外进行绘制,这是可以理解的,这是不可取的。
所以,我想知道:如何让组件在自定义边框内独占绘制?
我考虑的一种方法是在 paintComponent
方法中获取组件的 Border
对象。然后将此对象转换为适当的类,其中我定义将影响剪辑的参数。但这看起来不像是一个“合理”的设计。
编辑 -
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.border.AbstractBorder;
class JRoundedCornerBorder extends AbstractBorder
{
private static final long serialVersionUID = 7644739936531926341L;
private static final int THICKNESS = 2;
JRoundedCornerBorder()
{
super();
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if(c.hasFocus())
{
g2.setColor(Color.BLUE);
}
else
{
g2.setColor(Color.BLACK);
}
g2.setStroke(new BasicStroke(THICKNESS, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawRoundRect(THICKNESS, THICKNESS, width - THICKNESS - 2, height - THICKNESS - 2, 20, 20);
g2.dispose();
}
@Override
public Insets getBorderInsets(Component c)
{
return new Insets(THICKNESS, THICKNESS, THICKNESS, THICKNESS);
}
@Override
public Insets getBorderInsets(Component c, Insets insets)
{
insets.left = insets.top = insets.right = insets.bottom = THICKNESS;
return insets;
}
public boolean isBorderOpaque() {
return false;
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
// Add button with custom border
final JButton button = new JButton("Hello");
button.setBorder(new JRoundedCornerBorder());
button.setBackground(Color.YELLOW);
button.setPreferredSize(new Dimension(200, 200));
frame.add(button);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
红色圆圈突出显示组件超出其边框的位置。
In this custom border class, I define a RoundRectangle2D
shape. This object is used to paint the border. Unfortunately, since the paint
method of a JComponent
invokes paintComponent
before paintBorder
, setting the Graphics
clip to the RoundRectangle2D
shape has no effect; even if I issue a repaint
. Therefore, the component will paint outside it's border, which is understandably undesirable.
So, I was wondering: how do I get the component to paint exclusively inside a custom border?
One approach I considered was obtaining the component's Border
object in the paintComponent
method. And then casting this object to the appropriate class, wherein I define parameters that will influence the clip. But this didn't seem like a "sound" design.
Edit -
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.border.AbstractBorder;
class JRoundedCornerBorder extends AbstractBorder
{
private static final long serialVersionUID = 7644739936531926341L;
private static final int THICKNESS = 2;
JRoundedCornerBorder()
{
super();
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if(c.hasFocus())
{
g2.setColor(Color.BLUE);
}
else
{
g2.setColor(Color.BLACK);
}
g2.setStroke(new BasicStroke(THICKNESS, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawRoundRect(THICKNESS, THICKNESS, width - THICKNESS - 2, height - THICKNESS - 2, 20, 20);
g2.dispose();
}
@Override
public Insets getBorderInsets(Component c)
{
return new Insets(THICKNESS, THICKNESS, THICKNESS, THICKNESS);
}
@Override
public Insets getBorderInsets(Component c, Insets insets)
{
insets.left = insets.top = insets.right = insets.bottom = THICKNESS;
return insets;
}
public boolean isBorderOpaque() {
return false;
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
// Add button with custom border
final JButton button = new JButton("Hello");
button.setBorder(new JRoundedCornerBorder());
button.setBackground(Color.YELLOW);
button.setPreferredSize(new Dimension(200, 200));
frame.add(button);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
The red circles highlight where the component extends beyond it's border.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
啊...终于我明白了(由于某种原因错过了 roundBorder,我的错:-) 该按钮只是遵守其合同:它声明是不透明的,因此必须填充其整个区域,包括边框的区域。因此,设置一个剪辑(您可以在paintComponent中执行)将违反合同:
丑陋但安全的做法是将自身报告为透明并自己接管背景绘画:
ahh ... at last I got it (missed the roundBorder for some reason, my fault :-) The button is simply complying to its contract: it states being opaque, so must fill its complete area, including that of the border. So setting a clip (which you could do in paintComponent) would make violate the contract:
Ugly but safe would be to report itself as transparent and take over the background painting yourself:
不是您问题的答案,只是如何
执行此操作的另一个想法
从很长的代码中
not an answer to your question, just another idea how to do it
from very long code
边框怎么画?您实现了
Border
接口吗?有 3 种方法可以将所有边界逻辑放置在那里
How do you paint the border? Did you implement
Border
interface?There are 3 methods to place all your border logic there