简体   繁体   中英

Windows 7 Taskbar Progress Bar in Java

I'd like to know if it is possible to make a progress bar displayed on the taskbar like Windows Explorer does when there's a file operation going on?

I saw many examples, but they all involved C#.

SWT won't cut it.

任务栏上显示的进度条

I found out that this feature is included in Java 9 . It is part of AWT and it is quity simple too use.

Here is short example:

import java.awt.Taskbar;
import java.awt.Taskbar.State;

import javax.swing.JFrame;
import javax.swing.WindowConstants;

/**
 * @author fxl
 */
public class TaskbarSample {

    public static void main(String[] args) {

        // JavaDoc:
        // https://docs.oracle.com/javase/9/docs/api/java/awt/Taskbar.html

        // MSDNDoc:
        // https://msdn.microsoft.com/en-us/library/dd391692(VS.85).aspx
        if (Taskbar.isTaskbarSupported() == false) {
            return;
        }

        JFrame dialog = new JFrame("Test - 50%");
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);    


        Taskbar taskbar = Taskbar.getTaskbar();
        taskbar.setWindowProgressState(dialog, State.ERROR);
        taskbar.setWindowProgressValue(dialog, 50);     
    }

}

this is now possible using SWT please review the code example:
org.eclipse.swt.snippets.Snippet336

This example will do the job:

Task bar:
在此处输入图片说明

Code:

import org.bridj.Platform;
import org.bridj.Pointer;
import org.bridj.cpp.com.COMRuntime;
import org.bridj.cpp.com.shell.ITaskbarList3;
import org.bridj.jawt.JAWTUtils;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TaskBarListDemo extends JFrame implements ActionListener, ChangeListener
{
    private ITaskbarList3 list;
    private JSlider slider;
    private Pointer<?> hwnd;

    private TaskBarListDemo() throws ClassNotFoundException
    {
        super("TaskbarList Demo (" + (Platform.is64Bits() ? "64 bits" : "32 bits") + ")");

        list = COMRuntime.newInstance(ITaskbarList3.class);

        getContentPane().add("Center", new JLabel("Hello Native Windows 7 World !"));
        Box box = Box.createVerticalBox();

        int min = 0;
        int max = 300;
        int val = (min + max / 2);
        slider = new JSlider(min, max, val);
        slider.addChangeListener(this);
        box.add(slider);

        ButtonGroup group = new ButtonGroup();
        for (ITaskbarList3.TbpFlag state : ITaskbarList3.TbpFlag.values())
        {
            JRadioButton cb = new JRadioButton(state.name());
            group.add(cb);
            cb.putClientProperty(ITaskbarList3.TbpFlag.class, state);
            cb.setSelected(state == ITaskbarList3.TbpFlag.TBPF_NORMAL);
            cb.addActionListener(this);
            box.add(cb);
        }
        getContentPane().add("South", box);

    }

    @Override
    protected void finalize() throws Throwable
    {
        super.finalize();
        list.Release();
    }

    public void setVisible(boolean visible)
    {
        super.setVisible(visible);

        long hwndVal = JAWTUtils.getNativePeerHandle(this);
        hwnd = Pointer.pointerToAddress(hwndVal);
        list.SetProgressValue((Pointer) hwnd, slider.getValue(), slider.getMaximum());
    }

    @Override
    public void stateChanged(ChangeEvent actionEvent)
    {
        list.SetProgressValue((Pointer) hwnd, slider.getValue(), slider.getMaximum());
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent)
    {
        JRadioButton button = ((JRadioButton) actionEvent.getSource());
        if (button.isSelected())
        {
            ITaskbarList3.TbpFlag flag = (ITaskbarList3.TbpFlag) button.getClientProperty(ITaskbarList3.TbpFlag.class);
            list.SetProgressValue((Pointer) hwnd, slider.getValue(), slider.getMaximum());
            list.SetProgressState((Pointer) hwnd, flag);
        }
    }

    public static void main(String[] arguments) throws Exception
    {
        TaskBarListDemo f = new TaskBarListDemo();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
}

Maven dependencies:

<dependencies>
    <dependency>
        <groupId>com.nativelibs4java</groupId>
        <artifactId>bridj</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna-platform</artifactId>
        <version>LATEST</version>
    </dependency>
</dependencies>

There is no standard facility in Java for doing so, yet.

Hence you need to talk to Windows directly to do that. So you need to locate the correct Windows routine, and use JNA (probably the easiest) to invoke that routine. I do not know of a vendor or a project who has done this already.


Edit: It appears that the http://code.google.com/p/nativelibs4java/ project may do what you want.

There is a Java library providing the new Windows 7 features for Java. It's called J7Goodies by Strix Code . It allows you to display taskbar progress bar and do much more.

Windows exposes this through COM. I am sure a "flat DLL" call would be easier for you, but if you can get to COM you can do this. The COM interface is ITaskbarList3 (there is also an ITaskbarList4 you can use that inherits from it.) http://msdn.microsoft.com/en-us/library/dd391692(VS.85).aspx documents it. SetProgressState and SetProgressValue are the methods you will want to invoke. State is normal (green), paused (yellow), error (red), indeterminate (swooshing green) and none. On the MSDN page some community people have added details of calling this COM component from VB and C# - that might help you figure out the setup and tear down required from Java.

As Java9's java.awt.Taskbar only works for old swing frames (they somehow forgot to implement this for javafx.stage.Stage) and com.nativelibs4java bridj isn't working (anymore) (see https://github.com/nativelibs4java/BridJ/issues/94 ) I implemented a solution using JNA 4.1.0.

Please note:

  • Relies on calling internal javafx api (com.sun.javafx.stage.WindowHelper) - so it might break with the next java update
  • It only sets the "indeterminate" progress state - but normal progress state should be possible too with some adjustments

Hope this helps.

ITaskbarList3.java

package example;

import com.sun.jna.platform.win32.Guid.IID;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinNT.HRESULT;

public interface ITaskbarList3 {
    IID IID_ITASKBARLIST3 = new IID("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf"); // from ShObjIdl.h

    int TBPF_NOPROGRESS = 0;
    int TBPF_INDETERMINATE = 0x1;
    int TBPF_NORMAL = 0x2;
    int TBPF_ERROR = 0x4;
    int TBPF_PAUSED = 0x8;

    HRESULT SetProgressState(HWND hwnd, int tbpFlags);
}

TaskbarList3.java

package example;

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.platform.win32.COM.COMInvoker;

public final class TaskbarList3 extends COMInvoker implements ITaskbarList3 {

    public TaskbarList3(Pointer pointer) {
        setPointer(pointer);
    }

    @Override
    public HRESULT SetProgressState(HWND hwnd, int tbpFlags) {
        return (HRESULT) this._invokeNativeObject(
                10, // magic number (gathered by trial and error)
                new Object[] { this.getPointer(), hwnd, tbpFlags },
                HRESULT.class);
    }
}

TaskbarPeer.java

package example;

import com.sun.javafx.stage.WindowHelper;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Guid.CLSID;
import com.sun.jna.platform.win32.Ole32;
import com.sun.jna.platform.win32.W32Errors;
import com.sun.jna.platform.win32.WTypes;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.ptr.PointerByReference;

import javafx.stage.Stage;

public final class TaskbarPeer {

    public static void setIndeterminateProgress(Stage stage, boolean indeterminate) {
        final var peer = WindowHelper.getPeer(stage);
        final long windowHandle = peer.getRawHandle();

        final var clsid = new CLSID("56FDF344-FD6D-11d0-958A-006097C9A090"); // from ShObjIdl.h
        final var taskbarListPointerRef = new PointerByReference();

        var hr = Ole32.INSTANCE.CoCreateInstance(clsid, null, WTypes.CLSCTX_SERVER,
                ITaskbarList3.IID_ITASKBARLIST3, taskbarListPointerRef);

        if (W32Errors.FAILED(hr)) {
            throw new RuntimeException("failed with code: " + hr.intValue());
        }

        final TaskbarList3 taskbarList = new TaskbarList3(taskbarListPointerRef.getValue());
        final var hwnd = new HWND(new Pointer(windowHandle));
        final int progressState = indeterminate ? ITaskbarList3.TBPF_INDETERMINATE : ITaskbarList3.TBPF_NOPROGRESS;
        hr = taskbarList.SetProgressState(hwnd, progressState);

        if (W32Errors.FAILED(hr)) {
            throw new RuntimeException("failed with code: " + hr.intValue());
        }
    }
}

Sample.java

package example;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

public final class Sample extends Application {

    private boolean indeterminateProgressState = false;

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        final Button btn = new Button("Click me!");

        primaryStage.setScene(new Scene(btn));
        primaryStage.sizeToScene();
        primaryStage.show();

        btn.setOnAction(evt -> {
            indeterminateProgressState = !indeterminateProgressState;
            TaskbarPeer.setIndeterminateProgress(primaryStage, indeterminateProgressState);
        });
    }
}

如果您使用javaFX,此库将为您提供帮助: https : //github.com/daniprogramer777/FXTaskbarProgressBar

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM