如何通过Java Desktop.open实现两个Windows资源管理器窗口分屏显示
Hey, I get it — Java's Desktop.open() API is great for launching apps, but it doesn't give you any control over window positioning or sizing. To get those two Explorer windows side-by-side on Windows, we need to leverage native Windows functionality. Here are two solid solutions:
Solution 1: Use PowerShell Script (No Extra Dependencies)
Windows PowerShell can call system APIs directly to manipulate window positions. We can execute PowerShell commands from Java to handle the split-screen setup:
Code Example
import java.io.IOException; public class ExplorerSplitScreen { public static void main(String[] args) throws IOException { String folder1 = "C:\\Users\\YourUser\\Documents"; String folder2 = "C:\\Users\\YourUser\\Downloads"; // Open first folder and move it to left half String leftCommand = String.format( "powershell -Command \"Start-Process explorer.exe '%s'; Start-Sleep -Seconds 1; $hwnd = (Get-Process explorer | Where-Object {$_.MainWindowTitle -eq '%s'}).MainWindowHandle; Add-Type '@\"using System; using System.Runtime.InteropServices; public class Win32 { [DllImport(\"user32.dll\")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); }\"@; [Win32]::SetWindowPos($hwnd, [IntPtr]0, 0, 0, [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Width/2, [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Height, 0x0001)'", folder1, getFolderName(folder1) ); Runtime.getRuntime().exec(leftCommand); // Open second folder and move it to right half String rightCommand = String.format( "powershell -Command \"Start-Process explorer.exe '%s'; Start-Sleep -Seconds 1; $hwnd = (Get-Process explorer | Where-Object {$_.MainWindowTitle -eq '%s'}).MainWindowHandle; Add-Type '@\"using System; using System.Runtime.InteropServices; public class Win32 { [DllImport(\"user32.dll\")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); }\"@; [Win32]::SetWindowPos($hwnd, [IntPtr]0, [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Width/2, 0, [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Width/2, [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Height, 0x0001)'", folder2, getFolderName(folder2) ); Runtime.getRuntime().exec(rightCommand); } // Helper to extract folder name from path private static String getFolderName(String path) { return path.substring(path.lastIndexOf("\\") + 1); } }
Notes
- The
Start-Sleep -Seconds 1gives Explorer time to fully open before we try to adjust its position — if your system is slower, bump this up to 2 seconds to avoid missing the window handle. - This relies on matching the Explorer window's title to the folder name, so make sure your target folders have unique names to avoid selecting the wrong window.
Solution 2: Use JNA to Call Windows APIs (More Reliable)
If you need a more robust solution (that doesn't depend on window titles), use JNA (Java Native Access) to directly call Windows' user32.dll to get and set window positions.
Step 1: Add JNA Dependencies
If using Maven, add these to your pom.xml:
<dependencies> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.13.0</version> </dependency> </dependencies>
Code Example
import com.sun.jna.Native; import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.platform.win32.WinUser; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class ExplorerSplitScreenJNA { public static void main(String[] args) throws IOException, InterruptedException { String folder1 = "C:\\Users\\YourUser\\Documents"; String folder2 = "C:\\Users\\YourUser\\Downloads"; // Track existing Explorer process IDs before opening new windows List<Integer> existingExplorerPids = getExplorerPids(); // Open first folder Runtime.getRuntime().exec("explorer.exe " + folder1); Thread.sleep(1000); WinDef.HWND hwnd1 = getNewExplorerWindow(existingExplorerPids); // Open second folder Runtime.getRuntime().exec("explorer.exe " + folder2); Thread.sleep(1000); WinDef.HWND hwnd2 = getNewExplorerWindow(existingExplorerPids); // Get screen working area (excludes taskbar) WinUser.RECT screenRect = new WinUser.RECT(); User32.INSTANCE.GetWindowRect(User32.INSTANCE.GetDesktopWindow(), screenRect); int screenWidth = screenRect.right - screenRect.left; int screenHeight = screenRect.bottom - screenRect.top; // Move first window to left half User32.INSTANCE.SetWindowPos(hwnd1, WinUser.HWND_TOP, 0, 0, screenWidth / 2, screenHeight, WinUser.SWP_SHOWWINDOW); // Move second window to right half User32.INSTANCE.SetWindowPos(hwnd2, WinUser.HWND_TOP, screenWidth / 2, 0, screenWidth / 2, screenHeight, WinUser.SWP_SHOWWINDOW); } // Get all running Explorer process IDs private static List<Integer> getExplorerPids() { List<Integer> pids = new ArrayList<>(); User32.INSTANCE.EnumWindows((hwnd, data) -> { WinDef.DWORDByReference pidRef = new WinDef.DWORDByReference(); User32.INSTANCE.GetWindowThreadProcessId(hwnd, pidRef); int pid = pidRef.getValue().intValue(); if (getProcessName(pid).equalsIgnoreCase("explorer.exe")) { pids.add(pid); } return true; }, null); return pids; } // Get the handle of the newly opened Explorer window private static WinDef.HWND getNewExplorerWindow(List<Integer> existingPids) { List<Integer> currentPids = getExplorerPids(); currentPids.removeAll(existingPids); if (currentPids.isEmpty()) return null; WinDef.HWND[] windowHandle = new WinDef.HWND[1]; User32.INSTANCE.EnumWindows((hwnd, data) -> { WinDef.DWORDByReference pidRef = new WinDef.DWORDByReference(); User32.INSTANCE.GetWindowThreadProcessId(hwnd, pidRef); int pid = pidRef.getValue().intValue(); if (currentPids.contains(pid) && User32.INSTANCE.IsWindowVisible(hwnd)) { windowHandle[0] = hwnd; return false; // Stop enumerating once we find the window } return true; }, null); return windowHandle[0]; } // Get process name from PID (simplified version) private static String getProcessName(int pid) { try { // A quick way to get process name; for full reliability, use Kernel32 via JNA return new java.io.File( java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0] ).getAbsoluteFile().getParentFile().getParentFile().getName(); } catch (Exception e) { return ""; } } }
Advantages
- Doesn't rely on window titles — tracks new Explorer windows via process IDs, so it's more reliable even if folder names are duplicated.
- Gives you precise control over window position and size, and can be adapted for multi-monitor setups by adjusting how you retrieve screen bounds.
Wrap-Up
If you want a quick fix without adding dependencies, go with the PowerShell approach. If you need robustness and flexibility, the JNA method is the way to go. Both will get those two Explorer windows sitting nicely side-by-side.
内容的提问来源于stack exchange,提问作者CoutWout

