JavaSwing不规则窗体

JAVA程序的外表总是一板一眼的,看多了难免审美疲劳,能不能使我们的JAVA程序外观变得更美观更独特呢?答案是肯定的,我们可以让JAVA程序根据图片来生成自定义的不规则窗体。比如下图的这种外观:

image-20220312150455062

首先要说明一下,本方法是基于com.sun.awt.AWTUtilities这个类实现的,而这个类只能在jdk-6u10版本以后的版本才能体现出来的,在本文中讨论的所有 API 在新 com.sun.awt.AWTUtilities 类中出现,该类不是官方支持的部分 API。它在 Java SE 7 中的位置最有可能发生改变,签名方法可能在现在和最终的 Consumer JRE 发行之间发生轻微变化。

JDK地址:http://java.sun.com/javase/downloads/index.jsp

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Area;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.JFrame;
import com.sun.awt.AWTUtilities;

/**
*不规则窗体示例
* @author Hexen
*/
public class IrregularFormSample extends JFrame {

private static final long serialVersionUID = 1L;
private Point origin; //用于移动窗体
private Image img; //用来设定窗体不规则样式的图片

public IrregularFormSample() {
super();

/*首先初始化一张图片,我们可以选择一张有透明部分的不规则图片
* (当然我们要选择支持Alpha(透明)层的图片格式,如PNG),这张
*图片将被用来生成与其形状相同的不规则窗体
*/
MediaTracker mt=new MediaTracker(this);
img=Toolkit.getDefaultToolkit().createImage("remi.png");
mt.addImage(img, 0);
try {
mt.waitForAll();
} catch (InterruptedException e) {
e.printStackTrace();
}

try {
initialize();//窗体初始化
} catch (IOException e) {
e.printStackTrace();
}
}


/**
*窗体初始化
* @throws IOException
*/
private void initialize() throws IOException {
//设定窗体大小和图片一样大
this.setSize(img.getWidth(null), img.getHeight(null));
//设定禁用窗体装饰,这样就取消了默认的窗体结构
this.setUndecorated(true);
//初始化用于移动窗体的原点
this.origin=new Point();

//调用AWTUtilities的setWindowShape方法设定本窗体为制定的Shape形状
AWTUtilities.setWindowShape(this,getImageShape(img));
//设定窗体可见度
AWTUtilities.setWindowOpacity(this, 0.8f);

this.setLocationRelativeTo(null);

//由于取消了默认的窗体结构,所以我们要手动设置一下移动窗体的方法
addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e){
origin.x = e.getX();
origin.y = e.getY();
}
//窗体上单击鼠标右键关闭程序
public void mouseClicked(MouseEvent e) {
if(e.getButton()==MouseEvent.BUTTON3)
System.exit(0);
}
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
}
@Override
public void mouseEntered(MouseEvent e) {
repaint();
}
}
);

addMouseMotionListener(
new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
Point p = getLocation();
setLocation(p.x + e.getX() - origin.x, p.y + e.getY() - origin.y );
}
}
);
}


/**
*将Image图像转换为Shape图形
* @param img
* @param isFiltrate
* @return Image图像的Shape图形表示
* @author Hexen
*/
public Shape getImageShape(Image img) {
ArrayList<Integer> x=new ArrayList<Integer>();
ArrayList<Integer> y=new ArrayList<Integer>();
int width=img.getWidth(null);//图像宽度
int height=img.getHeight(null);//图像高度

//筛选像素
//首先获取图像所有的像素信息
PixelGrabber pgr = new PixelGrabber(img, 0, 0, -1, -1, true);
try {
pgr.grabPixels();
} catch (InterruptedException ex) {
ex.getStackTrace();
}
int pixels[] = (int[]) pgr.getPixels();

//循环像素
for (int i = 0; i < pixels.length; i++) {
//筛选,将不透明的像素的坐标加入到坐标ArrayList x和y中
int alpha = getAlpha(pixels[i]);
if (alpha == 0){
continue;
}else{
x.add(i%width>0 ? i%width-1:0);
y.add(i%width==0 ? (i==0 ? 0:i/width-1):i/width);
}
}

//建立图像矩阵并初始化(0为透明,1为不透明)
int[][] matrix=new int[height][width];
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
matrix[i][j]=0;
}
}

//导入坐标ArrayList中的不透明坐标信息
for(int c=0;c<x.size();c++){
matrix[y.get(c)][x.get(c)]=1;
}

/*由于Area类所表示区域可以进行合并,我们逐一水平"扫描"图像矩阵的每一行,
*将不透明的像素生成为Rectangle,再将每一行的Rectangle通过Area类的rec
*对象进行合并,最后形成一个完整的Shape图形
*/
Area rec=new Area();
int temp=0;

for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
if(matrix[i][j]==1){
if(temp==0)
temp=j;
else if(j==width){
if(temp==0){
Rectangle rectemp=new Rectangle(j,i,1,1);
rec.add(new Area(rectemp));
}else{
Rectangle rectemp=new Rectangle(temp,i,j-temp,1);
rec.add(new Area(rectemp));
temp=0;
}
}
}else{
if(temp!=0){
Rectangle rectemp=new Rectangle(temp,i,j-temp,1);
rec.add(new Area(rectemp));
temp=0;
}
}
}
temp=0;
}
return rec;
}


/**
*获取像素的Alpha值
* @param pixel
* @return像素的Alpha值
*/
private int getAlpha(int pixel) {
return (pixel >> 24) & 0xff;
}


/*我们可以选择在窗体上绘制图片,是窗体完全呈现出图片的样式,
*当然我们也可以根据需要不绘制它,而采取其他操作
*/
@Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(img, 0, 0, null);
}

public static void main(String[] args) {
IrregularFormSample sample = new IrregularFormSample();
sample.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sample.setVisible(true);
}
}