There's a lot of fine examples here which demonstrate splitter bars of various sorts, and a search did not reveal one quite like this one. Full working example, the splitter bar handler stuff is at the bottom. This is a little different because it uses a custom window class to handle the movement of the splitter bar indication, in this case, a focus rectangle. Converting this to a live update is not that much more of an effort either, just uncomment the PostMessage in the %WM_MOUSEMOVE. I think it's cheezy because I'm using the DrawFocusRect in a "non-live" mode to indicate the location of the splitter bar. 

Code:
#PBFORMS CREATED V1.51 '------------------------------------------------------------------------------ ' The first line in this file is a PB/Forms metastatement. ' It should ALWAYS be the first line of the file. Other ' PB/Forms metastatements are placed at the beginning and ' end of "Named Blocks" of code that should be edited ' with PBForms only. Do not manually edit or delete these ' metastatements or PB/Forms will not be able to reread ' the file correctly. See the PB/Forms documentation for ' more information. ' Named blocks begin like this: #PBFORMS BEGIN ... ' Named blocks end like this: #PBFORMS END ... ' Other PB/Forms metastatements such as: ' #PBFORMS DECLARATIONS ' are used by PB/Forms to insert additional code. ' Feel free to make changes anywhere else in the file. '------------------------------------------------------------------------------ #COMPILE EXE #DIM ALL '------------------------------------------------------------------------------ ' ** Includes ** '------------------------------------------------------------------------------ #PBFORMS BEGIN INCLUDES %USEMACROS = 1 #IF NOT %DEF(%WINAPI) #INCLUDE "WIN32API.INC" #ENDIF #IF NOT %DEF(%COMMCTRL_INC) #INCLUDE "COMMCTRL.INC" #ENDIF #INCLUDE "PBForms.INC" #PBFORMS END INCLUDES '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Constants ** '------------------------------------------------------------------------------ #PBFORMS BEGIN CONSTANTS %IDD_CHEEZYSPLITTER = 101 %IDR_MENU1 = 102 %IDR_ACCELERATOR1 = 103 %IDM_FILE_EXIT = 104 %IDM_EDIT_NOTHING = 105 %IDT_TEXTBOXLEFT = 1001 %IDT_TEXTBOXRIGHT = 1002 %IDSB_STATUS = 1003 %IDCC_SPLITTER = 1004 #PBFORMS END CONSTANTS '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** User Constants ** '------------------------------------------------------------------------------ %SPLITPOINT = 0 %SPLITLEFT = 4 %SPLITRIGHT = 8 '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Declarations ** '------------------------------------------------------------------------------ DECLARE FUNCTION AttachMENU1(BYVAL hDlg AS DWORD) AS DWORD DECLARE FUNCTION ASSIGNACCEL(tAccel AS ACCELAPI, BYVAL wKey AS WORD, BYVAL _ wCmd AS WORD, BYVAL byFVirt AS BYTE) AS LONG DECLARE FUNCTION AttachACCELERATOR1(BYVAL hDlg AS DWORD) AS DWORD DECLARE CALLBACK FUNCTION ShowCHEEZYSPLITTERProc() DECLARE FUNCTION ShowCHEEZYSPLITTER(BYVAL hParent AS DWORD) AS LONG #PBFORMS DECLARATIONS '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Main Application Entry Point ** '------------------------------------------------------------------------------ FUNCTION PBMAIN() IF ISFALSE RegisterSplitterWindow(GetModuleHandle("")) THEN MSGBOX "Failed to register the Splitter Bar Class" ELSE PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR _ %ICC_INTERNET_CLASSES) ShowCHEEZYSPLITTER %HWND_DESKTOP END IF END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Menus ** '------------------------------------------------------------------------------ FUNCTION AttachMENU1(BYVAL hDlg AS DWORD) AS DWORD #PBFORMS BEGIN MENU %IDR_MENU1->%IDD_CHEEZYSPLITTER LOCAL hMenu AS DWORD LOCAL hPopUp1 AS DWORD MENU NEW BAR TO hMenu MENU NEW POPUP TO hPopUp1 MENU ADD POPUP, hMenu, "File", hPopUp1, %MF_ENABLED MENU ADD STRING, hPopUp1, "E&xit" + $TAB + "Alt+F4", %IDM_FILE_EXIT, _ %MF_ENABLED MENU NEW POPUP TO hPopUp1 MENU ADD POPUP, hMenu, "Edit", hPopUp1, %MF_ENABLED MENU ADD STRING, hPopUp1, "Nothing", %IDM_EDIT_NOTHING, %MF_ENABLED MENU ATTACH hMenu, hDlg #PBFORMS END MENU FUNCTION = hMenu END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Accelerators ** '------------------------------------------------------------------------------ #PBFORMS BEGIN ASSIGNACCEL FUNCTION ASSIGNACCEL(tAccel AS ACCELAPI, BYVAL wKey AS WORD, BYVAL wCmd AS _ WORD, BYVAL byFVirt AS BYTE) AS LONG tAccel.fVirt = byFVirt tAccel.key = wKey tAccel.cmd = wCmd END FUNCTION #PBFORMS END ASSIGNACCEL '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ FUNCTION AttachACCELERATOR1(BYVAL hDlg AS DWORD) AS DWORD #PBFORMS BEGIN ACCEL %IDR_ACCELERATOR1->%IDD_CHEEZYSPLITTER LOCAL hAccel AS DWORD LOCAL tAccel() AS ACCELAPI DIM tAccel(1 TO 1) AS ACCELAPI ASSIGNACCEL tAccel(1), %VK_F4, %IDM_FILE_EXIT, %FVIRTKEY OR %FALT OR _ %FNOINVERT ACCEL ATTACH hDlg, tAccel() TO hAccel #PBFORMS END ACCEL FUNCTION = hAccel END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** CallBacks ** '------------------------------------------------------------------------------ CALLBACK FUNCTION ShowCHEEZYSPLITTERProc() LOCAL FormX, FormY, FrameX, StatusX, StatusY AS DWORD LOCAL SplitPoint AS LONG LOCAL hSplitter AS DWORD SELECT CASE AS LONG CBMSG CASE %WM_INITDIALOG ' Initialization handler CASE %WM_SIZE ' Dialog has been resized CONTROL SEND CBHNDL, %IDSB_STATUS, CBMSG, CBWPARAM, CBLPARAM DIALOG GET CLIENT CB.HNDL TO FormX, FormY CONTROL HANDLE CB.HNDL, %IDCC_SPLITTER TO hSplitter ' the SplitPoint is stored as a PERCENTAGE SplitPoint = GetWindowLong(hSplitter, %SPLITPOINT) ' note setting limits in PIXELS SetWindowLong hSplitter, %SPLITLEFT, ((FormX / 100) * 20) SetWindowLong hSplitter, %SPLITRIGHT, ((FormX / 100) * 80) FrameX = ((FormX / 100) * SplitPoint) - 2 CONTROL GET SIZE CB.HNDL, %IDSB_STATUS TO StatusX, StatusY FormY = FormY - StatusY CONTROL SET LOC CB.HNDL, %IDT_TEXTBOXLEFT, 0, 0 CONTROL SET SIZE CB.HNDL, %IDT_TEXTBOXLEFT, FrameX, FormY CONTROL SET LOC CB.HNDL, %IDCC_SPLITTER, FrameX, 0 CONTROL SET SIZE CB.HNDL, %IDCC_SPLITTER, 4, FormY FrameX = FrameX + 4 FormX = FormX - FrameX CONTROL SET LOC CB.HNDL, %IDT_TEXTBOXRIGHT, FrameX, 0 CONTROL SET SIZE CB.HNDL, %IDT_TEXTBOXRIGHT, FormX, FormY CASE %WM_MENUSELECT ' Update the status bar text STATIC szMenuPrompt AS ASCIIZ * %MAX_PATH IF ISFALSE LoadString(GetModuleHandle(BYVAL 0&), CBCTL, _ szMenuPrompt, SIZEOF(szMenuPrompt)) THEN szMenuPrompt = "Please choose from the menus above..." END IF CONTROL SEND CBHNDL, %IDSB_STATUS, %SB_SETTEXT, 0, _ VARPTR(szMenuPrompt) FUNCTION = 1 CASE %WM_NCACTIVATE STATIC hWndSaveFocus AS DWORD IF ISFALSE CBWPARAM THEN ' Save control focus hWndSaveFocus = GetFocus() ELSEIF hWndSaveFocus THEN ' Restore control focus SetFocus(hWndSaveFocus) hWndSaveFocus = 0 END IF CASE %WM_COMMAND ' Process control notifications SELECT CASE AS LONG CBCTL CASE %IDM_FILE_EXIT DIALOG END CB.HNDL CASE %IDM_EDIT_NOTHING MSGBOX "%IDM_EDIT_NOTHING=" + FORMAT$(%IDM_EDIT_NOTHING), _ %MB_TASKMODAL END SELECT END SELECT END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** Dialogs ** '------------------------------------------------------------------------------ FUNCTION ShowCHEEZYSPLITTER(BYVAL hParent AS DWORD) AS LONG LOCAL lRslt AS LONG #PBFORMS BEGIN DIALOG %IDD_CHEEZYSPLITTER->%IDR_MENU1->%IDR_ACCELERATOR1 LOCAL hDlg AS DWORD DIALOG NEW PIXELS, hParent, "Cheezy Splitter", _ %CW_USEDEFAULT, %CW_USEDEFAULT, 400, 300, _ %WS_POPUP OR %WS_BORDER OR %WS_THICKFRAME OR %WS_CAPTION _ OR %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX _ OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE _ OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _ %WS_EX_CONTROLPARENT OR %WS_EX_LEFT _ OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, _ TO hDlg CONTROL ADD TEXTBOX, hDlg, %IDT_TEXTBOXLEFT, "Text Box Left", _ 8, 16, 60, 72, _ %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %WS_HSCROLL OR _ %WS_VSCROLL OR %ES_LEFT OR %ES_MULTILINE OR %ES_AUTOHSCROLL, _ %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _ %WS_EX_RIGHTSCROLLBAR CONTROL ADD TEXTBOX, hDlg, %IDT_TEXTBOXRIGHT, "Text Box Right", _ 124, 16, 56, 72, _ %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %WS_HSCROLL OR _ %WS_VSCROLL OR %ES_LEFT OR %ES_MULTILINE OR %ES_AUTOHSCROLL, _ %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _ %WS_EX_RIGHTSCROLLBAR CONTROL ADD "SPLITTERBAR", hDlg, %IDCC_SPLITTER, "Splitter", _ 76, 16, 36, 72, _ %WS_CHILD OR %WS_VISIBLE, _ %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR CONTROL ADD STATUSBAR, hDlg, %IDSB_STATUS, "Status", _ 0, 109, 201, 12, _ %WS_CHILD OR %WS_VISIBLE, %WS_EX_TRANSPARENT OR %WS_EX_LEFT _ OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR AttachMENU1 hDlg AttachACCELERATOR1 hDlg #PBFORMS END DIALOG DIALOG SHOW MODAL hDlg, CALL ShowCHEEZYSPLITTERProc TO lRslt #PBFORMS BEGIN CLEANUP %IDD_CHEEZYSPLITTER #PBFORMS END CLEANUP FUNCTION = lRslt END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** register my splitterbar class '------------------------------------------------------------------------------ FUNCTION RegisterSplitterWindow(hInstance AS DWORD) AS LONG LOCAL wc AS WndClassEx LOCAL szClassName AS ASCIIZ * 80 szClassName = "SPLITTERBAR" wc.cbSize = SIZEOF(wc) wc.cbClsExtra = 0 wc.cbWndExtra = 12 wc.hbrBackground = GetStockObject(%BLACK_BRUSH) wc.hCursor = LoadCursor(%NULL, BYVAL %IDC_SIZEWE) wc.hIcon = 0 wc.hIconSm = 0 wc.hInstance = GetModuleHandle("") wc.lpfnWndProc = CODEPTR(SplitterBarProc) wc.lpszClassName = VARPTR(szClassName) wc.lpszMenuName = %NULL wc.style = 0 ' %CS_HREDRAW OR %CS_VREDRAW RegisterSplitterWindow = RegisterClassEx(wc) END FUNCTION '------------------------------------------------------------------------------ '------------------------------------------------------------------------------ ' ** cheezy splitter bar window procedure '------------------------------------------------------------------------------ FUNCTION SplitterBarProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, _ BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG LOCAL winPlace AS WINDOWPLACEMENT LOCAL winDC, pWnd, sPoint AS DWORD LOCAL mRect AS RECT ' the offsets and rectangle need to be statics STATIC winRect AS RECT STATIC winOffsets AS POINTAPI SELECT CASE wMsg CASE %WM_CREATE ' note the SplitPoint is a PERCENTAGE SetWindowLong hWnd, %SPLITPOINT, 50 CASE %WM_MOUSEMOVE IF (wParam AND %MK_LBUTTON) = %MK_LBUTTON THEN ' get the parent information and clear the prior focus rectangle pWnd = GetParent(hWnd) winDC = GetWindowDC(pWnd) DrawFocusRect winDC, winRect ' get our position winPlace.Length = SIZEOF(winPlace) GetWindowPlacement hWnd, winPlace ' do calculations to the new position of the splitter mRect = winPlace.rcNormalPosition OffsetRect mRect, LO(INTEGER, lParam), 0 ' note that the main resize sets these as PIXELS IF (mRect.nLeft > GetWindowLong(hWnd, %SPLITLEFT)) _ AND (mRect.nLeft < GetWindowLong(hWnd, %SPLITRIGHT)) THEN winRect = mRect OffsetRect winRect, winOffsets.x, winOffsets.y GetClientRect pWnd, mRect ' winPlace.rcNormalPosition.nLeft contains upper left of splitter sPoint = winPlace.rcNormalPosition.nLeft + LO(INTEGER, lParam) ' sPoint now is relative to original position sPoint = CSNG(sPoint / mRect.nRight) * 100 SetWindowLong hWnd, %SPLITPOINT, sPoint END IF DrawFocusRect winDC, winRect ReleaseDC pWnd, winDC ' PostMessage pWnd, %WM_SIZE, 0, 0 END IF CASE %WM_LBUTTONDOWN ' cheat, clear the original offsets winOffsets = winPlace.ptMinPosition ' get the location of the splitter in the parents client area winPlace.Length = SIZEOF(winPlace) GetWindowPlacement hWnd, winPlace winRect = winPlace.rcNormalPosition ' have our position, get the parent's position on the screen pWnd = GetParent(hWnd) GetWindowRect pWnd, mRect ' this converts the clients' upper left corner into a screen position ClientToScreen pWnd, winOffsets ' do the math to adjust from window upper left to client upper left winOffsets.x = winOffsets.x - mRect.nLeft winOffsets.y = winOffsets.y - mRect.nTop OffsetRect winRect, winOffsets.x, winOffsets.y ' note we are getting the WINDOW DC, not the CLIENT DC winDC = GetWindowDC(pWnd) DrawFocusRect winDC, winRect ReleaseDC pWnd, winDC ' and capture the mouse SetCapture hWnd CASE %WM_LBUTTONUP ' clear the focus rectangle and inform parent that we're done pWnd = GetParent(hWnd) winDC = GetWindowDC(pWnd) DrawFocusRect winDC, winRect ReleaseDC pWnd, winDC ReleaseCapture PostMessage pWnd, %WM_SIZE, 0, 0 END SELECT SplitterBarProc = DefWindowProc(hWnd, wMsg, wParam, lParam) END FUNCTION '------------------------------------------------------------------------------
Comment