Newsgroup: it.comp.programmare.win32
Titolo: Come si crea una "Split Bar" ?

Salve a tutti,
avrei bisogno di creare una Splitting View composta da due panes, ma
sbirciando tra le pagine di MSDN mi sono accorto che non esiste un controllo
apposito per creare le cosidette "Split Bar". Ci sono tuttavia delle classi
MFC che permettono di agevolare la procedura di creazione "manuale". Io però
vorrei sapere se esiste una qualche metodologia standard per creare queste
barre che non faccia uso delle MFC ovvero utilizzando solo le Win32 API.
Sarò grato a chiunque sia in grado di fornirmi un link, un frammento di
codice, o anche una semplice spiegazione.
Ciao.



La split bar e' "semplicemente" la porzione di window sottostante due
altre windows. Mi spiego meglio: prendi una window, questa sara' il
contenitore di due windows posizionate vicine in modo tale la distanza
tra i bordi delle due sia percepita come split bar.
Chiaramamente la window sottostante dovra' gestire il posizionamento
delle due figlie oltre che visualizzare la barra di spostamento.
Girando in rete in rete ho trovato vari esempi, ne ho preso uno che ho
convertito in una semplice classe che ti puo' servire come base per il
tuo codice, ti posto qui il codice (purtroppo l'indentazione con le
tabulazioni e' tutta sballata) usando solo le Win32 API:
splitter.h
splitter.cpp
main.cpp (esempio di uso)
Ciao
Stefano
/******************** splitter.h
#define STRICT
#include <stdio.h>
#include <string.h>
#include <windows.h>
#ifndef SPLITTER_CLASS
#define SPLITTER_CLASS
#define SP_RIGHT  0
#define SP_LEFT   1
#define SP_TOP    2
#define SP_BOTTOM 3
#define SP_HORIZ  4
#define SP_VERT   5
class Splitter
{
	private:
   	HWND hwnd;
      HWND hTop,hBottom,hLeft,hRight;
		int nSplitterPos;
		int nSplitterBorder;
		int  oldx,oldy;
		BOOL fMoved;
		BOOL fDragMode;
		void DrawXorBar(HDC,int,int,int,int);
		static long WINAPI
SplitterWndProc(HWND,UINT,WPARAM,LPARAM);
   public:
      int SplitterType;
      Splitter(void);
      void CreateSplitter(HWND,int);
      void AddControl(HWND,int);
		LRESULT OnLButtonDown(HWND,UINT,WPARAM,LPARAM);
		LRESULT OnLButtonUp(HWND,UINT,WPARAM,LPARAM);
		LRESULT OnMouseMove(HWND,UINT,WPARAM,LPARAM);
      void Resize(int,int);
      void SetPos(int);
      void SizeWindows(int,int);
};
#endif
/************* splitter.cpp
#include "splitter.h"
Splitter::Splitter(void)
{
	nSplitterPos=0;
   nSplitterBorder=2;
   oldy=-4;
}
void Splitter::AddControl(HWND hCtrl,int type)
{
	switch (type)
   {
   	case SP_TOP:
      	hTop=hCtrl;
      	break;
      case SP_BOTTOM:
      	hBottom=hCtrl;
         break;
      case SP_LEFT:
      	hLeft=hCtrl;
         break;
      case SP_RIGHT:
      	hRight=hCtrl;
         break;
   }
   SetWindowPos(hwnd,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}
void Splitter::CreateSplitter(HWND hParent,int type)
{
	HINSTANCE hInst;
   WNDCLASS wclass;
   SplitterType=type;
	hInst=(HINSTANCE)GetWindowLong(hParent,GWL_HINSTANCE);
	if (!GetClassInfo(hInst,"Splitter",&wclass))
	{
		wclass.style         = 0;
		wclass.lpfnWndProc   = (WNDPROC)SplitterWndProc;
		wclass.cbClsExtra    = 0;
		wclass.cbWndExtra    = 0;
		wclass.hInstance		= hInst;
		wclass.hIcon			= 0;
      if (type==SP_VERT)
			wclass.hCursor       =
LoadCursor(NULL,IDC_SIZEWE);
      else
	      wclass.hCursor       = LoadCursor(NULL,IDC_SIZENS);
		wclass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
		wclass.lpszMenuName  = 0;
		wclass.lpszClassName = "Splitter";
		RegisterClass(&wclass);
   }
   RECT r;
   GetClientRect(hParent,&r);
	hwnd =
CreateWindow("Splitter","",WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_VISIBLE|WS_CHILD,0,0,r.right,r.bottom,hParent,(HMENU)10,hInst,this);
}
void Splitter::DrawXorBar(HDC hdc, int x1, int y1, int width, int
height)
{
	static WORD _dotPatternBmp[8] =
	{
		0x00aa, 0x0055, 0x00aa, 0x0055,
		0x00aa, 0x0055, 0x00aa, 0x0055
	};
   y1=y1+24;
	HBITMAP hbm;
	HBRUSH  hbr, hbrushOld;
	hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
	hbr = CreatePatternBrush(hbm);
	SetBrushOrgEx(hdc, x1, y1, 0);
	hbrushOld = (HBRUSH)SelectObject(hdc, hbr);
	PatBlt(hdc, x1, y1, width, height, PATINVERT);
	SelectObject(hdc, hbrushOld);
	DeleteObject(hbr);
	DeleteObject(hbm);
}
#pragma argsused
LRESULT Splitter::OnLButtonDown(HWND hwnd, UINT iMsg, WPARAM wParam,
LPARAM lParam)
{
	POINT pt;
	HDC hdc;
	RECT rect;
	pt.x = (short)LOWORD(lParam);  // horizontal position of
cursor
	pt.y = (short)HIWORD(lParam);
	GetWindowRect(hwnd, &rect);
	//convert the mouse coordinates relative to the top-left of
	//the window
	ClientToScreen(hwnd, &pt);
	pt.x -= rect.left;
	pt.y -= rect.top;
	//same for the window coordinates - make them relative to 0,0
	OffsetRect(&rect, -rect.left, -rect.top);
	if (pt.y < 0)
   	pt.y = 0;
	if (pt.y > rect.bottom-4)
		pt.y = rect.bottom-4;
   if (pt.x < 0)
   	pt.x = 0;
   if (pt.x > rect.right-4)
   	pt.x = rect.right-4;
	fDragMode = TRUE;
	SetCapture(hwnd);
	hdc = GetWindowDC(GetParent(hwnd));
   if (SplitterType==SP_HORIZ)
   {
		DrawXorBar(hdc, 1, pt.y - 2, rect.right-2,4);
      oldy = pt.y;
   }
   else
   {
		DrawXorBar(hdc, pt.x, 1, 4,rect.bottom-2);
      oldx = pt.x;
   }
	ReleaseDC(hwnd, hdc);
	return 0;
}
#pragma argsused
LRESULT Splitter::OnLButtonUp(HWND hwnd, UINT iMsg, WPARAM wParam,
LPARAM lParam)
{
	HDC hdc;
	RECT rect;
	POINT pt;
	pt.x = (short)LOWORD(lParam);  // horizontal position of
cursor
	pt.y = (short)HIWORD(lParam);
	if(fDragMode == FALSE)
		return 0;
	GetWindowRect(hwnd, &rect);
	ClientToScreen(hwnd, &pt);
	pt.x -= rect.left;
	pt.y -= rect.top;
	OffsetRect(&rect, -rect.left, -rect.top);
	if (pt.y < 0)
   	pt.y = 0;
	if(pt.y > rect.bottom-4)
		pt.y = rect.bottom-4;
   if (pt.x < 0)
   	pt.x = 0;
   if (pt.x > rect.right-4)
   	pt.x = rect.right-4;
	hdc = GetWindowDC(GetParent(hwnd));
   if (SplitterType==SP_HORIZ)
		DrawXorBar(hdc, 1,oldy - 2, rect.right-2,4);
   else
		DrawXorBar(hdc, pt.x , 1, 4,rect.bottom-2);
	ReleaseDC(hwnd, hdc);
	oldy = pt.y;
	fDragMode = FALSE;
	//convert the splitter position back to screen coords.
	GetWindowRect(hwnd, &rect);
	pt.x += rect.left;
	pt.y += rect.top;
	//now convert into CLIENT coordinates
	ScreenToClient(hwnd, &pt);
	GetClientRect(hwnd, &rect);
   if (SplitterType==SP_HORIZ)
		nSplitterPos = pt.y;
   else
		nSplitterPos = pt.x;
	//position the child controls
	SizeWindows(rect.right,rect.bottom);
	ReleaseCapture();
	return 0;
}
#pragma argsused
LRESULT Splitter::OnMouseMove(HWND hwnd, UINT iMsg, WPARAM wParam,
LPARAM lParam)
{
	HDC hdc;
	RECT rect;
	POINT pt;
	if (fDragMode == FALSE)
      return 0;
	pt.x = (short)LOWORD(lParam);  // horizontal position of
cursor
	pt.y = (short)HIWORD(lParam);
	GetWindowRect(hwnd, &rect);
	ClientToScreen(hwnd, &pt);
	pt.x -= rect.left;
	pt.y -= rect.top;
	OffsetRect(&rect, -rect.left, -rect.top);
	if (pt.y < 0)
      pt.y = 0;
	if (pt.y > rect.bottom-4)
		pt.y = rect.bottom-4;
   if (pt.x < 0)
   	pt.x = 0;
   if (pt.x > rect.right-4)
		pt.x = rect.right-4;
   if (SplitterType==SP_HORIZ)
   {
		if (pt.y != oldy && wParam & MK_LBUTTON)
		{
			hdc = GetWindowDC(GetParent(hwnd));
			DrawXorBar(hdc, 1,oldy - 2, rect.right-2,4);
			DrawXorBar(hdc, 1,pt.y - 2, rect.right-2,4);
			ReleaseDC(hwnd, hdc);
			oldy = pt.y;
		}
   }
   else
   {
		if (pt.x != oldx && wParam & MK_LBUTTON)
      {
			hdc = GetWindowDC(GetParent(hwnd));
			DrawXorBar(hdc, oldx ,1, 4, rect.bottom-2);
			DrawXorBar(hdc, pt.x ,1, 4, rect.bottom-2);
			ReleaseDC(hwnd, hdc);
      	oldx = pt.x;
      }
   }
	return 0;
}
void Splitter::Resize(int w,int h)
{
	MoveWindow(hwnd,0,0,w,h,TRUE);
}
void Splitter::SetPos(int p)
{
	RECT r;
	nSplitterPos=p;
   GetClientRect(GetParent(hwnd),&r);
   SizeWindows(r.right,r.bottom);
}
void Splitter::SizeWindows(int nWidth, int nHeight)
{
	if (SplitterType==SP_HORIZ)
   {
		MoveWindow(hTop,0,0,nWidth,nSplitterPos,TRUE);
MoveWindow(hBottom,0,nSplitterPos+nSplitterBorder,nWidth,nHeight-nSplitterPos-nSplitterBorder,TRUE);
   }
   else
   {
		MoveWindow(hLeft,0,0,nSplitterPos,nHeight,TRUE);
MoveWindow(hRight,nSplitterPos+nSplitterBorder,0,nWidth-nSplitterPos-nSplitterBorder,nHeight,TRUE);
   }
}
long WINAPI Splitter::SplitterWndProc(HWND hwnd,UINT msg,WPARAM
wParam,LPARAM lParam)
{
	Splitter *p;
	// Prelevo il puntatore all'oggetto a cui è associata la
finestra
	p=(Splitter*)GetWindowLong(hwnd,GWL_USERDATA);
	if (!p && msg!=WM_CREATE)	// Finestra non ancora
inizializzata
		return(DefWindowProc(hwnd,msg,wParam,lParam));
	switch (msg)
	{
		case WM_CREATE:
			// Registro nella memoria aggiuntiva di ogni
finestra il puntatore
			// all'oggetto a cui è associata
         LPCREATESTRUCT lpcs;
			lpcs=(LPCREATESTRUCT)lParam;
			p=(Splitter*)lpcs->lpCreateParams;
			SetWindowLong(hwnd,GWL_USERDATA,(LONG)p);
			return 0;
      case WM_SIZE:
      	p->SizeWindows(LOWORD(lParam),HIWORD(lParam));
         return 0;
		case WM_LBUTTONDOWN:
			p->OnLButtonDown(hwnd,msg,wParam,lParam);
			return 0;
		case WM_LBUTTONUP:
			p->OnLButtonUp(hwnd, msg, wParam, lParam);
			return 0;
		case WM_MOUSEMOVE:
			p->OnMouseMove(hwnd, msg, wParam, lParam);
			return 0;
	}
   return(DefWindowProc(hwnd,msg,wParam,lParam));
}
/****** main.cpp
#define STRICT
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include "splitter.h"
Splitter splitter;
long WINAPI MainWndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM
lparam)
{
   HWND hwndChild1,hwndChild2;
   HINSTANCE hInst;
	switch (message)
	{
		case WM_CREATE:
      	hInst=(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
			hwndChild1 =
CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","",WS_VISIBLE|WS_CHILD|ES_MULTILINE,0,0,0,0,hwnd,(HMENU)1,hInst,0);
			hwndChild2 =
CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","",WS_VISIBLE|WS_CHILD|ES_MULTILINE,0,0,0,0,hwnd,(HMENU)2,hInst,
0);
//      	splitter.CreateSplitter(hwnd,SP_HORIZ);
//       splitter.AddControl(hwndChild1,SP_TOP);
//       splitter.AddControl(hwndChild2,SP_BOTTOM);
      	splitter.CreateSplitter(hwnd,SP_VERT);
         splitter.AddControl(hwndChild1,SP_LEFT);
         splitter.AddControl(hwndChild2,SP_RIGHT);
         splitter.SetPos(250);
			return(0);
      case WM_SIZE:
      	splitter.Resize(LOWORD(lparam),HIWORD(lparam));
         break;
		case WM_DESTROY:
			PostQuitMessage(0);
			return(0);
	}
	return(DefWindowProc(hwnd,message,wparam,lparam));
}
#pragma argsused
int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
						 LPSTR lpszCmdParam,
int nCmdShow)
{
	static char szAppName[]="empty";
	HWND hwnd;
	MSG  msg;
	WNDCLASS wclass;
	if (!hPrevInstance)
	{
		wclass.style         = CS_HREDRAW|CS_VREDRAW;
		wclass.lpfnWndProc   = (WNDPROC)MainWndProc;
		wclass.cbClsExtra    = 0;
		wclass.cbWndExtra    = 0;
		wclass.hInstance		= hInstance;
		wclass.hIcon			=
LoadIcon(NULL,IDI_APPLICATION);
		wclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
		wclass.hbrBackground =
(HBRUSH)GetStockObject(WHITE_BRUSH);
		wclass.lpszMenuName  = NULL;
		wclass.lpszClassName = szAppName;
		RegisterClass(&wclass);
	}
hwnd=CreateWindow(szAppName,"Splitter",WS_OVERLAPPEDWINDOW,100,100,400,200,NULL,NULL,hInstance,NULL);
	ShowWindow(hwnd,nCmdShow);
	UpdateWindow(hwnd);
	while (GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return(msg.wParam);
}
Stefano "HappyMan" (Lago Maggiore - NO)
--
Personal Web 
http://www.sgr.info
Email happyman69 (at) 
libero.it

Sei un grande!!! Non potevo desiderare di meglio :D