📄 tanchors.cpp
字号:
/*****************************************************************************/
/* TAnchors.cpp Copyright Ladislav Zezula 2001 */
/*---------------------------------------------------------------------------*/
/* A class for easy object anchoring. Those who compare the Delphi program- */
/* ming with Visual C++, will certainly miss the "Anchors" property in visual*/
/* design. This class supports something like that, although it's not so */
/* comfort like the visual design in Delphi/C++ Builder */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- -----------------------------------------------------*/
/* 19.12.01 1.00 Lad Created */
/* 21.12.01 1.01 Lad Added TRACE outputs for debug support */
/* 28.12.01 1.02 Lad Added the __USE_FAST_REDRAW__ flag */
/* 09.01.01 1.02 Lad Fixed ugly effect caused by the group boxes. */
/* 15.07.03 1.03 Lad Added method using DeferWindowPos */
/*****************************************************************************/
#include <tchar.h>
#include <windows.h>
#include <winuser.h>
#include <commctrl.h>
#include "TAnchors.h"
// Choose one flag only !!!
//#define __USE_SET_WINDOW_POS__ // Redraws the windows using SetWindowPos + WS_CLIPCHILDREN
#define __USE_DEFER_WINDOW_POS__ // Redraws windows using DeferWindowPos
//#define __USE_FAST_REDRAW__ // Redraws windows using double buffering
//-----------------------------------------------------------------------------
// Constructor and destructor
TAnchors::TAnchors()
{
// Initialize anchors to NULL
m_pFirstAnchor = NULL;
}
TAnchors::~TAnchors()
{
TAnchor * pAnchor = m_pFirstAnchor;
TAnchor * temp;
// Free all used anchors
while(pAnchor != NULL)
{
temp = pAnchor->next;
delete pAnchor;
pAnchor = temp;
}
}
//-----------------------------------------------------------------------------
// Public functions
// This function adds the anchors for an object into the list of anchors.
// Later when the window will be resized, the anchors will be applied.
BOOL TAnchors::AddAnchor(HWND hWnd, DWORD dwAnchors)
{
TAnchor * newAnchor;
TAnchor * lastAnchor = m_pFirstAnchor;
HWND hParent = GetParent(hWnd);// Parent of given window
POINT ptLT; // Left-top point in the client rectangle
POINT ptRB; // Right-bottom point in the client rectangle
RECT rect; // Window rect
// Test if the window passed is valid
if(IsWindow(hWnd) == FALSE || IsWindow(hParent) == FALSE)
{
OutputDebugString(_T("Invalid window handle passed to TAnchors::AddAnchor\n"));
return FALSE;
}
#ifdef __USE_SET_WINDOW_POS__
// Add the WS_CLIPCHILDREN style to the parent. This fastens the window
// redrawing. But I have found that the groupboxes make very ugly effect due to their
// bad redrawing logic. So we must be careful and add the style only if no
// groupbox was found inside the window.
BOOL bFoundGroupBox = FALSE;
for(HWND hChild = GetWindow(hParent, GW_CHILD); hChild != NULL; hChild = GetWindow(hChild, GW_HWNDNEXT))
{
char szClassName[64];
DWORD dwStyle = GetWindowLong(hChild, GWL_STYLE);
// If we knew the group box, stop the searching (one group box is enough)
GetClassNameA(hChild, szClassName, sizeof(szClassName));
if(!stricmp(szClassName, "Button") && (dwStyle & BS_GROUPBOX))
{
bFoundGroupBox = TRUE;
break;
}
}
// Add the WS_CLIPCHILDREN style
if(bFoundGroupBox == FALSE)
SetWindowLong(hParent, GWL_STYLE, GetWindowLong(hParent, GWL_STYLE) | WS_CLIPCHILDREN);
#endif // __USE_SET_WINDOW_POS__
// Create the new anchor
newAnchor = new TAnchor;
ZeroMemory(newAnchor, sizeof(TAnchor));
newAnchor->dwAnchors = dwAnchors;
newAnchor->hWnd = hWnd;
// Retrieve the relative position of each window side
GetClientRect(hParent, &newAnchor->parentRect);
ptLT.x = newAnchor->parentRect.left;
ptLT.y = newAnchor->parentRect.top;
ptRB.x = newAnchor->parentRect.right;
ptRB.y = newAnchor->parentRect.bottom;
ClientToScreen(hParent, &ptLT);
ClientToScreen(hParent, &ptRB);
// Store the distances
GetWindowRect(hWnd, &rect);
newAnchor->left = rect.left - ptLT.x;
newAnchor->top = rect.top - ptLT.y;
newAnchor->right = ptRB.x - rect.right;
newAnchor->bottom = ptRB.y - rect.bottom;
newAnchor->width = rect.right - rect.left;
newAnchor->height = rect.bottom - rect.top;
// Store the center relative distance
newAnchor->dx = (double)(newAnchor->left + newAnchor->width / 2) / (double)newAnchor->parentRect.right;
newAnchor->dy = (double)(newAnchor->top + newAnchor->height / 2) / (double)newAnchor->parentRect.bottom;
// Insert anchor in the chain
if(m_pFirstAnchor == NULL)
m_pFirstAnchor = newAnchor;
else
{
while(lastAnchor->next != NULL)
lastAnchor = lastAnchor->next;
lastAnchor->next = newAnchor;
}
return TRUE;
}
BOOL TAnchors::AddAnchor(HWND hParent, UINT ctrl, DWORD dwAnchors)
{
return AddAnchor(GetDlgItem(hParent, ctrl), dwAnchors);
}
// This function makes the complete anchoring. It must be called in response to
// WM_SIZE message, or whenever the child windows need to be repositioned.
BOOL TAnchors::AnchorAllObjects(HWND hParent)
{
TAnchor * pAnchor;
RECT NewRect; // New position and size of the resized window
// If no anchored windows, or the parent is not a valid window, do nothing
if(m_pFirstAnchor == NULL || IsWindow(hParent) == FALSE)
return FALSE;
#ifdef __USE_SET_WINDOW_POS__
for(pAnchor = m_pFirstAnchor; pAnchor != NULL; pAnchor = pAnchor->next)
{
if(GetNewWindowRect(hParent, pAnchor, NewRect))
{
SetWindowPos(pAnchor->hWnd, NULL, NewRect.left, NewRect.top, NewRect.right, NewRect.bottom, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
InvalidateRect(pAnchor->hWnd, NULL, TRUE);
}
}
#endif
// This method uses xxxDeferWindowPos and is the best one. Deferred window
// positioning is a part of Windows API and thus supported by Microsoft.
#ifdef __USE_DEFER_WINDOW_POS__
HDWP hDwp = NULL;
int nWindows = 0;
// Count the anchored windows and begin the window positioning
for(pAnchor = m_pFirstAnchor; pAnchor != NULL; pAnchor = pAnchor->next)
nWindows++;
hDwp = BeginDeferWindowPos(nWindows);
for(pAnchor = m_pFirstAnchor; pAnchor != NULL; pAnchor = pAnchor->next)
{
if(GetNewWindowRect(hParent, pAnchor, NewRect))
hDwp = DeferWindowPos(hDwp, pAnchor->hWnd, NULL, NewRect.left, NewRect.top, NewRect.right, NewRect.bottom, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
}
EndDeferWindowPos(hDwp);
#endif
// This method is similar to using SetWindowPos, except that the redrawing
// is completely directed by us.
#ifdef __USE_FAST_REDRAW__
SendMessage(hParent, WM_SETREDRAW, FALSE, 0);
for(pAnchor = m_pFirstAnchor; pAnchor != NULL; pAnchor = pAnchor->next)
{
if(GetNewWindowRect(hParent, pAnchor, NewRect))
SetWindowPos(pAnchor->hWnd, NULL, NewRect.left, NewRect.top, NewRect.right, NewRect.bottom, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
}
// Fast redraw logic does not work properly in this moment
// Problem : how to redraw the non-client area ?
SendMessage(hParent, WM_SETREDRAW, TRUE, 0);
PaintWindow(hParent, NULL);
#endif // __USE_FAST_REDRAW__
return TRUE;
}
//-----------------------------------------------------------------------------
// This function calculates the new position of the window after the size
// of its parent has been changed.
BOOL TAnchors::GetNewWindowRect(HWND hParent, TAnchor * pAnchor, RECT & NewRect)
{
POINT ptLT;
RECT winRect; // Screen rectangle of the moved window
RECT clientRect; // Client rectangle of the resized window
int x, y, cx, cy; // New window pos and size
// Retrieve the client dimensions
GetClientRect(hParent, &clientRect);
ptLT.x = clientRect.left;
ptLT.y = clientRect.top;
ClientToScreen(hParent, &ptLT);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -