タイトルバー消してもそれっぽいのが残るので、シェルスタイルをNO_TRIMにして移動とリサイズが出来るようにしてみる。
右下のみでリサイズ可能。
package swt.window.resize;
import org.eclipse.swt.SWT;
import org.eclipse.swt.internal.Callback;
import org.eclipse.swt.internal.win32.OS;
import org.eclipse.swt.internal.win32.POINT;
import org.eclipse.swt.internal.win32.RECT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.wb.swt.SWTResourceManager;
public class NoTitleBarWindowResize {
static long defWndProc;
static boolean isResizeable = false;
static RECT dragRect = null;
static POINT dragPoint = null;
/**
* ウィンドウプロシージャ<br>
*
* @param hWnd ウィンドウハンドル<br>
* @param msg ウィンドウメッセージ<br>
* @param wp WPARAM<br>
* @param lp LPARAM<br>
* @return ウィンドウプロシージャの戻り値<br>
*/
public static long windowProc(long hWnd, long msg, long wp, long lp) {
switch ((int) msg) {
case OS.WM_MOUSEMOVE:
/* マウス移動 */
switch ((int) wp) {
case OS.MK_LBUTTON:
if (isResizeable) {
if (dragRect == null || dragPoint == null) {
dragRect = new RECT();
dragPoint = new POINT();
OS.GetWindowRect(hWnd, dragRect);
dragPoint.x = toLoWord(lp);
dragPoint.y = toHiWord(lp);
}
long newWidth = (dragRect.right - dragRect.left) + (toLoWord(lp) - dragPoint.x);
long newHeight = (dragRect.bottom - dragRect.top) + (toHiWord(lp) - dragPoint.y);
OS.SetWindowPos(hWnd, (long) OS.HWND_TOP, 0, 0, (int) newWidth, (int) newHeight, OS.SWP_NOMOVE);
} else {
OS.ReleaseCapture();
OS.SendMessage(hWnd, OS.WM_NCLBUTTONDOWN, OS.HTCAPTION, 0);
}
return 0;
default:
dragRect = null;
dragPoint = null;
break;
}
break;
case OS.WM_NCHITTEST:
/* ウィンドウ内にカーソルがある */
// ウィンドウサイズ取得
RECT rect = new RECT();
OS.GetWindowRect(hWnd, rect);
// スクリーンクライアント座標変換
POINT pointScreen = new POINT();
OS.ScreenToClient(hWnd, pointScreen);
// リサイズ可能判定
long rectWidth = rect.right - rect.left;
long rectHeight = rect.bottom - rect.top;
long clientX = toLoWord(lp) + pointScreen.x;
long clientY = toHiWord(lp) + pointScreen.y;
if ((rectWidth - 8 <= clientX && clientX <= rectWidth)
&& (rectHeight - 8 <= clientY && clientY <= rectHeight)) {
OS.SetCursor(OS.LoadCursor(0, OS.IDC_SIZENWSE));
isResizeable = true;
} else {
OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW));
isResizeable = false;
}
break;
case OS.WM_SETCURSOR:
/* カーソル変更時 */
if (toLoWord(lp) == OS.HTCLIENT) {
return 0;
}
break;
}
return OS.CallWindowProc(defWndProc, hWnd, (int) msg, wp, lp);
}
/**
* メイン<br>
*
* @param args 引数<br>
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display, SWT.NO_TRIM);
shell.setBackground(SWTResourceManager.getColor(SWT.COLOR_GRAY));
/* ウィンドウプロシージャ */
Callback windowProcCallback = new Callback(NoTitleBarWindowResize.class, "windowProc", 4);
defWndProc = OS.SetWindowLongPtr(shell.handle, OS.GWL_WNDPROC, windowProcCallback.getAddress());
shell.setSize(256, 128);
shell.setLayout(new FillLayout(SWT.HORIZONTAL));
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
/**
* 上位ビット<br>
*
* @param val 値<br>
* @return 上位ビット<br>
*/
private static int toHiWord(long val) {
return (int) (val >> 16);
}
/**
* 下位ビット<br>
*
* @param val 値<br>
* @return 下位ビット<br>
*/
private static int toLoWord(long val) {
return (int) (val & 0xFFFF);
}
}
ウィンドウプロシージャとか持ち出したので「SWTでやる意味とは?」状態ですが…
/* ウィンドウプロシージャ */
Callback windowProcCallback = new Callback(NoTitleBarWindowResize.class, "windowProc", 4);
defWndProc = OS.SetWindowLongPtr(shell.handle, OS.GWL_WNDPROC, windowProcCallback.getAddress());
この部分で自作のウィンドウプロシージャとデフォルトとを入れ替えます。
入れ替えた際にデフォルトのウィンドウプロシージャが戻り値として取れるので、保存しておいて自作プロシージャの最後で呼ぶようにします。
こうすることで、自作部分以外はデフォルトで処理されるようになります。
WM_NCHITTEST
でクライアント領域内のカーソル判定を行い、マウスカーソルが右下にある場合リサイズ可能とカーソル変更しています。
WM_MOUSEMOVE
でマウスの移動とその際左ボタン押下があるかみてウィンドウサイズ変更しています。
コメントを残す