这是我想要做的。我已经扩展了JButton并覆盖了paintComponent方法,创建了我想要的圆形边缘按钮效果,以及当按钮被鼠标滚动时的颜色褪色效果。一切都很好。我的问题是,当图像显示时,JButton仍在绘制一个白色矩形区域。
我想1)白色的角落消失,2)按钮的cetner显示它背后的面板。这是我尝试过的:
1-绘制按钮时使用getParent()。getBackground()并首先绘制按钮。这适用于不透明面板。不过我希望这个按钮可以在部分或完全透明的面板上工作。使用透明面板绘制颜色,但在白色背景上隐藏面板后面的任何内容(如图像)。
2-我尝试了很多setOpaque(false)或setContentAreaFilled(false)的组合。我在调用super.paintComponent(g)时没有调用它。这些似乎都不起作用。
3-当我不使用方法g2.clearRect(0,0,宽度,高度)(在绘画前清除图形区域)时按钮看起来正确,但由于图形对象永远不会被覆盖淡入淡出效果按钮翻转后停止工作。
4-我使用JLabel作为文本,并尝试将其设置为不透明或仅使用它,问题仍然存在。所以我认为这不是问题所在。
由于我只想要对JButton产生影响,而不是其他摆动组件,我真的希望避免制作我自己的ButtonUI。
谢谢,我希望这是有道理的。下面是我按钮的代码。
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
/**
* WButton.java
*
* An extension of JButton but with custom graphics
*
*/
public class WButton extends JButton{
private Timer timer;
private float[] background = {.3f,.6f,.8f,0f};
private boolean fadeUp = true;
private boolean fadeDown = false;
private JLabel label;
/**
* Default Constructor
*/
public WButton(){
super();
label = new JLabel();
setupButton();
}
/**
* Text constructor
*/
public WButton(String text){
super(text);
label = new JLabel(text);
setupButton();
}
/**
* common setup functions
*/
private void setupButton(){
timer = new Timer(24,new TimerAction(this));
label.setLabelFor(this);
add(label);
}
/**
* Set the background color
*/
@Override
public void setBackground(Color bg){
background = bg.getRGBComponents(background);
background[3] = 0f;
super.setBackground(new Color(background[0],background[1],
background[2],background[3]));
repaint();
}
/**
* get background
*/
@Override
public Color getBackground(){
if(background!=null)
return new Color(background[0],background[1],background[2],background[3]);
return new Color(.5f,.5f,.5f);
}
/**
* Set the font of the button
*/
@Override
public void setFont(Font font){
super.setFont(font);
if(label!=null)
label.setFont(font);
}
/**
* Override the set text method
*/
@Override
public void setText(String t){
super.setText(t);
if(label!=null)
label.setText(t);
}
/**
* Paint the button
*/
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
Graphics2D g2 = (Graphics2D)g;
g2.clearRect(0,0,width,height);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//Check Button Model state
if(model.isPressed())
paintPressedButton(g2,width,height);
else{
if(model.isRollover()){
if(fadeUp){
fadeUp = false;
timer.start();
}
}
else{
if(fadeDown){
fadeDown = false;
timer.start();
}
}
g2.setPaint(new Color(background[0],background[1],background[2],background[3]));
g2.fillRoundRect(0,0,width-1,height-1,height,height);
}
}
/**
* Draw a pressed button
*/
private void paintPressedButton(Graphics2D g2,int width,int height){
float[] temp = new float[4];
for(int i=0;i<background.length;i++)
temp[i] = background[i]-.4f < 0f ? 0f : background[i]-.4f;
g2.setPaint(new Color(temp[0],temp[1],temp[2],temp[3]));
g2.fillRoundRect(0,0,width-1,height-1,height,height);
}
/**
* paint the border
*/
public void paintBorder(Graphics g){
int width = getWidth();
int height = getHeight();
g.setColor(Color.BLACK);
g.drawRoundRect(0,0,width-1,height-1,height,height);
}
/**
* Inner action listener class
*/
private class TimerAction implements ActionListener{
private float alphaInc = .2f;
WButton button;
public TimerAction(WButton b){
button = b;
}
public void actionPerformed(ActionEvent e){
if(model.isRollover()){
background[3] += alphaInc;
if(background[3] > 1.0f){
timer.stop();
background[3] = 1.0f;
fadeDown = true;
}
}
else{
background[3] -= alphaInc;
if(background[3] < 0f){
timer.stop();
background[3] = 0f;
fadeUp = true;
}
}
button.repaint();
}
}
}
编辑1
有什么建议让我更接近,但不是那里。而不是g2.clearRect()我用建议的透明颜色绘制了对象。白色的盒子不见了,但有不同的颜色。经过调查,是父面板的颜色,但没有透明度。这是一个例子的图片(面板有70%的透明度)。第一张照片是节目开始的时候。第二张图片是在1次鼠标翻转之后。
答案 0 :(得分:7)
您可以做的不是使用clearRect()
,而是使用完全透明的颜色清除背景。
g2.setColor(new Color(0,0,0,0));
g2.drawRect(0,0,width,height);
您仍然需要setOpaque(false)
上的JButton
,以便在将鼠标悬停在其上一次后不会使用蓝色翻转颜色作为背景。
编辑:在看到你刚刚发布的内容后,我认为问题在于主框架没有重新绘制。
尝试:
SwingUtilities.getWindowAncestor(this).repaint();
在paint方法中重新绘制框架,这可能会解决问题。
答案 1 :(得分:0)
这里的问题是,swing在JButton上使用paintImmediately(x, y, width, height)
重新绘制更改后的区域。如果您查看该方法内部,它将遍历父级层次结构(如果父级不透明),直到找到一个不透明的组件。然后调用重绘。您可能会注意到,这种方法没有考虑背景颜色的 alpha分量,因为这些分量是不透明的(isOpaque = true)。
要解决此问题,可以在JButton中重写paintImmediately()
方法,如下所示:
@Override
public void paintImmediately(int x, int y, int w, int h) {
super.paintImmediately(x, y, w, h);
Component component = this;
boolean repaint = false;
while (!component.isOpaque() || (component.getBackground() != null && component.getBackground().getAlpha() < 255)) {
if (component.getBackground() != null && component.getBackground().getAlpha() < 255) {
repaint = true;
}
if (component.getParent() == null) {
break;
}
component = component.getParent();
if (!(component instanceof JComponent)) {
break;
}
}
// There is no need to repaint if no component with an alpha component in
// background is found and no parent component is found (implied by component != this)
// since super.paintImmediately() should have handled the general case.
if (repaint && component != this) {
component.repaint();
}
}
此方法将检查不是透明的或具有透明背景的最顶层组件的父级,然后重新绘制。从性能的角度来看,这比当前接受的答案要好得多(每次悬停/按下按钮时,都会重新绘制整个窗口)。