`

JNA实现窗口最小化

阅读更多

原始发表时间:2009-06-27

 

本文学习过程如下图示(下图为整个工作思维导图的一部分):



开发环境:
JDK 1.5 (编译的目标版本为1.4)
JNA 3.0.9(开发时的版本,将会切换为3.1.0)


    做了几个月的Swing,恼人的问题一个接一个的出现了。
    因为项目需要,得重新定制界面风格,继承可怕的UI接口,去实现ButtonUI、MenuUI等等等等,图片显示、组件定位都得自己来。经搜索,发现网上也有现成的工具类,乍一看感觉真好啊,突然觉得春光明媚,希望之星冉冉升起,心说“Swing社区也很有活力嘛”,定睛一看,才知道都是收费的……随便一个项目的工具包都是几百美金……好了不扯这茬,总之是没戏了……自己写吧……(这里犯了一个错误,其实SUN的官方有一个项目叫做SwingX,在swing lab管理下,里面有不少扩展过的控件,应该说功能已经十分强大,而且参考其源代码也能受益匪浅,结果overlook之后,偶开始硬着头皮写自己的扩展……)

    本来不需要用JNA,也不需要Win32API(小用一下并不复杂,看到此文的读者如果还不会,可以大胆尝试使用,控制windows的窗口很有趣……),结果因为用户的一个很合理的需求,不得不用了。

    定制的界面中,标题栏已经被干掉,最小化、最大化、关闭按钮都替换成了自己写的图形化按钮(如下图)
    因为界面去掉了系统默认的外框,而用自己改造过的图形化标题栏,所以这些按钮的最小化、最大化功能必须自己编写。
    之前最小化没有能够实现,因为为了实现标题栏自定义,应用中的导航界面设置了 setUndecorated(true),即去除了操作系统对于窗口的标题栏特性的支持,所以最小化功能无法使用JFrame中的 void setExtendedState(int state) 来实现。

    这时很自然地会想到Win32API来获取窗口句柄,设置窗口显示状态。
    于是想起了之前使用JNA项目(也是使用JNA才实现了上图中右上角的圆角特效),仔细查看官方文档(一开始没有看完官方文档,导致浪费了2个多小时在捣腾 FindWindow 和 GetWindowText 函数),有段参考代码如下:

user32.EnumWindows(new WNDENUMPROC() {
    int count;
    public boolean callback(Pointer hWnd, Pointer userData) {
        System.out.println("Found window " + hWnd + ", total " + ++count);
        return true;
    }
}, null);

    这段代码的启示意义很重要,虽然这段代码在JNA 3.0.9和3.1.0 已经改变了 callback 方法的参数列表,还是让我写出了以下代码:

        final User32 user32 = User32.INSTANCE;

        user32.EnumWindows(new WNDENUMPROC() {
            int count;

            public boolean callback(HWND wnd, Pointer data) {
                System.out.println("Found window " + wnd + ", total " + ++count);
                int buflen = 150;
                byte[] lpString = new byte[300];
                user32.GetWindowText(wnd, lpString, buflen);
                System.out.println("lpString: " + Native.toString(lpString));
                return true;
            }
        }, null);

    虽然上面的代码没有正确完成打印所有窗口标题的意图(打印出乱码),但是它确实列举了系统当前的各个窗口句柄的信息。其中黑体字太重要了,一开始依葫芦画瓢,竟然错写成return false,结果每次都只能打印一个窗口的句柄信息,好生苦恼……

    通过网上搜索 FindWindow 的用法,其函数原型:
     HWND FindWindow
     (
         LPCTSTR lpClassName,
         LPCTSTR lpWindowName
     );

    理解之后,写出如下代码,用于搜索客户端程序的窗口句柄

    static HWND getUnitFrameWnd(){
        HWND hwnd = User32.INSTANCE.FindWindow(null, "XXX系统功能导航(客户端)");
        if (unitFrameWnd == null) {
            unitFrameWnd = hwnd;
        }
        return unitFrameWnd;
    }

    应用程序的导航界面 是整个应用所有窗口的父窗口,所以它的title (这里标题取值为“XXX系统功能导航(客户端)”)就可以作为 FindWindow 的参数 lpWindowName ,至于Java的JFrame程序对应于参数 lpClassName 的取值为“SunAwtFrame ”(猜猜我是怎么知道的,用了VS 2008里附带的Spy++,专门用于查询窗口句柄的信息,装一下VC++好像就会附带了,不一定要VS这个庞然大物……)

----------------------------
注:这边有个教训,一开始以为参数为空,就觉得传内容为空的字符串也可以,结果发现返回句柄信息总是为空,比如
User32.INSTANCE.FindWindow("", "XXX系统功能导航(客户端)");
就无法找到我们需要的窗口句柄,如果我们无法给出某个参数的值,就必须将该参数设置为null(这里参数 lpClassName 应该 置为null)
----------------------------

    后来查询到Win32API中,控制窗口最小化、最大化比较好的函数是 ShowWindow ,因为它在修改窗口状态的同时,立即应用效果。但是遍寻JNA 3.0.9里的 User32 接口也没有找到 ShowWindow 的影子,怎么办呢?
    查询MSDN文档,发现 ShowWindow 函数说明如下:
BOOL ShowWindow(HWND hWnd,int nCmdShow)

    另外关于参数 nCmdShow ,找到几个可用的常量值分别如下:
int SW_MAXIMIZE = 0x03;
int SW_MINIMIZE = 0x06;
int SW_RESTORE = 0x09;

    看字面意思就知道是我们正在寻求的东东。好吧,学习 JNA 源代码User32 来写一个接口 Win32API ,将本地方法映射到Java的源代码,可以写出下面的代码:

public interface Win32API extends User32 {
    /**
     * 最大化窗口
     */
    public static int SW_MAXIMIZE = 0x03;
    /**
     * 最小化窗口
     */
    public static int SW_MINIMIZE = 0x06;
    /**
     * 恢复窗口
     */
    public static int SW_RESTORE = 0x09;
    Win32API INSTANCE = (Win32API) Native.loadLibrary("user32", Win32API.class, DEFAULT_OPTIONS);

    /**
     * Updated at 下午03:44:53, on 2009-6-26<br>
     * 获取桌面句柄
     *
     * @return
     * @author Caesar
     */
    public HWND GetDesktopWindow();

    /**
     * Updated at 下午03:44:59, on 2009-6-26<br>
     * 设置窗口句柄的显示状态
     *
     * @param wnd
     * @param nCmdShow
     *            可选值为SW_MINIMIZE - 最小化, SW_MAXIMIZE - 最大化
     * @return
     * @author Caesar
     * @see #SW_MINIMIZE
     * @see #SW_MAXIMIZE
     */
    public boolean ShowWindow(HWND wnd, int nCmdShow);
}

    我们需要的工具已经收入囊中,接下来就是在最小化按钮的事件处理上做点工作就OK了。

        WindowButton btnWinMin = new WindowButton(winMinIcon, parent) {
            private static final long serialVersionUID = 1L;
            protected void actionPerformed(Container frame) {
                HWND mainFrame = getUnitFrameWnd ();  // 这个函数的代码在前面已有提供,获取客户端主界面的窗口句柄
                Win32API.INSTANCE.ShowWindow(mainFrame, Win32API.SW_MINIMIZE);
            }
        };

    类 WindowButton 继承自JButton,通过提供的图标对象 winMinIcon 来显示定制的最小化按钮效果,其代码如下:

public class WindowButton extends RolloverBrighterButton implements ActionListener {
    private static final long serialVersionUID = 1L;
    private Container parentComponent;

    public WindowButton() {
        super();
    }

    public WindowButton(Icon icon, Container parentComponent) {
        super(icon);
        this.parentComponent = parentComponent;
        addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        actionPerformed(parentComponent);
    }

    protected void actionPerformed(Container frame) {

    }
}

    至此,通过Win32API的调用,实现了定制的最小化按钮的功能。

 

 

 

后记:

 

朋友问:

..难道重写标题必须用jna吗?
http://www.blogjava.net/javagui/archive/2007/11/03/157948.html
可以看下这篇文章..

我回答:
抱歉,让你困扰了,这边我的原因没有写明
因为我使用的L&F是windows look & feel,项目没有给我大量的时间重新开发一套L&F,另外我当时没有来得及仔细的学习OpenSwing,所以在界面外观上想了点偷懒的办法,就是主界面使用自制的风格,按美工给的图片来确定整体风格,一些小的对话窗口、录入框之类的就直接沿用windows L&F
但是使用Windows L&F有个麻烦,就是翻阅源码的时候,发现L&F中各个类基本上是在进行底层的调用(可能直接调用某些C函数库,现在也没有去深究,只是猜测),一看头大了,就想了个歪招,把JFrame和JDialog的外框给去掉了,套上自己画的,然后通过JNA调用Win32实现了窗口最大化、最小化等功能……
原因如上。 :-)
分享到:
评论

相关推荐

    使用JNA获取窗口句柄,并发送消息

    使用JNA获取窗口句柄,并发送消息 可以使用applet的方式,实现 CS架构的SSO.

    Java实现获取窗口句柄并操作窗口jna-4.4.0

    Java实现获取窗口句柄并操作窗口 JNA Java实现获取窗口句柄并操作窗口 JNA

    jna 实现回调函数 code.zip

    jna 实现回调函数 code.zip jna 实现回调函数 code.zip jna 实现回调函数 code.zip jna 实现回调函数 code.zip jna 实现回调函数 code.zip jna 实现回调函数 code.zip jna 实现回调函数 code.zip

    JNA实现回调及其他

    JNA调用C/C++简单demo,包含文档及简单Demo,基本使用的都包含

    jna-4.5.1 , jna-4.5.1-sources , jna-platform-4.5.1 jar包

    jna-4.5.1 , jna-4.5.1-sources , jna-platform-4.5.1 jar包 JNA全称Java Native Access,是一个...开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。

    android studio 上实现JNA

    android 实现jna的所有东西.简单易懂. 

    jna jar实现java调用dll

    MyEclipse 6.5 导入就可测试 绝对能跑起来 实现 java 通过 jna 包 调用dll

    JNA 回调 范例 C++异步回调实现

    这几天搞搞JNA,主要是组内小弟靠不住。 找了下资料,居然没有回调函数的样例,郁闷的我不行,于是就自己折腾一晚上,自己实现一个。 C++部分使用ACE实现了一个线程,线程中调用Java部分的回调函数。 C++使用vc8...

    JNA实例 JNA实例 JNA实例

    JNA实例=======================================================JNA实例

    jna-5.5.0.jar中文文档.zip

    ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1...

    jna-4.3.0-API文档-中文版.zip

    赠送jar包:jna-4.3.0.jar; 赠送原API文档:jna-4.3.0-javadoc.jar; 赠送源代码:jna-4.3.0-sources.jar; 赠送Maven依赖信息文件:jna...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    jna-5.4.0.jar中文文档.zip

    ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1...

    jna-4.1.0-API文档-中文版.zip

    赠送jar包:jna-4.1.0.jar; 赠送原API文档:jna-4.1.0-javadoc.jar; 赠送源代码:jna-4.1.0-sources.jar; 赠送Maven依赖信息文件:jna...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    深入浅出JNA

    描述jna实现dll调用的文档,替换原有JNI方式

    jna-5.0.0.jar中文文档.zip

    ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1...

    JNA-5.7.0 jna-platform-5.7.0

    JNA-5.7.0 jna-platform-5.7.0

    jna-4.0.0.jar中文文档.zip

    ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1...

    jna-5.10.0.jar中文文档.zip

    ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1...

    jna-5.9.0.jar

    2021 最新JNA jar包,jna-5.9.0

Global site tag (gtag.js) - Google Analytics