Arial Century Courier Georgia Tahoma Verdana Times New Roman
-
+
void Controller::Size (int cx, int cy) {
_cx = cx;
_cy = cy;
int xSplit = (_cx * _splitRatio) / 100;
if (xSplit < 0) xSplit = 0;
if (xSplit + splitWidth >= _cx) xSplit = _cx - splitWidth;
_splitter.MoveDelayPaint(xSplit, 0, splitWidth, cy);
_leftWin.Move(0, 0, xSplit, cy);
_rightWin.Move(xSplit+splitWidth, 0, cx-xSplit-splitWidth, cy);
_splitter.ForceRepaint ;
}
Обратите
внимание на используемый здесь важный прием. Мы перемещаем расщепитель, но задерживаем его перерисовку до изменения его обоих подокон, расположенных слева и справа. Эта методика устраняет некоторое неприятное смазывание изображения.
Выше была представлена реализация клиентского кода. Теперь, я надеюсь, Вам будет интересно увидеть реализацию сплиттера.
Прежде всего нам приятно объединить зависимые функции в пространство имен. Вам видны вызовы Splitter::RegisterClass и Splitter::MakeWindow. Splitter в этих именах — это namespace.
namespace Splitter {
void RegisterClass (HINSTANCE hInst);
void MakeWindow (HWnd& hwndSplitter /* out */, HWnd hwndParent, int childId);
};
Ниже приводится реализация этих функций.
LRESULT CALLBACK WndProcSplitter(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
void Splitter::RegisterClass (HINSTANCE hInst) {
WinClassMaker splitterClass(WndProcSplitter, "RsSplitterClass", hInst);
splitterClass.SetSysCursor(IDC_SIZEWE);
splitterClass.SetBgSysColor(COLOR_3DFACE);
splitterClass.Register;
}
void Splitter::MakeWindow (HWnd& hwndSplitter, HWnd hwndParent, int childId) {
ChildWinMaker splitterMaker("RsSplitterClass", hwndParent, childId);
splitterMaker.Create; hwndSplitter.Init(splitterMaker);
splitterMaker.Show;
}
Курсор мыши IDC_SIZEWE мы связываем с классом расщепителя — это стандартная, «направленная с запада на восток», двунаправленная стрелка. Мы также устанавливаем фоновую кисть к COLOR_3DFACE.
Оконная процедура расщепителя имеет дело с созданием/разрушением расщепителя, прорисовкой и перемещением мыши.
LRESULT CALLBACK WndProcSplitter(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
SplitController* pCtrl = GetWinLong<SplitController*>(hwnd);
switch (message) {
case WM_CREATE:
try {
pCtrl = new SplitController(hwnd, reinterpret_cast<CREATESTRUCT *>(lParam));
SetWinLong<SplitController*>(hwnd, pCtrl);
} catch (char const * msg) {
MessageBox(hwnd, msg, "Initialization", MB_ICONEXCLAMATION | MB_OK);
return -1;
} catch (...) {
MessageBox(hwnd, "Unknown Error", "Initialization", MB_ICONEXCLAMATION | MB_OK);
return -1;
}
return 0;
case WM_SIZE:
pCtrl->Size(LOWORD(lParam), HIWORD(lParam));
return 0;
case WM_PAINT:
pCtrl->Paint;
return 0;
case WM_LBUTTONDOWN:
pCtrl->LButtonDown(MAKEPOINTS(lParam));
return 0;
case WM_LBUTTONUP:
pCtrl->LButtonUp(MAKEPOINTS(lParam));
return 0;
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON) pCtrl->LButtonDrag(MAKEPOINTS(lParam));
return 0;
case WM_CAPTURECHANGED:
pCtrl->CaptureChanged;
return 0;
case WM_DESTROY:
SetWinLong<SplitController*>(hwnd, 0);
delete pCtrl;
return 0;
}
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
Это,
в значительной степени, стандартный код. Подробности, как обычно, находятся в методах контроллера. Конструктор очень прост.
SplitController::SplitController(HWND hwnd, CREATESTRUCT * pCreat) : _hwnd (hwnd), _hwndParent (pCreat->hwndParent) {}
Прорисовка более интересна. Мы должны имитировать эффекты 2.5-размерности Windows. Мы делаем это путем тщательного отбора перьев.
class Pens3d {
public:
Pens3d;
Pen& Hilight { return _penHilight; }
Pen& Light { return _penLight; }
Pen& Shadow { return _penShadow; }
Pen& DkShadow { return _penDkShadow; }
private:
Pen _penHilight;
Pen _penLight;
Pen _penShadow;
Pen _penDkShadow;
};
Pens3d::Pens3d : _penLight(GetSysColor (COLOR_3DLIGHT)), _penHilight(GetSysColor (COLOR_3DHILIGHT)), _penShadow(GetSysColor (COLOR_3DSHADOW)), _penDkShadow(GetSysColor (COLOR_3DDKSHADOW)) {}
void SplitController::Paint {