Java 设置背景图片 的问题

时间:2022-11-17 19:08:22

运行程序后,结果如图: Java 设置背景图片 的问题
但是只有当鼠标移到放置按钮的位置时按钮才出现: Java 设置背景图片 的问题

但是我要的效果就是在按钮窗口添加一个图背景片,所以必须一开始出现所有组件必须都在背景图片之上显现。
求解决办法。

(我已经用JInternalFrame解决了图背景片问题,但那是针对Internal Frame的。   要不直接用JInternalFrame的父类:JLayeredPane,应该也可以达到目的,但是这样一来就显得为了达到目的,代价太大了。个人觉得如果直接Jpanel中paint绘图应该是最简单和最直接的方法)

完整代码如下:

package com.han;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * The result is :
 * <p>
 * If you use pack(), use the setPref() method when you want to resize
 * components; If you do not use the Layout Manager, employ the combined
 * methods: setLayout(null) + Components.setBounds()
 * 
 * @author HAN
 * 
 */
@SuppressWarnings("serial")
public class PanelTest extends JFrame {
static JPanel panel;
static JButton button;

public PanelTest() {
// TODO Auto-generated constructor stub
Container c = getContentPane();
panel = new JPanel() {
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Image img = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/images/Luxun.jpg"));
g2.drawImage(img, 0, 0, this);
}
};
c.add(panel, BorderLayout.CENTER);
//  panel.setPreferredSize(new Dimension(200, 250));
System.out.println(panel.getPreferredSize());
System.out.println(panel.getSize());
button = new JButton("Test");
panel.add(button);

}

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
PanelTest frame = new PanelTest();
 frame.pack();
frame.setSize(new Dimension(500, 500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
System.out.println(panel.getSize());
System.out.println(panel.getPreferredSize());
}

}

30 个解决方案

#1


怎么没人回答啊。。。

我自己附上用LayeredPane的解决办法。
结果如图:
Java 设置背景图片 的问题

package com.han;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

/**
 * The JLayeredPane has no layout manager by default, so you have to use 
 * setBounds() for each component in it. However, you can still assign a layout
 * manager to the layered pane.
 * <p>
 * Many programs use intermediate containers (such as panels) and their layout 
 * managers to lay out components on the same layer, but use absolute 
 * positioning to lay out components on different layers.
 * <p>
 * We can use frame.pack() or frame.setSize() whatever its layout method is 
 * (use a layout manager or not).
 * <p>
 * In fact, if we hesitate to use component.setPreferredSize() or 
 * component.setSize(), we first see the layout method employed to layout this 
 * component. If it has a layout manager, we use component.setPreferredSize(); 
 * else (no layout manager), we use component.setBounds().
 * <p>
 * Concerning the JLayeredPane, the <i>depth</i> is higher, the component is on
 * the top. Within its depth, the position number is 0, top-most; -1, bottom-most;
 * 0, 1, 2, 3, ... from top to bottom.
 * 
 * @author HAN
 *
 */
@SuppressWarnings("serial")
public class JLayeredPane_1 extends JFrame {

public JLayeredPane_1() {
// TODO Auto-generated constructor stub
Container container = getContentPane();

final JLayeredPane layeredPane = new JLayeredPane();
// layeredPane.setBorder(BorderFactory.createTitledBorder(null, 
// "layeredPane", TitledBorder.LEADING, TitledBorder.TOP, 
// new Font(null, Font.BOLD + Font.ITALIC, 14), Color.RED));
layeredPane.setBorder(BorderFactory.createTitledBorder("<html><b><i>" +
"<u><font face='SansSerif' size='5' color='red'>layeredPane" +
"</font></u></i></b></html>"));
Dimension dimension = new Dimension(300, 310);
layeredPane.setPreferredSize(dimension);

final JPanel panelBg = new JPanel();
final Image imageBg = Toolkit.getDefaultToolkit()
.getImage(this.getClass().getResource("/images/Lighthouse.jpg"));
ImageIcon imageIcon = new ImageIcon(imageBg.getScaledInstance
(dimension.width, dimension.height, Image.SCALE_FAST));
final JLabel bg = new JLabel(imageIcon);
final Point origin = new Point(10, 30);
final Rectangle rectangle = new Rectangle(origin, dimension);
panelBg.setBounds(rectangle);
panelBg.add(bg);

final JPanel panelContent = new JPanel();
JButton button = new JButton("button 1");
JButton button2 = new JButton("button 2");
JButton button3 = new JButton("button 3");
panelContent.setBounds(rectangle);
panelContent.setOpaque(false);
panelContent.add(button);
panelContent.add(button2);
panelContent.add(button3);

layeredPane.add(panelBg, new Integer(0));
layeredPane.add(panelContent, new Integer(1));

container.add(layeredPane, BorderLayout.CENTER);

addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// System.out.println(layeredPane.getSize()); //此处必须用getSize()而不是用getPreferredSize()
// System.out.println(layeredPane.getPreferredSize());
Dimension dimensionNew = layeredPane.getSize();
Rectangle rectangleNew = new Rectangle(origin, dimensionNew);
panelBg.setBounds(rectangleNew);
panelContent.setBounds(rectangleNew);
bg.setIcon(new ImageIcon(imageBg.getScaledInstance
(dimensionNew.width, dimensionNew.height, Image.SCALE_FAST)));
}
});
}

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
JLayeredPane_1 frame = new JLayeredPane_1();
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}

}

#2


自己再顶一下。。。。就解释~~~

#3


重写一下 paint方法 先添加背景图片 在调用按钮的repaint方法 试试 
其实能用布局解决最好了。这样的代码不乱

#4


您说的是在哪里调用按钮的repaint方法?我在构造函数的最后添加button.repaint()不行,结果老样子。
不过我是看了L&F包里的properties,button可以有paint, 但是Panel没有。估计也正是因为这个在Panel里paint添加背景图片是行不通的。
引用 3 楼  的回复:
重写一下 paint方法 先添加背景图片 在调用按钮的repaint方法 试试 
其实能用布局解决最好了。这样的代码不乱

#5


你到底想实现什么样的效果,我有点没听明白

#6


呃,又看了你一楼的内容,明白了。


很简单,不要重写 paint(Graphics g) 方法,应该重写 paintComponent(Graphics g) 方法, 问题解决。

#7


问题解决了,现在来说说为什么:


因为 paint() 方法实际做了三件事,

1 调用 paintComponent(),绘制组件
2 绘制组件边框
3 循环调用所有子组件的 paint() 方法,绘制子组件

同时,paint() 方法确保所有的绘制都用了“双缓冲”的技术,提高了在屏幕上显示绘制结果的效率。


你重写 paint() 方法,破坏了双缓冲,阻止了子组件的绘制,阻止了 border 的绘制。

为什么鼠标移上去按钮就出来了?

因为虽然你看不见,但是 JButton 本身是 isVisible() ,并且有大小,有位置,只是你没画而已,它仍然捕捉到鼠标事件,鼠标事件导致按钮高亮,引发重绘(注意是JButton自己的重绘,没有惊动它的父组件JPanel),所以鼠标显示出来了。

#8


你对这个问题研究比较透彻。JPanel的绘制背景图片问题是通过paintComponent()解决了,但是同样用paintComponent()来绘制JButton的背景确出现了问题:
若使用g2.drawImage(img, 0, 0, this.getPreferredSize().width, this.getPreferredSize().height, this);则运行后显示不了图片。
如果用g2.drawImage(img, 0, 0, this.getPreferredSize().width, this.getPreferredSize().height, null);则有时运行后图片能显示,有时运行后则不能显示。我认为还是那个ImageObserver的使用问题,this与null到时有什么区别!

引用 7 楼 raistlic 的回复:
问题解决了,现在来说说为什么:


因为 paint() 方法实际做了三件事,

1 调用 paintComponent(),绘制组件
2 绘制组件边框
3 循环调用所有子组件的 paint() 方法,绘制子组件

同时,paint() 方法确保所有的绘制都用了“双缓冲”的技术,提高了在屏幕上显示绘制结果的效率。


你重写 paint() 方法,……

#9


一般使用SwingX提供的JXPanel的setBackgroundPainter(new ImagePainter(...))

#10



public void paintComponent(Graphics g) {
      super.paintComponent(g);
      setBackground(Color.WHITE);
      if (image != null) {
         int height = image.getHeight(this);
         int width = image.getWidth(this);

         if (height != -1 && height > getHeight())
            height = getHeight();

         if (width != -1 && width > getWidth())
            width = getWidth();

         int x = (int) (((double) (getWidth() - width)) / 2.0);
         int y = (int) (((double) (getHeight() - height)) / 2.0);
        
         g.drawImage(image, x, y-50, width, height, this);
        
      }
   }

用这种方法添加背景都有这种困扰。这种方法我测试过很多次,页面好像一有改变就重新绘图一次添加背景。
所以你的那些按钮被掩盖了。
技术上我是没办法了。以前我也遇到过相同的困扰,不过换了一种逻辑上方式实现了。
那就是单独把被背景放到一个jpanel里面。不需要的时候让这个jpanel不显示

#11


你说的这个也要用到Graphics2D.drawImage(Image img,
                int x,
                int y,
                Color bgcolor,
                ImageObserver observer)
方法吧。。但是ImageObserver 到底是干什么的呢,可以设置为null吗,设置为this与设置为null有什么区别?
引用 9 楼 huntor 的回复:
一般使用SwingX提供的JXPanel的setBackgroundPainter(new ImagePainter(...))

#12


我看ImageOberver主要为异步载入图片服务,对于从硬盘上读图片,this/null没多少区别,基本一步到位。

#13


你那Test想干嘛

#14


给一个我写给你的代码给你借鉴一下咯

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestFrame extends JFrame
{
private Image image = null;
private ImageIcon icon = new ImageIcon("img/2.jpg");

public TestFrame()
{
super("测试窗口");

// 设置标题栏上的图片为image
Image image = new ImageIcon("img/2.jpg").getImage();
this.setIconImage(image);

Toolkit toolkit = this.getToolkit();
Dimension dimension = toolkit.getDefaultToolkit().getScreenSize();

this.setSize(dimension.width, dimension.height);
this.setVisible(true);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}

public static void main(String[] args)
{
new TestFrame();
}

// 绘制背景这个方法jvm会自动调用
public void paint(Graphics g)
{
super.paint(g);
image = icon.getImage();
g.drawImage(image, 0, 0, null);

}

}

#15


引用 11 楼 Gaowen_HAN 的回复:
你说的这个也要用到Graphics2D.drawImage(Image img,
                int x,
                int y,
                Color bgcolor,
                ImageObserver observer)
方法吧。。但是ImageObserver 到底是……


关于 ImageObserver, 我也不太熟悉。

我所知道的跟12楼说的差不多,如果你要画的 Image 对象,可能在 drawImage 这句调用的时候仍然在 loading 的话,ImageObserver这个参数才有意义,如果你是画一个内存中的 BufferedImage 对象的话,这个参数不用传任何东西,用 null 就行了。

#16


我查看了API,上面说其中的ImageObserver是要调用imageUpdate方法的,如果把ImageObserver设置为null,那岂不是要抛出NullPointerException了??
引用 12 楼 huntor 的回复:
我看ImageOberver主要为异步载入图片服务,对于从硬盘上读图片,this/null没多少区别,基本一步到位。

#17


我写的这个基于Nimbus package的Customize组件的一个完整程序:
package com.han;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Toolkit;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JSlider;
import javax.swing.Painter;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;

@SuppressWarnings("serial")
public class JSlider_customized extends JFrame {

public JSlider_customized() {
// TODO Auto-generated constructor stub
for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if (laf.getName().equals("Nimbus")) {
try {
UIManager.setLookAndFeel(laf.getClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

JPanel panel = new JPanel(new GridLayout(0, 1, 20, 20));
JSlider slider = new JSlider(0, 100, 50);
Container c = getContentPane();
c.add(panel, BorderLayout.CENTER);
panel.setBackground(Color.DARK_GRAY);
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
panel.add(slider);
UIDefaults sliderDefaults = new UIDefaults();
sliderDefaults.put("Slider.thumbWidth", 20);
sliderDefaults.put("Slider.thumbHeight", 20);
sliderDefaults.put("Slider:SliderThumb.backgroundPainter",
new Painter<JComponent>() {
public void paint(Graphics2D g, JComponent c, int w, int h) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(2f));

g.setColor(Color.RED);
g.fillOval(1, 1, w - 3, h - 3);
g.setColor(Color.WHITE);
g.drawOval(1, 1, w - 3, h - 3);
 Image img = Toolkit.getDefaultToolkit().getImage(
 JSlider_customized.class
 .getResource("/images/Luxun.jpg"));

 g.drawImage(img, 0, 0, w, h, null);
}
});
sliderDefaults.put("Slider:SliderTrack.backgroundPainter",
new Painter<JComponent>() {
public void paint(Graphics2D g, JComponent c, int w, int h) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(2f));
g.setColor(Color.GRAY);
g.fillRoundRect(0, 6, w - 1, 8, 8, 8);
g.setColor(Color.WHITE);
g.drawRoundRect(0, 6, w - 1, 8, 8, 8);
}
});
slider.putClientProperty("Nimbus.Overrides", sliderDefaults);
slider.putClientProperty("Nimbus.Overrides.InheritDefaults", false);

JSlider slider2 = new JSlider(0, 100, 50);
panel.add(slider2);
}

/**
 * @param args
 */
public static void main(String[] args) {

// JFrame.setDefaultLookAndFeelDecorated(true);
JSlider_customized frame = new JSlider_customized();
// frame.setUndecorated(true);
// frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);

frame.pack();// leaves the frame layout manager in charge of the frame
// size, so that all its contents are at or above their
// preferred sizes
// frame.setLocation(100, 100); // set the frame location
frame.setLocationRelativeTo(null); // centers a frame onscreen
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}

}

运行结果: Java 设置背景图片 的问题
然后用鼠标随便调整下窗口大小,那个设置的图片就出来了: Java 设置背景图片 的问题
其中的关键代码是: Java 设置背景图片 的问题,如果把null改成JComponent c,则会抛出异常 Java 设置背景图片 的问题。所以这还是这个ImageObserver在作怪!而我于是去查new Painter<JComponent>() {
public void paint(Graphics2D g, JComponent c, int w, int h)的API,对于JComponent c里面说到:Generally, to enhance reusability, most standard Painters ignore this parameter. They can thus be reused in any context. The object may be null. Implementations must not throw a NullPointerException if the object parameter is null.也就是说JComponent c可以为null。所以这种情况该如何是好啊,怎么才能正常的显示drawImage画出的图片啊!!!!
引用 16 楼 Gaowen_HAN 的回复:
我查看了API,上面说其中的ImageObserver是要调用imageUpdate方法的,如果把ImageObserver设置为null,那岂不是要抛出NullPointerException了??
引用 12 楼 huntor 的回复:我看ImageOberver主要为异步载入图片服务,对于从硬盘上读图片,this/null没多少区别,基本一步到位。
       ……

#18


Toolkit的getImage的原因。
使用 ImageIO的read方法就正常。

#19


引用 17 楼 Gaowen_HAN 的回复:
我写的这个基于Nimbus package的Customize组件的一个完整程序:
Java code123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172……


<Filthy Rich Clients> 原话 :

Note: For all of the drawImage() methods, you will notice that there is an
ImageObserver argument as the final parameter. This argument is useful for images
that may not be fully loaded yet at the time of the drawImage() call or that are animating,
such as an animated GIF image. But in general, if you are using images that
are already loaded, such as any BufferedImage, this argument is not needed. You
should pass null for the final argument in these cases, as follows:

drawImage(image, x, y, null);


This is what you will see for the drawImage() calls in our demo code, as we generally
use BufferedImage objects.

#20


您还真是一语中的。我之前说的那个 “鼠标随便调整下窗口大小,那个设置的图片就出来了”的问题和“如果把null改成JComponent c,则会抛出异常”的问题一下子都解决了!!
但是能给我讲讲为什么吗?Thanks
引用 18 楼 huntor 的回复:
Toolkit的getImage的原因。
使用 ImageIO的read方法就正常。

#21


哦,谢谢啊 也就是说BufferedImage在drawImage时是全部Loaded的。此时指定ImageObserver以及设置为null是一样的效果。
引用 19 楼 raistlic 的回复:
引用 17 楼 Gaowen_HAN 的回复:我写的这个基于Nimbus package的Customize组件的一个完整程序:
Java code1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606……

#22


Toolkit 的getImage 都要和MediaTracker搭配使用。
后来才想起来。

#23


哦, 好的谢谢,虽然没有说明为什么会和ImageIO.read()有这样的效果差别。。
引用 22 楼 huntor 的回复:
Toolkit 的getImage 都要和MediaTracker搭配使用。
后来才想起来。

#24


解决了诸多问题,我发上自己使用paintComponent()方法绘制的各种Button:
正常状态:
Java 设置背景图片 的问题
获得焦点状态:
Java 设置背景图片 的问题
被按下状态:
Java 设置背景图片 的问题
被释放状态:
Java 设置背景图片 的问题
实现代码:
package com.han;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.LineMetrics;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;

@SuppressWarnings("serial")
public class JButton_Bg extends JFrame {

public JButton_Bg() {
for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if (laf.getName().equals("Nimbus")) {
try {
UIManager.setLookAndFeel(laf.getClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// TODO Auto-generated constructor stub
Container c = getContentPane();
c.setLayout(new FlowLayout());

final JButton button = new MyButton("button 2");

c.add(button);
JButton button2 = new JButton("button 2");
c.add(button2);
button2.setBackground(Color.blue);

JButton button3 = new MyButton2("Cancel");
c.add(button3);

// 完全重绘的Button,其Text的HTML设置特性消失
// JButton button4 = new
// MyButton3("<html><font size=12>Sub</font></html>");
JButton button4 = new MyButton3("Sub");
// button4.setFont(new Font("Serif", Font.PLAIN, 14));
c.add(button4);
}
(由于没贴的字数限制,接下来帖子的代码接着)
引用 21 楼 Gaowen_HAN 的回复:
哦,谢谢啊 也就是说BufferedImage在drawImage时是全部Loaded的。此时指定ImageObserver以及设置为null是一样的效果。
引用 19 楼 raistlic 的回复:引用 17 楼 Gaowen_HAN 的回复:我写的这个基于Nimbus package的Customize组件的一个完整程序:
Java code12345678910……

#25


private class MyButton extends JButton {
private String text;
private String state = "normal";
// private String state = "focused";
// private String state = "pressed";
// private String state = "released";

// 无参构造继承时自动调用,而有参构造继承时则需手动重写
MyButton(String text) {
// super("<html><font size=5>" + text + "</font></html>");
super(text);
this.text = text;

// 下 面的代码块若是放到下面的paintComponent()方法里则Swing界面初始化时,
// 布局管理器还是采用的是系统默认的PreferredSize。因为构造函数要优先于
// paintComponent()方法执行。
Dimension preferredSize = getPreferredSize();
Dimension preferredSizeNew = new Dimension(preferredSize.width,
preferredSize.width);
setPreferredSize(preferredSizeNew);
}

@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

int width = this.getPreferredSize().width;
int height = this.getPreferredSize().height;

// BufferedImage img;
// try {
// img = ImageIO.read(this.getClass().getResource(
// "/images/icon.jpg"));
// g2.drawImage(img, 0, 0, width, height, this);
// } catch (IOException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }

if (state.equals("normal")) {
// draw background pattern
Point2D center = new Point2D.Float(width / 2, height / 2);
float radius = height / 2;
float[] dist = { 0.0f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2, 0, height,
height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2),
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent())));

} else if (state.equals("focused")) {
// draw background pattern
Point2D center = new Point2D.Float(width / 2, height / 2);
float radius = height / 2;
float[] dist = { 0.2f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2, 0, height,
height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2),
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent())));
} else if (state.equals("pressed")) {
// draw background pattern
int offsetCenter = 1;
Point2D center = new Point2D.Float(width / 2 + offsetCenter,
height / 2 + offsetCenter);
float radius = height / 2;
float[] dist = { 0.2f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2
+ offsetCenter, offsetCenter, height, height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2)
+ offsetCenter,
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent()))
+ offsetCenter);
} else if (state.equals("released")) {
// draw background pattern
Point2D center = new Point2D.Float(width / 2, height / 2);
float radius = height / 2;
float[] dist = { 0.2f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2, 0, height,
height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2),
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent())));
}

addMouseListener(new MouseAdapter() {

@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("光标移入组件");
state = "focused";
repaint();
}

@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("光标移出组件");
state = "normal";
repaint();
}

@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
System.out.print("鼠标按键被按下,");
state = "pressed";
repaint();
}

@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
System.out.print("鼠标按键被释放,");
state = "released";
repaint();
}

});

}
}

#26


要实现一个异形的JButton,还要重写这个方法:
public boolean contains(int x, int y)

引用
Gives the UI delegate an opportunity to define the precise shape of this component for the sake of mouse processing.

#27


谢谢,已修改。这个确实给非矩形按钮的鼠标事件提供了更为精确的热点区控制。
由于每帖的字数限制,代码发到了 CSDN博客上。大家有兴趣可以去看看,如果能发表下修改意见那将非常高兴。
引用 26 楼 huntor 的回复:
要实现一个异形的JButton,还要重写这个方法:
Java code1public boolean contains(int x, int y)
引用Gives the UI delegate an opportunity to define the precise shape of this component for the sake of mouse proc……

#28


。。。。没看懂额

#29


。。。哪里没看懂,可以提出来
引用 28 楼 chenzhengfei2010 的回复:
。。。。没看懂额

#30


Java 设置背景图片 的问题
Java 设置背景图片 的问题
Java 设置背景图片 的问题
一个Java编写的MP3 Player :
Java 设置背景图片 的问题
运行环境:JRE 7 或者以上
自行体验吧~~
下载链接

#1


怎么没人回答啊。。。

我自己附上用LayeredPane的解决办法。
结果如图:
Java 设置背景图片 的问题

package com.han;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

/**
 * The JLayeredPane has no layout manager by default, so you have to use 
 * setBounds() for each component in it. However, you can still assign a layout
 * manager to the layered pane.
 * <p>
 * Many programs use intermediate containers (such as panels) and their layout 
 * managers to lay out components on the same layer, but use absolute 
 * positioning to lay out components on different layers.
 * <p>
 * We can use frame.pack() or frame.setSize() whatever its layout method is 
 * (use a layout manager or not).
 * <p>
 * In fact, if we hesitate to use component.setPreferredSize() or 
 * component.setSize(), we first see the layout method employed to layout this 
 * component. If it has a layout manager, we use component.setPreferredSize(); 
 * else (no layout manager), we use component.setBounds().
 * <p>
 * Concerning the JLayeredPane, the <i>depth</i> is higher, the component is on
 * the top. Within its depth, the position number is 0, top-most; -1, bottom-most;
 * 0, 1, 2, 3, ... from top to bottom.
 * 
 * @author HAN
 *
 */
@SuppressWarnings("serial")
public class JLayeredPane_1 extends JFrame {

public JLayeredPane_1() {
// TODO Auto-generated constructor stub
Container container = getContentPane();

final JLayeredPane layeredPane = new JLayeredPane();
// layeredPane.setBorder(BorderFactory.createTitledBorder(null, 
// "layeredPane", TitledBorder.LEADING, TitledBorder.TOP, 
// new Font(null, Font.BOLD + Font.ITALIC, 14), Color.RED));
layeredPane.setBorder(BorderFactory.createTitledBorder("<html><b><i>" +
"<u><font face='SansSerif' size='5' color='red'>layeredPane" +
"</font></u></i></b></html>"));
Dimension dimension = new Dimension(300, 310);
layeredPane.setPreferredSize(dimension);

final JPanel panelBg = new JPanel();
final Image imageBg = Toolkit.getDefaultToolkit()
.getImage(this.getClass().getResource("/images/Lighthouse.jpg"));
ImageIcon imageIcon = new ImageIcon(imageBg.getScaledInstance
(dimension.width, dimension.height, Image.SCALE_FAST));
final JLabel bg = new JLabel(imageIcon);
final Point origin = new Point(10, 30);
final Rectangle rectangle = new Rectangle(origin, dimension);
panelBg.setBounds(rectangle);
panelBg.add(bg);

final JPanel panelContent = new JPanel();
JButton button = new JButton("button 1");
JButton button2 = new JButton("button 2");
JButton button3 = new JButton("button 3");
panelContent.setBounds(rectangle);
panelContent.setOpaque(false);
panelContent.add(button);
panelContent.add(button2);
panelContent.add(button3);

layeredPane.add(panelBg, new Integer(0));
layeredPane.add(panelContent, new Integer(1));

container.add(layeredPane, BorderLayout.CENTER);

addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// System.out.println(layeredPane.getSize()); //此处必须用getSize()而不是用getPreferredSize()
// System.out.println(layeredPane.getPreferredSize());
Dimension dimensionNew = layeredPane.getSize();
Rectangle rectangleNew = new Rectangle(origin, dimensionNew);
panelBg.setBounds(rectangleNew);
panelContent.setBounds(rectangleNew);
bg.setIcon(new ImageIcon(imageBg.getScaledInstance
(dimensionNew.width, dimensionNew.height, Image.SCALE_FAST)));
}
});
}

/**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
JLayeredPane_1 frame = new JLayeredPane_1();
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}

}

#2


自己再顶一下。。。。就解释~~~

#3


重写一下 paint方法 先添加背景图片 在调用按钮的repaint方法 试试 
其实能用布局解决最好了。这样的代码不乱

#4


您说的是在哪里调用按钮的repaint方法?我在构造函数的最后添加button.repaint()不行,结果老样子。
不过我是看了L&F包里的properties,button可以有paint, 但是Panel没有。估计也正是因为这个在Panel里paint添加背景图片是行不通的。
引用 3 楼  的回复:
重写一下 paint方法 先添加背景图片 在调用按钮的repaint方法 试试 
其实能用布局解决最好了。这样的代码不乱

#5


你到底想实现什么样的效果,我有点没听明白

#6


呃,又看了你一楼的内容,明白了。


很简单,不要重写 paint(Graphics g) 方法,应该重写 paintComponent(Graphics g) 方法, 问题解决。

#7


问题解决了,现在来说说为什么:


因为 paint() 方法实际做了三件事,

1 调用 paintComponent(),绘制组件
2 绘制组件边框
3 循环调用所有子组件的 paint() 方法,绘制子组件

同时,paint() 方法确保所有的绘制都用了“双缓冲”的技术,提高了在屏幕上显示绘制结果的效率。


你重写 paint() 方法,破坏了双缓冲,阻止了子组件的绘制,阻止了 border 的绘制。

为什么鼠标移上去按钮就出来了?

因为虽然你看不见,但是 JButton 本身是 isVisible() ,并且有大小,有位置,只是你没画而已,它仍然捕捉到鼠标事件,鼠标事件导致按钮高亮,引发重绘(注意是JButton自己的重绘,没有惊动它的父组件JPanel),所以鼠标显示出来了。

#8


你对这个问题研究比较透彻。JPanel的绘制背景图片问题是通过paintComponent()解决了,但是同样用paintComponent()来绘制JButton的背景确出现了问题:
若使用g2.drawImage(img, 0, 0, this.getPreferredSize().width, this.getPreferredSize().height, this);则运行后显示不了图片。
如果用g2.drawImage(img, 0, 0, this.getPreferredSize().width, this.getPreferredSize().height, null);则有时运行后图片能显示,有时运行后则不能显示。我认为还是那个ImageObserver的使用问题,this与null到时有什么区别!

引用 7 楼 raistlic 的回复:
问题解决了,现在来说说为什么:


因为 paint() 方法实际做了三件事,

1 调用 paintComponent(),绘制组件
2 绘制组件边框
3 循环调用所有子组件的 paint() 方法,绘制子组件

同时,paint() 方法确保所有的绘制都用了“双缓冲”的技术,提高了在屏幕上显示绘制结果的效率。


你重写 paint() 方法,……

#9


一般使用SwingX提供的JXPanel的setBackgroundPainter(new ImagePainter(...))

#10



public void paintComponent(Graphics g) {
      super.paintComponent(g);
      setBackground(Color.WHITE);
      if (image != null) {
         int height = image.getHeight(this);
         int width = image.getWidth(this);

         if (height != -1 && height > getHeight())
            height = getHeight();

         if (width != -1 && width > getWidth())
            width = getWidth();

         int x = (int) (((double) (getWidth() - width)) / 2.0);
         int y = (int) (((double) (getHeight() - height)) / 2.0);
        
         g.drawImage(image, x, y-50, width, height, this);
        
      }
   }

用这种方法添加背景都有这种困扰。这种方法我测试过很多次,页面好像一有改变就重新绘图一次添加背景。
所以你的那些按钮被掩盖了。
技术上我是没办法了。以前我也遇到过相同的困扰,不过换了一种逻辑上方式实现了。
那就是单独把被背景放到一个jpanel里面。不需要的时候让这个jpanel不显示

#11


你说的这个也要用到Graphics2D.drawImage(Image img,
                int x,
                int y,
                Color bgcolor,
                ImageObserver observer)
方法吧。。但是ImageObserver 到底是干什么的呢,可以设置为null吗,设置为this与设置为null有什么区别?
引用 9 楼 huntor 的回复:
一般使用SwingX提供的JXPanel的setBackgroundPainter(new ImagePainter(...))

#12


我看ImageOberver主要为异步载入图片服务,对于从硬盘上读图片,this/null没多少区别,基本一步到位。

#13


你那Test想干嘛

#14


给一个我写给你的代码给你借鉴一下咯

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestFrame extends JFrame
{
private Image image = null;
private ImageIcon icon = new ImageIcon("img/2.jpg");

public TestFrame()
{
super("测试窗口");

// 设置标题栏上的图片为image
Image image = new ImageIcon("img/2.jpg").getImage();
this.setIconImage(image);

Toolkit toolkit = this.getToolkit();
Dimension dimension = toolkit.getDefaultToolkit().getScreenSize();

this.setSize(dimension.width, dimension.height);
this.setVisible(true);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}

public static void main(String[] args)
{
new TestFrame();
}

// 绘制背景这个方法jvm会自动调用
public void paint(Graphics g)
{
super.paint(g);
image = icon.getImage();
g.drawImage(image, 0, 0, null);

}

}

#15


引用 11 楼 Gaowen_HAN 的回复:
你说的这个也要用到Graphics2D.drawImage(Image img,
                int x,
                int y,
                Color bgcolor,
                ImageObserver observer)
方法吧。。但是ImageObserver 到底是……


关于 ImageObserver, 我也不太熟悉。

我所知道的跟12楼说的差不多,如果你要画的 Image 对象,可能在 drawImage 这句调用的时候仍然在 loading 的话,ImageObserver这个参数才有意义,如果你是画一个内存中的 BufferedImage 对象的话,这个参数不用传任何东西,用 null 就行了。

#16


我查看了API,上面说其中的ImageObserver是要调用imageUpdate方法的,如果把ImageObserver设置为null,那岂不是要抛出NullPointerException了??
引用 12 楼 huntor 的回复:
我看ImageOberver主要为异步载入图片服务,对于从硬盘上读图片,this/null没多少区别,基本一步到位。

#17


我写的这个基于Nimbus package的Customize组件的一个完整程序:
package com.han;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Toolkit;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JSlider;
import javax.swing.Painter;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;

@SuppressWarnings("serial")
public class JSlider_customized extends JFrame {

public JSlider_customized() {
// TODO Auto-generated constructor stub
for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if (laf.getName().equals("Nimbus")) {
try {
UIManager.setLookAndFeel(laf.getClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

JPanel panel = new JPanel(new GridLayout(0, 1, 20, 20));
JSlider slider = new JSlider(0, 100, 50);
Container c = getContentPane();
c.add(panel, BorderLayout.CENTER);
panel.setBackground(Color.DARK_GRAY);
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
panel.add(slider);
UIDefaults sliderDefaults = new UIDefaults();
sliderDefaults.put("Slider.thumbWidth", 20);
sliderDefaults.put("Slider.thumbHeight", 20);
sliderDefaults.put("Slider:SliderThumb.backgroundPainter",
new Painter<JComponent>() {
public void paint(Graphics2D g, JComponent c, int w, int h) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(2f));

g.setColor(Color.RED);
g.fillOval(1, 1, w - 3, h - 3);
g.setColor(Color.WHITE);
g.drawOval(1, 1, w - 3, h - 3);
 Image img = Toolkit.getDefaultToolkit().getImage(
 JSlider_customized.class
 .getResource("/images/Luxun.jpg"));

 g.drawImage(img, 0, 0, w, h, null);
}
});
sliderDefaults.put("Slider:SliderTrack.backgroundPainter",
new Painter<JComponent>() {
public void paint(Graphics2D g, JComponent c, int w, int h) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(2f));
g.setColor(Color.GRAY);
g.fillRoundRect(0, 6, w - 1, 8, 8, 8);
g.setColor(Color.WHITE);
g.drawRoundRect(0, 6, w - 1, 8, 8, 8);
}
});
slider.putClientProperty("Nimbus.Overrides", sliderDefaults);
slider.putClientProperty("Nimbus.Overrides.InheritDefaults", false);

JSlider slider2 = new JSlider(0, 100, 50);
panel.add(slider2);
}

/**
 * @param args
 */
public static void main(String[] args) {

// JFrame.setDefaultLookAndFeelDecorated(true);
JSlider_customized frame = new JSlider_customized();
// frame.setUndecorated(true);
// frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);

frame.pack();// leaves the frame layout manager in charge of the frame
// size, so that all its contents are at or above their
// preferred sizes
// frame.setLocation(100, 100); // set the frame location
frame.setLocationRelativeTo(null); // centers a frame onscreen
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}

}

运行结果: Java 设置背景图片 的问题
然后用鼠标随便调整下窗口大小,那个设置的图片就出来了: Java 设置背景图片 的问题
其中的关键代码是: Java 设置背景图片 的问题,如果把null改成JComponent c,则会抛出异常 Java 设置背景图片 的问题。所以这还是这个ImageObserver在作怪!而我于是去查new Painter<JComponent>() {
public void paint(Graphics2D g, JComponent c, int w, int h)的API,对于JComponent c里面说到:Generally, to enhance reusability, most standard Painters ignore this parameter. They can thus be reused in any context. The object may be null. Implementations must not throw a NullPointerException if the object parameter is null.也就是说JComponent c可以为null。所以这种情况该如何是好啊,怎么才能正常的显示drawImage画出的图片啊!!!!
引用 16 楼 Gaowen_HAN 的回复:
我查看了API,上面说其中的ImageObserver是要调用imageUpdate方法的,如果把ImageObserver设置为null,那岂不是要抛出NullPointerException了??
引用 12 楼 huntor 的回复:我看ImageOberver主要为异步载入图片服务,对于从硬盘上读图片,this/null没多少区别,基本一步到位。
       ……

#18


Toolkit的getImage的原因。
使用 ImageIO的read方法就正常。

#19


引用 17 楼 Gaowen_HAN 的回复:
我写的这个基于Nimbus package的Customize组件的一个完整程序:
Java code123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172……


<Filthy Rich Clients> 原话 :

Note: For all of the drawImage() methods, you will notice that there is an
ImageObserver argument as the final parameter. This argument is useful for images
that may not be fully loaded yet at the time of the drawImage() call or that are animating,
such as an animated GIF image. But in general, if you are using images that
are already loaded, such as any BufferedImage, this argument is not needed. You
should pass null for the final argument in these cases, as follows:

drawImage(image, x, y, null);


This is what you will see for the drawImage() calls in our demo code, as we generally
use BufferedImage objects.

#20


您还真是一语中的。我之前说的那个 “鼠标随便调整下窗口大小,那个设置的图片就出来了”的问题和“如果把null改成JComponent c,则会抛出异常”的问题一下子都解决了!!
但是能给我讲讲为什么吗?Thanks
引用 18 楼 huntor 的回复:
Toolkit的getImage的原因。
使用 ImageIO的read方法就正常。

#21


哦,谢谢啊 也就是说BufferedImage在drawImage时是全部Loaded的。此时指定ImageObserver以及设置为null是一样的效果。
引用 19 楼 raistlic 的回复:
引用 17 楼 Gaowen_HAN 的回复:我写的这个基于Nimbus package的Customize组件的一个完整程序:
Java code1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606……

#22


Toolkit 的getImage 都要和MediaTracker搭配使用。
后来才想起来。

#23


哦, 好的谢谢,虽然没有说明为什么会和ImageIO.read()有这样的效果差别。。
引用 22 楼 huntor 的回复:
Toolkit 的getImage 都要和MediaTracker搭配使用。
后来才想起来。

#24


解决了诸多问题,我发上自己使用paintComponent()方法绘制的各种Button:
正常状态:
Java 设置背景图片 的问题
获得焦点状态:
Java 设置背景图片 的问题
被按下状态:
Java 设置背景图片 的问题
被释放状态:
Java 设置背景图片 的问题
实现代码:
package com.han;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.LineMetrics;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;

@SuppressWarnings("serial")
public class JButton_Bg extends JFrame {

public JButton_Bg() {
for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if (laf.getName().equals("Nimbus")) {
try {
UIManager.setLookAndFeel(laf.getClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// TODO Auto-generated constructor stub
Container c = getContentPane();
c.setLayout(new FlowLayout());

final JButton button = new MyButton("button 2");

c.add(button);
JButton button2 = new JButton("button 2");
c.add(button2);
button2.setBackground(Color.blue);

JButton button3 = new MyButton2("Cancel");
c.add(button3);

// 完全重绘的Button,其Text的HTML设置特性消失
// JButton button4 = new
// MyButton3("<html><font size=12>Sub</font></html>");
JButton button4 = new MyButton3("Sub");
// button4.setFont(new Font("Serif", Font.PLAIN, 14));
c.add(button4);
}
(由于没贴的字数限制,接下来帖子的代码接着)
引用 21 楼 Gaowen_HAN 的回复:
哦,谢谢啊 也就是说BufferedImage在drawImage时是全部Loaded的。此时指定ImageObserver以及设置为null是一样的效果。
引用 19 楼 raistlic 的回复:引用 17 楼 Gaowen_HAN 的回复:我写的这个基于Nimbus package的Customize组件的一个完整程序:
Java code12345678910……

#25


private class MyButton extends JButton {
private String text;
private String state = "normal";
// private String state = "focused";
// private String state = "pressed";
// private String state = "released";

// 无参构造继承时自动调用,而有参构造继承时则需手动重写
MyButton(String text) {
// super("<html><font size=5>" + text + "</font></html>");
super(text);
this.text = text;

// 下 面的代码块若是放到下面的paintComponent()方法里则Swing界面初始化时,
// 布局管理器还是采用的是系统默认的PreferredSize。因为构造函数要优先于
// paintComponent()方法执行。
Dimension preferredSize = getPreferredSize();
Dimension preferredSizeNew = new Dimension(preferredSize.width,
preferredSize.width);
setPreferredSize(preferredSizeNew);
}

@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

int width = this.getPreferredSize().width;
int height = this.getPreferredSize().height;

// BufferedImage img;
// try {
// img = ImageIO.read(this.getClass().getResource(
// "/images/icon.jpg"));
// g2.drawImage(img, 0, 0, width, height, this);
// } catch (IOException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }

if (state.equals("normal")) {
// draw background pattern
Point2D center = new Point2D.Float(width / 2, height / 2);
float radius = height / 2;
float[] dist = { 0.0f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2, 0, height,
height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2),
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent())));

} else if (state.equals("focused")) {
// draw background pattern
Point2D center = new Point2D.Float(width / 2, height / 2);
float radius = height / 2;
float[] dist = { 0.2f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2, 0, height,
height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2),
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent())));
} else if (state.equals("pressed")) {
// draw background pattern
int offsetCenter = 1;
Point2D center = new Point2D.Float(width / 2 + offsetCenter,
height / 2 + offsetCenter);
float radius = height / 2;
float[] dist = { 0.2f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2
+ offsetCenter, offsetCenter, height, height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2)
+ offsetCenter,
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent()))
+ offsetCenter);
} else if (state.equals("released")) {
// draw background pattern
Point2D center = new Point2D.Float(width / 2, height / 2);
float radius = height / 2;
float[] dist = { 0.2f, 1.0f };
Color[] colors = { new Color(0, 0, 0, 255),
new Color(255, 255, 255, 0) };
RadialGradientPaint paint = new RadialGradientPaint(center,
radius, dist, colors);
g2.setPaint(paint);
g2.fill(new Ellipse2D.Double(width / 2 - height / 2, 0, height,
height));
// draw string text
g2.setColor(Color.RED);
Font defaultFont = getFont();
g2.setFont(defaultFont);
Rectangle2D rect = defaultFont.getStringBounds(text,
g2.getFontRenderContext());
LineMetrics lineMetrics = defaultFont.getLineMetrics(text,
g2.getFontRenderContext());
g2.drawString(
text,
(float) (width / 2 - rect.getWidth() / 2),
(float) ((height / 2) + ((lineMetrics.getAscent() + lineMetrics
.getDescent()) / 2 - lineMetrics.getDescent())));
}

addMouseListener(new MouseAdapter() {

@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("光标移入组件");
state = "focused";
repaint();
}

@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("光标移出组件");
state = "normal";
repaint();
}

@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
System.out.print("鼠标按键被按下,");
state = "pressed";
repaint();
}

@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
System.out.print("鼠标按键被释放,");
state = "released";
repaint();
}

});

}
}

#26


要实现一个异形的JButton,还要重写这个方法:
public boolean contains(int x, int y)

引用
Gives the UI delegate an opportunity to define the precise shape of this component for the sake of mouse processing.

#27


谢谢,已修改。这个确实给非矩形按钮的鼠标事件提供了更为精确的热点区控制。
由于每帖的字数限制,代码发到了 CSDN博客上。大家有兴趣可以去看看,如果能发表下修改意见那将非常高兴。
引用 26 楼 huntor 的回复:
要实现一个异形的JButton,还要重写这个方法:
Java code1public boolean contains(int x, int y)
引用Gives the UI delegate an opportunity to define the precise shape of this component for the sake of mouse proc……

#28


。。。。没看懂额

#29


。。。哪里没看懂,可以提出来
引用 28 楼 chenzhengfei2010 的回复:
。。。。没看懂额

#30


Java 设置背景图片 的问题
Java 设置背景图片 的问题
Java 设置背景图片 的问题
一个Java编写的MP3 Player :
Java 设置背景图片 的问题
运行环境:JRE 7 或者以上
自行体验吧~~
下载链接