Swing 不规则窗体的制作

终极解决之道

经过反复的研究探索,终于获得了一个完美的解决方法:不用shape、不用抓图、不用workaround,真正的、彻底的、完全的、随意的在桌面上任意绘图、涂鸦、撒野,真正的属于程序员的Freedom!下面就来一起揭开这层窗户纸吧!

 

在程序中依次设置以下几个参数:

  • 设置窗口完全透明:AWTUtilities.setWindowOpaque(frame, false);
  • 设置窗口无边缘:frame.setUndecorated(true);
  • 设置窗口的ContentPane为要显示的Pane:frame.setContentPane(myPane);
  • 在myPane中放置具体要显示的内容,也可以重载paint方法进行Java2D绘制。这些paint会直接发生在桌面背景上。
  • 接下来,就是见证奇迹的时刻!

 

 (不好意思,暴露我的桌面了)

 

通过上面方法,可以做一个任意大小、任意位置的window,在相应的桌面位置上随意显示Swing组件,或做任意Java2D画图。比如下面小例子可以在屏幕上直接画一个红色的立体矩形,而没有显示窗口:

 

 

Java代码   收藏代码
    import com.sun.awt.AWTUtilities;  
    import java.awt.Color;  
    import java.awt.Graphics;  
    import javax.swing.JFrame;  
    import javax.swing.JPanel;  
      
    public class Test {  
      
        public static void main(String[] args) {  
            JFrame frame = new JFrame();  
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
            frame.setUndecorated(true);  
            frame.setBounds(500, 500, 300, 300);  
            AWTUtilities.setWindowOpaque(frame, false);  
      
            JPanel pane = new JPanel() {  
      
                @Override  
                public void paint(Graphics g) {  
                    super.paint(g);  
      
                    g.setColor(Color.red);  
                    g.fill3DRect(10, 10, 100, 100, true);  
                }  
            };  
      
            frame.setContentPane(pane);  
      
            frame.setVisible(true);  
        }  
    }  

 

运行效果如下图:


窗口的拖拽移动

窗口不再规则,窗口标题栏不再出现,如何移动窗口?按照其他类似软件的习惯做法,应当允许用鼠标直接拖拽窗体任意位置进行窗口移动。做一个鼠标监听器对窗口中的元素进行拖动监听,对窗口进行相应拖动距离的移动:

 

Java代码   收藏代码

    private MouseAdapter moveWindowListener = new MouseAdapter() {  
      
            private Point lastPoint = null;  
      
            @Override  
            public void mousePressed(MouseEvent e) {  
                lastPoint = e.getLocationOnScreen();  
            }  
      
            @Override  
            public void mouseDragged(MouseEvent e) {  
                Point point = e.getLocationOnScreen();  
                int offsetX = point.x - lastPoint.x;  
                int offsetY = point.y - lastPoint.y;  
                Rectangle bounds = FreeLoginUI.this.getBounds();  
                bounds.x += offsetX;  
                bounds.y += offsetY;  
                FreeLoginUI.this.setBounds(bounds);  
                lastPoint = point;  
            }  
    };  

  对窗体上的组件安装这一listener,就可以对窗口中任意元素进行拖拽,直接拖动窗体四处晃悠了。

 

图片的切割

要做好的界面,需要一个耐心、有创意的美工大力协助,例如图片的切割就很重要。下图展示了如何从效果图进行具体切割素材:

 


制作渐变背景Panel

仔细观察中间的输入区域部分,其背景是有渐变设计的。其制作方法也很简单:首先让美工帮助制作一个一个像素宽、整个panel高度的小图片作为素材;然后用这个图片创建纹理Paint;最后用这个纹理对真个panel进行fill。

 

Java代码   收藏代码
    private JPanel inputPane = new JPanel() {  
      
            private String backgroundImageURL = FreeUtil.getImageURL("login_background.png");  
            private TexturePaint paint = FreeUtil.createTexturePaint(backgroundImageURL);  
      
            @Override  
            protected void paintComponent(Graphics g) {  
                super.paintComponent(g);  
                Graphics2D g2d = (Graphics2D) g;  
                g2d.setPaint(paint);  
                g2d.fillRect(0, 0, this.getWidth(), this.getHeight());  
            }  
        };  

 

 

肆虐你的桌面:六月飘雪!

既然窗户纸捅破了,在桌面上就随意折腾吧。这几天窗外酷热难耐,咱们就来个桌面飘雪,也许可以望梅止渴,带来丝丝清凉吧!

 

先准备一个雪花的png透明图片,然后在桌面上随机生成50个雪花坐标,每次paint让每个雪花的左右略微抖一下(snowX[i] += TWaverUtil.getRandomInt(5) - 3),垂直距离下坠5像素(snowY[i] += 5),再旋转个小角度。然后,用一个线程不停的repaint窗口。

 

雪花png图片:

 


程序代码如下:

 

 

Java代码   收藏代码
    public class TestSnow {  
      
        public static void main(String[] args) {  
            final JFrame frame = new JFrame();  
            frame.setAlwaysOnTop(true);  
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
            frame.setUndecorated(true);  
            frame.setExtendedState(JFrame.MAXIMIZED_BOTH);  
            AWTUtilities.setWindowOpaque(frame, false);  
      
            final JPanel pane = new JPanel() {  
      
                private int[] snowX = null;  
                private int[] snowY = null;  
                private int[] angles = null;  
                private int count = 50;  
      
                @Override  
                public void paint(Graphics g) {  
                    super.paint(g);  
                    Rectangle bounds = frame.getBounds();  
                    if (snowX == null) {  
      
                        snowX = new int[count];  
                        for (int i = 0; i < snowX.length; i++) {  
                            snowX[i] = TWaverUtil.getRandomInt(bounds.width);  
                        }  
                        snowY = new int[count];  
                        for (int i = 0; i < snowY.length; i++) {  
                            snowY[i] = TWaverUtil.getRandomInt(bounds.height);  
                        }  
                        angles = new int[count];  
                        for (int i = 0; i < snowY.length; i++) {  
                            angles[i] = TWaverUtil.getRandomInt(360);  
                        }  
                    }  
      
                    Graphics2D g2d = (Graphics2D) g;  
                    Image image = TWaverUtil.getImage("/free/test/snow.png");  
                    for (int i = 0; i < count; i++) {  
                        snowX[i] += TWaverUtil.getRandomInt(5) - 3;  
                        snowY[i] += 5;  
                        angles[i] += i / 5;  
                        snowY[i] = snowY[i] > bounds.height ? 0 : snowY[i];  
                        angles[i] = angles[i] > 360 ? 0 : angles[i];  
                        int x = snowX[i];  
                        int y = snowY[i];  
                        int angle = angles[i];  
                        g2d.translate(x, y);  
                        double angleValue = Math.toRadians(angle);  
                        g2d.rotate(angleValue);  
                        g2d.drawImage(image, 0, 0, null);  
                        g2d.rotate(-angleValue);  
                        g2d.translate(-x, -y);  
                    }  
                }  
            };  
      
            frame.setContentPane(pane);  
            frame.setVisible(true);  
            Thread thread = new Thread() {  
      
                @Override  
                public void run() {  
                    while (true) {  
                        try {  
                            Thread.sleep(10);  
                        } catch (Exception ex) {  
                            ex.printStackTrace();  
                        }  
                        pane.repaint();  
                    }  
                }  
            };  
      
            thread.start();  
        }  
    }  

 

快快运行代码,让雪花飘起来吧!

 


 

如果愿意折腾,还可以修改代码中的:

 

  • private int count = 50,调整雪花的数量;
  • 修改angles[i] += i / 5,调整雪花翻滚的速度;
  • 修改snowY[i] += 5,调整雪花下坠的速度;
  • 修改snowX[i] += TWaverUtil.getRandomInt(5) – 3,调整雪花左右摆动的速度;

 

别说你不知道怎么结束程序啊,不会Alt+F4的话,你这个程序员肯定不合格了。

秘密背后的秘密

当把透明窗口Frame设置特别大以后(例如10000*10000),你会发现不但界面变得极其缓慢,而且还会内存溢出。Sun的秘密不言自明了:还是使用了BufferedImage。否则,鼠标点击你画的椭圆或桌面的图标,它如何知道是点击了窗体,还是操作了桌面?只能生成内存图片,在里面进行像素判断了。要挖掘再深入的秘密,我也不清楚了,自己继续探索吧!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值