Lesson 4: 窗口大小和客户区大小
课程预览
在处理图形的时候,知道你要绘制的区域的准确尺寸很重要。上节课我们创建了一个窗口并把它的尺寸设为500X400.但是Direct3D的绘制区域并不是窗口的500x400。
本节我们将要探索绘制区域的实际尺寸并学习一个准确设置它的函数。
Window Size vs. Client Size
当我们调用CreateWindowEx()时,我们用500和400设置窗口大小。但是客户区大小是不同的,客户区是窗口不包含边框的部分。
正如你看到的,我们只会在窗口的客户区绘图,它的确切大小为什么相当重要?当用Direct3D绘画时你被询问以指定产生图形的大小。如果窗口客户区大小不同于图形大小,它会拉伸或收缩以适应客户区。
正如你看到的,右边的截图有明显的失真。这是图形收缩适应客户区造成的。
The AdjustWindowRect() Function
其思想是预先决定客户区大小然后计算相应的窗口大小,而不是设置窗口尺寸再决定客户区大小。要达到此目的需要在创建窗口之前使用AdjustWindowRect() 函数。
这真的是个卖萌函数。它做的就是采用要求的客户区的尺寸和位置并计算必要的窗口位置和尺寸来创建客户区大小。
函数原型:
BOOL AdjustWindowRect(LPRECT lpRect,
DWORD dwStyle,
BOOL bMenu);
第一个参数是指向RECT结构的指针。RECT包含了所要求客户区的坐标。当函数被调用后RECT被修改以代替包含窗口区域的坐标。
第二个参数是窗口风格。函数用这个信息决定窗口边框的大小。
第三个参数是个BOOL值,告诉函数我们是否使用菜单。菜单不在客户区。
下面是我们修改过的CreateWindowEx()调用:
RECT wr = {0, 0, 500, 400}; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
L"WindowClass1",
L"Our First Windowed Program",
WS_OVERLAPPEDWINDOW,
300, // x-position of the window
300, // y-position of the window
wr.right - wr.left, // width of the window
wr.bottom - wr.top, // height of the window
NULL,
NULL,
hInstance,
NULL);
拆解代码:
RECT wr = {0, 0, 500, 400};
这是个简单语句,我们创建一个矩形(窗口矩形命名为‘wr’),初始化为所要求的客户区大小。我们不在‘left’和‘top’值里放入位置是因为我们所做的不需要如此。
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
RECT初始化之后我们调用AdjustWindowRect()函数。我们给他填上RECT的地址,窗口风格并指定没有菜单。
wr.right - wr.left,
wr.bottom - wr.top,
调用AdjustWindowRect()之后,左右之间的宽和顶底之间的高将会是不同的。
使用这两个窗口的宽高表达式将给我们正确的窗口尺寸。
添加新代码
这儿是我们的新代码包括 AdjustWindowRect()函数。我们已经改变的部分现在是粗体。
// include the basic windows header file
#include <windows.h>
#include <windowsx.h>
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
// register the window class
RegisterClassEx(&wc);
// calculate the size of the client area
RECT wr = {0, 0, 500, 400}; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
wr.right - wr.left, // width of the window
wr.bottom - wr.top, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
// enter the main loop:
// this struct holds Windows event messages
MSG msg;
// wait for the next message in the queue, store the result in 'msg'
while(GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
}
// Handle any messages the switch statement didn't
return DefWindowProc (hWnd, message, wParam, lParam);
}
当你运行这个程序的时候你会发现外观上真的没有区别。事实上你在游戏编程中使用AdjustWindowRect()之前你都不会看到差别。
好的,再来一节就接触Direct3D!