问题描述
我有一个使用自定义UI委托绘制的JButton(CustomButtonUI扩展了BasicButtonUI)。 CustomButtonUI的paint()方法绘制带有圆角抗锯齿角的按钮,使外观尽可能平滑。
I've got a JButton which is painted using a custom UI delegate (CustomButtonUI extends BasicButtonUI). The CustomButtonUI's paint() method draws the button with rounded "antialiased" corners, to make the apperance as "smooth" as possible.
不知何故,抗锯齿边缘每次我将鼠标拖到
按钮上时按钮都会消失。这使按钮边缘看起来像素化。但是,一旦我添加了一行代码来重新绘制按钮的父级,即使我将鼠标拖到按钮上,抗锯齿也会启动。
Somehow the "antialiased" edges of the button disappears each time i drag the mouse over thebutton. This makes the button edges look "pixelized". However, once I add a line of code to repaint the parent of the button, the antialiasing kicks in even when i drag the mouse over the button.
现在,我的问题涉及到这是一个好主意?我会从子组件重绘父组件。我想知道这是否会导致重绘的循环?如果父
尝试重新绘制其子项并且子项尝试重新绘制其父项 - 那么我假设我们正在讨论循环。
Now, my question relates to wether this is a good idea? I do after all repaint the parent component from a child component. I wonder if this lead to a loop of repaints? If the parenttries to repaint its children and the children tries to repaint its parent - then i assume we're talking about a loop.
我已经附上我的代码作为参考。非常欢迎任何评论!
I've attached my code as a reference. Any comments are very welcome!
public class JCustomButtonUI extends BasicButtonUI {
@Override
public void installUI(JComponent c) {
super.installUI(c);
AbstractButton b = (AbstractButton) c;
b.setBorderPainted(false);
}
@Override
public void paint(Graphics g, JComponent c) {
//Cast the Graphics instance to a Graphics2D instance.
Graphics2D g2d = (Graphics2D) g;
JButton b = (JButton) c;
//Repaint parent component to make sure that we get "antialiased"
//edges.
b.getParent().repaint();
//Get the component's height and width.
int w = (int) g.getClipBounds().getWidth();
int h = ((int) g.getClipBounds().getHeight());
//Make sure the button is drawn with "antialiased" edges.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.GRAY);
g2d.fillRoundRect(0, 0, w, h, w, h);
}
}
更新1
为了说明别名和抗锯齿边框,请看下面的两张图片。当我(来自ButtonUI的paint()方法)手动调用父JPanel的重绘方法时,所有边框都是完全抗锯齿的。但是,当我不手动调用父JPanel的重绘方法时,一旦我将鼠标悬停在按钮上,边框就不再被抗锯齿了。
Update 1
Just to illustrate the alias and antialiased border, please have a look at the below two pictures. When i (from the ButtonUI's paint() method) manually invoke the parent JPanel's repaint method, all borders are perfectly antialiased all the time. However, when i do not manually invoke the parent JPanel's repaint method, then the borders are no longer antialiased once i hoover the mouse over the button.
我已经分享了整个组件,其中包含一个JPanel,一个JSlider和Snipt上的几个JButton。请从获取。
I have shared the entire "component" which consists of a JPanel, a JSlider and a couple of JButtons on Snipt. Please get it from http://snipt.org/wnllg.
似乎我设法让它运转起来。我没有在paintComponent()方法中绘制JPanel的背景,而是创建了一个安装在JPanel上的JCustomPanelUI。我不认为这是解决方案本身,但我没有使用Graphics实例的宽度和高度,而是尝试使用JPanel本身的widht和height。当我使用Graphics实例的宽度和高度时,我不太确定为什么出了问题。我认为Graphics实例的宽度和高度已经根据JPanel组件的尺寸进行了准备。您可以在此处查看最终组件:,
It seems that i have managed to get it working. Instead of painting the JPanel's background in its paintComponent() method, i created a JCustomPanelUI which i installed on the JPanel. I don't think that was the solution itself, but instead of using width and height from the Graphics instance, I tried using widht and height from the JPanel itself. I'm not quite sure why things go wrong when i use width and height from the Graphics instance. I thought the width and height from the Graphics instance was already "prepared" with regard to dimensions from the JPanel component. You can have a look at the final component here: http://snipt.org/wnlli,
推荐答案
我已将示例简化为抗锯齿,我无法重现该问题。它似乎不依赖于平台。我不确定你为什么使用 getClipBounds()
。
I've reduced the example to just the anti-aliasing, and I am unable to reproduce the problem. It doesn't appear to be platform dependent. I'm not sure why you are using getClipBounds()
.
附录:
我更新了示例,使用透明按钮后面的渐变背景;我并排放置了反锯齿(左)和别名(右)的例子。我没有看到意外的行为。
I've update the example to use a gradient background behind a transparent button; I've put anti-aliased (left) and aliased (right) examples side-by-side. I see no unexpected behavior.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.plaf.basic.BasicButtonUI;
/** @see http://stackoverflow.com/questions/5169647 */
public class ButtonUITest extends JPanel {
public ButtonUITest() {
this.setLayout(new GridLayout(1, 0));
this.setPreferredSize(new Dimension(640, 480));
this.add(new CustomButton(true));
this.add(new CustomButton(false));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int w = this.getWidth();
int h = this.getHeight();
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(new GradientPaint(0, 0, Color.blue, w, h, Color.red));
g2d.fillRect(0, 0, w, h);
}
private void display() {
JFrame f = new JFrame("ButtonUITest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class CustomButton extends JButton {
public CustomButton(boolean antialiased) {
this.setOpaque(false);
this.setUI(new CustomButtonUI(antialiased));
}
}
private static class CustomButtonUI extends BasicButtonUI {
private boolean antialiased;
public CustomButtonUI(boolean antialiased) {
this.antialiased = antialiased;
}
@Override
public void paint(Graphics g, JComponent c) {
int w = c.getWidth();
int h = c.getHeight();
Graphics2D g2d = (Graphics2D) g;
if (antialiased) {
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
g2d.setColor(Color.LIGHT_GRAY);
g2d.fillOval(0, 0, w, 2 * h);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new ButtonUITest().display();
}
});
}
}
这篇关于JPanel什么时候绘制(或重绘)其子组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!