xresizable.cpp
来自「Visual_C++[1].NET_Bible1 Visual_C++宝典书中」· C++ 代码 · 共 322 行
CPP
322 行
// XResizable.cpp : implementation file
//
#include "stdafx.h"
#include "XResizable.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// a helper function for calculating proportions
static int MulDiv3(int x,int now,int was,int ini) {
return ::MulDiv(::MulDiv(x,ini,was),now,ini);
}
void CXResizable::ResizeControls() {
// if not resizable, then don't bother
if (! IsResizable()) return;
// get the original, old and new sizes
SResizeInfo resizeInfo;
CRect rcWas;
GetClientRectWas(rcWas);
CRect rcNow;
GetClientRectNow(rcNow);
CRect rcIni;
GetClientRectIni(rcIni);
// has it changed?
if (! rcWas.IsRectEmpty() && ! rcNow.IsRectEmpty() && rcWas != rcNow) {
// first lets count the child controls so we can
// preallocatethe DeferWindowPos
int n = 0;
HWND hwnd = CWnd_GetSafeHwnd();
::EnumChildWindows(hwnd,EnumChildProc_CountControls,reinterpret_cast<LPARAM>(&n));
// pack up the info we need into a struct
// that we pass to the callback
resizeInfo.szNow = rcNow.Size();
resizeInfo.szWas = rcWas.Size();
resizeInfo.szIni = rcIni.Size();
resizeInfo.pResizable = this;
// we defer the movement of controls until after we've worked out all the new sizes
resizeInfo.defer = ::BeginDeferWindowPos(n);
ASSERT(resizeInfo.defer);
// resize all the child controls
::EnumChildWindows(hwnd,EnumChildProc_ResizeControls,reinterpret_cast<LPARAM>(&resizeInfo));
ASSERT(resizeInfo.defer);
// do all the deferred sizing now
VERIFY(::EndDeferWindowPos(resizeInfo.defer));
(*this)->Invalidate();
}
}
BOOL CALLBACK CXResizable::EnumChildProc_CountControls(HWND /*hwnd*/, LPARAM lParam) {
// just bump up the counter
int* pCount = reinterpret_cast<int*>(lParam);
(*pCount)++;
return TRUE;
}
BOOL CALLBACK CXResizable::EnumChildProc_ResizeControls(HWND hwnd, LPARAM lParam) {
// the lparam is a pointer to struct that
// contains the info we need
SResizeInfo* pResizeInfo = reinterpret_cast<SResizeInfo*>(lParam);
// the wndow must be valid
if (hwnd && ::IsWindow(hwnd)) {
// get a CWnd* for the hwnd (for convenience)
CWnd* pControl = CWnd::FromHandle(hwnd);
// and find out the id number of the control
int id = pControl->GetDlgCtrlID();
// only resize if the id number is valid
if (id) {
// we are inside a static function, so there
// is not this pointer. Instead we pass the
// this pointer in with the struct, so
// pResizeable will point to the TXResizable
// dialog/page that called us
CXResizable* pResizable = pResizeInfo->pResizable;
// get the sizes we need including the
// current window rectangle for the control
// (in client coordinates)
CSize szNow = pResizeInfo->szNow;
CSize szWas = pResizeInfo->szWas;
CSize szIni = pResizeInfo->szIni;
CSize szDelta = szNow - szWas;
CRect rcControl;
pControl->GetWindowRect(rcControl);
CRect rcControlwas(rcControl);
pResizable->CWnd_ScreenToClient(rcControl);
// now resize the of the control
pResizable->ResizeControl(id,pControl,rcControl, szNow,szWas,szIni,szDelta);
// if the size or position has changed
if (rcControl != rcControlwas) {
// defer the repositioning until later
// we use NOCOPYBITS so that transparent
// controls like static will resize properly
pResizeInfo->defer = ::DeferWindowPos(
pResizeInfo->defer,
(*pControl),NULL,
rcControl.left,rcControl.top,rcControl.Width(),rcControl.Height(),
SWP_DRAWFRAME|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOREPOSITION|SWP_NOZORDER
);
ASSERT(pResizeInfo->defer);
}
}
}
return TRUE;
}
void CXResizable::ResizeControl(UINT id,CWnd* pControl,CRect& rcControl, const CSize& szNow, const CSize& szWas, const CSize& szIni, const CSize& szDelta) {
// bydefault we use the resize flags to resize
// we can override this to use other methods if required
ResizeControlUsingFlags(id,pControl,rcControl, szNow,szWas,szIni,szDelta);
}
void CXResizable::ResizeControlUsingFlags(UINT id,CWnd* pControl,CRect& rcControl, const CSize& szNow, const CSize& szWas, const CSize& szIni, const CSize& szDelta) {
// first lets ask for the appropriate flag for this control
UINT nFlags = GetResizeFlags(id,pControl,rcControl, szNow,szWas,szIni,szDelta);
// now adjust the retangle accordingly
if (nFlags != RESIZE_NONE) {
{
int l = rcControl.left;
int r = rcControl.right;
int c = (l+r+1)/2;
int dlprop = ::MulDiv3(l,szNow.cx,szWas.cx,szIni.cx)-l;
int drprop = ::MulDiv3(r,szNow.cx,szWas.cx,szIni.cx)-r;
int dcprop = ::MulDiv3(c,szNow.cx,szWas.cx,szIni.cx)-c;
int dfull = szDelta.cx;
switch (nFlags & RESIZE_LEFT_FLAGS) {
case RESIZE_LEFT_LFIX:
break;
case RESIZE_LEFT_LPROP:
rcControl.left += dlprop;
break;
case RESIZE_LEFT_RPROP:
rcControl.left += drprop;
break;
case RESIZE_LEFT_CPROP:
rcControl.left += dcprop;
break;
case RESIZE_LEFT_RFIX:
rcControl.left += dfull;
break;
}
switch (nFlags & RESIZE_RIGHT_FLAGS) {
case RESIZE_RIGHT_LFIX:
break;
case RESIZE_RIGHT_LPROP:
rcControl.right += dlprop;
break;
case RESIZE_RIGHT_RPROP:
rcControl.right += drprop;
break;
case RESIZE_RIGHT_CPROP:
rcControl.right += dcprop;
break;
case RESIZE_RIGHT_RFIX:
rcControl.right += dfull;
break;
}
}
{
int t = rcControl.top;
int b = rcControl.bottom;
int c = (t+b+1)/2;
int dtprop = ::MulDiv3(t,szNow.cy,szWas.cy,szIni.cy)-t;
int dbprop = ::MulDiv3(b,szNow.cy,szWas.cy,szIni.cy)-b;
int dcprop = ::MulDiv3(c,szNow.cy,szWas.cy,szIni.cy)-c;
int dfull = szDelta.cy;
switch (nFlags & RESIZE_TOP_FLAGS) {
case RESIZE_TOP_TFIX:
break;
case RESIZE_TOP_TPROP:
rcControl.top += dtprop;
break;
case RESIZE_TOP_BPROP:
rcControl.top += dbprop;
break;
case RESIZE_TOP_CPROP:
rcControl.top += dcprop;
break;
case RESIZE_TOP_BFIX:
rcControl.top += dfull;
break;
}
switch (nFlags & RESIZE_BOTTOM_FLAGS) {
case RESIZE_BOTTOM_TFIX:
break;
case RESIZE_BOTTOM_TPROP:
rcControl.bottom += dtprop;
break;
case RESIZE_BOTTOM_BPROP:
rcControl.bottom += dbprop;
break;
case RESIZE_BOTTOM_CPROP:
rcControl.bottom += dcprop;
break;
case RESIZE_BOTTOM_BFIX:
rcControl.bottom += dfull;
break;
}
}
}
}
UINT CXResizable::GetResizeFlags(UINT id,CWnd* pControl,CRect& rcControl, const CSize& szNow, const CSize& szWas, const CSize& szIni, const CSize& szDelta) {
// by default we will use the smart resize method to
// automatically calculate an appropriate resize flag
return GetSmartResizeFlags(id,pControl,rcControl, szNow,szWas,szIni,szDelta);
}
UINT CXResizable::GetSmartResizeFlags(UINT /*id*/,CWnd* pControl,CRect& rcControl, const CSize& /*szNow*/, const CSize& szWas, const CSize& /*szIni*/, const CSize& /*szDelta*/) {
// not very smart in this implementation
return RESIZE_NONE;
}
void CXResizable::GetGripperRect(CRect& rcGripper) {
// the gripper is at the bottom right and is
// the same size asa scroll bar
GetClientRectNow(rcGripper);
rcGripper.left = rcGripper.right - ::GetSystemMetrics(SM_CXVSCROLL);
rcGripper.top = rcGripper.bottom - ::GetSystemMetrics(SM_CYVSCROLL);
}
void CXResizable::DrawGripper(CDC* pDC) {
// draw the gripper in the appropriate position
CRect rcGripper;
GetGripperRect(rcGripper);
pDC->DrawFrameControl(rcGripper, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
}
bool CXResizable::IsResizable() const {
// is this dialog/page resizeable?
bool bResizable = true;
if (::IsWindow(CWnd_GetSafeHwnd())) {
// only if it doesn't have a modal frame
bResizable = ((*this)->GetStyle() & DS_MODALFRAME) != DS_MODALFRAME;
}
return bResizable;
}
bool CXResizable::IsResizeDirectly() const {
// property pages cannot be sized directly
// (the property sheet will resize them instead)
bool bIsDialog = (*this)->IsKindOf(RUNTIME_CLASS(CDialog));
bool bIsPropertyPage = (*this)->IsKindOf(RUNTIME_CLASS(CPropertyPage));
return bIsDialog && ! bIsPropertyPage;
}
void CXResizable::OnSize(UINT /*nType*/, int /*cx*/, int /*cy*/) {
if (::IsWindow(CWnd_GetSafeHwnd())) {
CRect rc, rw;
(*this)->GetClientRect(rc);
(*this)->GetWindowRect(rw);
// do we have a valid rectangle?
if (! rc.IsRectEmpty()) {
// copy the previous rectangle into m_rcWas
// if there was one .. otherwise just set it
if (m_rcNow.IsRectEmpty()) {
m_rcWas = rc;
m_rwWas = rw;
} else {
m_rcWas = m_rcNow;
m_rwWas = m_rwNow;
}
m_rcNow = rc;
m_rwNow = rw;
// if we haven't already set up the initial
// rectnagle, do it now
if (m_rcIni.IsRectEmpty()) {
m_rcIni = rc;
m_rwIni = rw;
}
// if the size has changed, resize ourselves
if (m_rcNow != m_rcWas) {
ResizeControls();
}
}
}
}
UINT CXResizable::OnNcHitTest(CPoint point) {
if (::IsWindow(CWnd_GetSafeHwnd()) && IsResizeDirectly()) {
if (IsResizable() && ! (*this)->IsZoomed()) {
// check for a hit in the gripper
CPoint pointScreen = point;
CWnd_ScreenToClient(&pointScreen);
CRect rcGripper;
GetGripperRect(rcGripper);
if (rcGripper.PtInRect(pointScreen)) {
return HTBOTTOMRIGHT;
}
}
}
return HTNOWHERE;
}
bool CXResizable::OnPaint() {
if (::IsWindow(CWnd_GetSafeHwnd()) && IsResizable()) {
CPaintDC dc(*this); // device context for painting
CRect rc;
GetClientRectNow(rc);
dc.FillSolidRect(rc,::GetSysColor(COLOR_3DFACE));
// draw the gripper if required
if (IsResizeDirectly() && ! (*this)->IsZoomed()) {
DrawGripper(&dc);
return true;
}
}
return false;
}
void CXResizable::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) {
if (::IsWindow(CWnd_GetSafeHwnd())) {
// the smallest size is the original dialog/page size
CRect rw;
GetWindowRectIni(rw);
lpMMI->ptMinTrackSize.x = rw.Width();
lpMMI->ptMinTrackSize.y = rw.Height();
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?