Windows 7 Taskbar Progress Bar in Java
I'd like to know if it is开发者_Python百科 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.
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);
});
}
}
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.
精彩评论