Windows程序设计--(五)绘图基础
5.1 GDI的结构
图形设备接口(GDI:Graphics Device Interface)是Windows的子系统,它负责在视讯显示器和打印机上显示图形。
5.2 设备环境
5.2.1 获取设备环境句柄
最常用的取得并释放设备内容句柄的方法是,在处理WM_PAINT消息时,使用BeginPaint和EndPaint呼叫:
hdc = BeginPaint (hwnd, &ps) ;
其它行程序
EndPaint (hwnd, &ps) ;
Windows程序还可以在处理非WM_PAINT消息时取得设备内容句柄:
hdc = GetDC (hwnd) ;
其它行程序
ReleaseDC (hwnd, hdc) ;
Windows程序还可以取得适用于整个窗口(而不仅限于窗口的显示区域)的设备内容句柄:
hdc = GetWindowDC (hwnd) ;
其它行程序
ReleaseDC (hwnd, hdc) ;
5.3 点和线的绘制
5.3.1 设定像素
SetPixel函数在指定的x和y坐标以特定的颜色设定图素:
SetPixel (hdc, x, y, crColor) ;
第一个参数是设备内容的句柄。第二个和第三个参数指明了坐标位置。通常要获得窗口显示区域的设备内容,并且x和y相对于该显示区域的左上角。最后一个参数是COLORREF型态指定了颜色。如果在函数中指定的颜色视讯显示器不支持,则函数将图素设定为最接近的纯色并从函数传回该值。
GetPixel函数传回指定坐标处的图素颜色:
crColor = GetPixel (hdc, x, y) ;
5.3.2 直线
画一条直线,必须呼叫两个函数。第一个函数指定了线的开始点,第二个函数指定了线的终点:
MoveToEx (hdc, xBeg, yBeg, NULL) ;
LineTo (hdc, xEnd, yEnd) ;
绘制直线
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//消息函数声明 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)//主函数
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");//窗口类名称
HWND hwnd;//句柄
MSG msg;//结构体
WNDCLASS wndclass;//窗口类 //窗口类属性
wndclass.style = CS_HREDRAW | CS_VREDRAW;//样式
wndclass.lpfnWndProc = WndProc;//窗口处理函数
wndclass.cbClsExtra = ;//窗口实例扩展
wndclass.cbWndExtra = ;//窗口类扩展
wndclass.hInstance = hInstance;//窗口实例句柄
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);//加载图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);//鼠标,移入内容区域变成箭头
wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);//主窗口背景色
wndclass.lpszMenuName = NULL;//窗口菜单
wndclass.lpszClassName = szAppName;//窗口类名 if (!RegisterClass(&wndclass)) {//注册窗口类,如果注册失败弹出窗口
MessageBox(NULL, TEXT("窗口创建失败!程序需要Windows NT!(传递窗口消息为UNICODE)"), szAppName, MB_ICONERROR);//消息窗口 return ;
} hwnd = CreateWindow(szAppName, //Windows类名
TEXT("窗口绘制成功!"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //初始化窗口位置的X坐标
CW_USEDEFAULT, //初始化窗口位置的Y坐标
, //初始化窗口宽度大小
, //初始化窗口长度大小
NULL, //父类窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL); //创建参数
ShowWindow(hwnd, iCmdShow);//显示窗口
UpdateWindow(hwnd);//更新窗口 while (GetMessage(&msg, NULL, , )) {//从消息队列中获取消息
TranslateMessage(&msg);//将虚拟键消息转换为字符消息
DispatchMessage(&msg);//分发到回调函数
}
return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc;//设备环境句柄
int x, y;
/*
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT
其中left,top赋为0,因此right和bottom表示客户区的宽度和高度(像素)
*/
RECT rect;//矩形结构 switch (message) {//处理得到的消息
case WM_PAINT://处理窗口绘制
hdc = GetDC(hwnd);
GetClientRect(hwnd, &rect);//获取当前位置
for (x = ; x < rect.right; x += ) {//竖线
MoveToEx(hdc, x, , NULL);//设置起点
LineTo(hdc, x, rect.bottom);//设置终点
}
for (y = ; y < rect.bottom; y += ) {//横线
MoveToEx(hdc, , y, NULL);
LineTo(hdc, rect.right, y);
}
ReleaseDC(hwnd, hdc);
return ;
case WM_DESTROY://处理窗口关闭时的消息
PostQuitMessage();//将退出消息插入消息队列,程序从消息循环退出,return msg.wParam
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);//执行默认消息处理
}
绘制矩形
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//消息函数声明 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)//主函数
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");//窗口类名称
HWND hwnd;//句柄
MSG msg;//结构体
WNDCLASS wndclass;//窗口类 //窗口类属性
wndclass.style = CS_HREDRAW | CS_VREDRAW;//样式
wndclass.lpfnWndProc = WndProc;//窗口处理函数
wndclass.cbClsExtra = ;//窗口实例扩展
wndclass.cbWndExtra = ;//窗口类扩展
wndclass.hInstance = hInstance;//窗口实例句柄
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);//加载图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);//鼠标,移入内容区域变成箭头
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITENESS);//主窗口背景色
wndclass.lpszMenuName = NULL;//窗口菜单
wndclass.lpszClassName = szAppName;//窗口类名 if (!RegisterClass(&wndclass)) {//注册窗口类,如果注册失败弹出窗口
MessageBox(NULL, TEXT("窗口创建失败!程序需要Windows NT!(传递窗口消息为UNICODE)"), szAppName, MB_ICONERROR);//消息窗口 return ;
} hwnd = CreateWindow(szAppName, //Windows类名
TEXT("Hk_Mayfly"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //初始化窗口位置的X坐标
CW_USEDEFAULT, //初始化窗口位置的Y坐标
, //初始化窗口宽度大小
, //初始化窗口长度大小
NULL, //父类窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL); //创建参数
ShowWindow(hwnd, iCmdShow);//显示窗口
UpdateWindow(hwnd);//更新窗口 while (GetMessage(&msg, NULL, , )) {//从消息队列中获取消息
TranslateMessage(&msg);//将虚拟键消息转换为字符消息
DispatchMessage(&msg);//分发到回调函数
}
return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc;//设备环境句柄
POINT apt[] = { , , , , , , , , , };//矩形坐标
int i;
/*
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT
其中left,top赋为0,因此right和bottom表示客户区的宽度和高度(像素)
*/
RECT rect;//矩形结构 switch (message) {//处理得到的消息
case WM_PAINT://处理窗口绘制
hdc = GetDC(hwnd);
GetClientRect(hwnd, &rect);//获取当前位置
MoveToEx(hdc, apt[].x, apt[].y, NULL);
for (i = ; i < ; ++i) {
LineTo(hdc, apt[i].x, apt[i].y);
}
ReleaseDC(hwnd, hdc);
return ;
case WM_DESTROY://处理窗口关闭时的消息
PostQuitMessage();//将退出消息插入消息队列,程序从消息循环退出,return msg.wParam
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);//执行默认消息处理
}
使用Polyline替换,也可以绘制矩形。
Polyline(hdc, apt, );
或者
MoveToEx(hdc, apt[].x, apt[].y, NULL);
PolylineTo(hdc, apt, );
绘制正弦曲线
#include <Windows.h>
#include <math.h> #define NUM 1000
#define TWOPI (2*3.14159) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//消息函数声明 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)//主函数
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");//窗口类名称
HWND hwnd;//句柄
MSG msg;//结构体
WNDCLASS wndclass;//窗口类 //窗口类属性
wndclass.style = CS_HREDRAW | CS_VREDRAW;//样式
wndclass.lpfnWndProc = WndProc;//窗口处理函数
wndclass.cbClsExtra = ;//窗口实例扩展
wndclass.cbWndExtra = ;//窗口类扩展
wndclass.hInstance = hInstance;//窗口实例句柄
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);//加载图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);//鼠标,移入内容区域变成箭头
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITENESS);//主窗口背景色
wndclass.lpszMenuName = NULL;//窗口菜单
wndclass.lpszClassName = szAppName;//窗口类名 if (!RegisterClass(&wndclass)) {//注册窗口类,如果注册失败弹出窗口
MessageBox(NULL, TEXT("窗口创建失败!程序需要Windows NT!(传递窗口消息为UNICODE)"), szAppName, MB_ICONERROR);//消息窗口 return ;
} hwnd = CreateWindow(szAppName, //Windows类名
TEXT("Hk_Mayfly"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //初始化窗口位置的X坐标
CW_USEDEFAULT, //初始化窗口位置的Y坐标
, //初始化窗口宽度大小
, //初始化窗口高度大小
NULL, //父类窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL); //创建参数
ShowWindow(hwnd, iCmdShow);//显示窗口
UpdateWindow(hwnd);//更新窗口 while (GetMessage(&msg, NULL, , )) {//从消息队列中获取消息
TranslateMessage(&msg);//将虚拟键消息转换为字符消息
DispatchMessage(&msg);//分发到回调函数
}
return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc;//设备环境句柄
PAINTSTRUCT ps;
static int cxClient, cyClient;
int i;
POINT apt[NUM]; switch (message) {//处理得到的消息
case WM_SIZE:
cxClient = LOWORD(lParam);//客户区宽度
cyClient = HIWORD(lParam);//客户区的高度
return ;
case WM_PAINT://处理窗口绘制
hdc = BeginPaint(hwnd, &ps);
MoveToEx(hdc, , cyClient / , NULL);//中间横线
LineTo(hdc, cxClient, cyClient / ); for (i = ; i < NUM; i++) {
apt[i].x = i * cxClient / NUM;
apt[i].y = (int)(cyClient / * ( - sin(TWOPI * i / NUM)));
//apt[i].x = i*15;
//apt[i].y = (int)cyClient*sin(0.1*i);
}
Polyline(hdc, apt, NUM);
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY://处理窗口关闭时的消息
PostQuitMessage();//将退出消息插入消息队列,程序从消息循环退出,return msg.wParam
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);//执行默认消息处理
}
5.3.3 边框绘制函数
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
,//宽度
,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps; switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//Rectangle(hdc, 100, 200, 500, 400);//矩形
//Ellipse(hdc, 100, 200, 500, 400);//椭圆
//RoundRect(hdc, 100, 200, 500, 400, 100, 100);//圆角矩阵
//Arc(hdc, 100, 200, 500, 400, 500, 350, 100, 350);//弧
//Chord(hdc, 100, 200, 500, 400, 500, 350, 100, 350);//弦
//Pie(hdc, 100, 200, 500, 400, 500, 350, 100, 350);//饼
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
自定义程序
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
,//宽度
,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps; switch (message) {
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
Rectangle(hdc, , , , );
MoveToEx(hdc, , , NULL);
LineTo(hdc, , );
MoveToEx(hdc, cxClient, , NULL);
LineTo(hdc, , );
MoveToEx(hdc, , cyClient, NULL);
LineTo(hdc, , );
MoveToEx(hdc, cxClient, cyClient, NULL);
LineTo(hdc, , );
Ellipse(hdc, , , , );
Arc(hdc, , , , , , , , );//弧,逆时针绘制
Arc(hdc, , , , , , , , );
Ellipse(hdc, , , , );//小圆圈
Ellipse(hdc, , , , );
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
5.3.4 贝塞尔样条曲线
一条二维的贝塞尔曲线由四个点定义-两个端点和两个控制点。曲线的端点在两个端点上,控制点就好像「磁石」一样把曲线从两个端点间的直线处拉走。
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//宽度
CW_USEDEFAULT,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} void DrawBezier(HDC hdc, POINT apt[]) {
PolyBezier(hdc, apt, ); MoveToEx(hdc, apt[].x, apt[].y, NULL);
LineTo(hdc, apt[].x, apt[].y); MoveToEx(hdc, apt[].x, apt[].y, NULL);
LineTo(hdc, apt[].x, apt[].y);
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static POINT apt[];
int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps; switch (message) {
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam); apt[].x = cxClient / ;
apt[].y = cyClient / ; apt[].x = cxClient / ;
apt[].y = cyClient / ; apt[].x = cxClient / ;
apt[].y = * cyClient / ; apt[].x = * cxClient / ;
apt[].y = cyClient / ; return ;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON || wParam & MK_RBUTTON) {
hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(WHITE_PEN));
DrawBezier(hdc, apt);
if (wParam & MK_LBUTTON) {
apt[].x = LOWORD(lParam);
apt[].y = HIWORD(lParam);
}
if (wParam & MK_RBUTTON) {
apt[].x = LOWORD(lParam);
apt[].y = HIWORD(lParam);
}
SelectObject(hdc, GetStockObject(BLACK_PEN));
DrawBezier(hdc, apt);
ReleaseDC(hwnd, hdc);
} return ;
case WM_PAINT:
InvalidateRect(hwnd, NULL, TRUE);
hdc = BeginPaint(hwnd, &ps);
DrawBezier(hdc, apt);
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
5.3.6 创建,选择和删除画笔
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
,//宽度
,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps;
static HPEN hPen1, hPen2; switch (message) {
case WM_CREATE:
hPen1 = CreatePen(PS_DOT, , );
hPen2 = CreatePen(PS_DASH, , RGB(, , ));
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, hPen1);
Ellipse(hdc, , , , );
Ellipse(hdc, , , , );//小圆圈
SelectObject(hdc, hPen2);
Arc(hdc, , , , , , , , );//弧,逆时针绘制
SelectObject(hdc, CreatePen(PS_DASH, , RGB(, , )));
Arc(hdc, , , , , , , , );
Ellipse(hdc, , , , );
DeleteObject(SelectObject(hdc, CreatePen(PS_DASH, , RGB(, , ))));
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
DeleteObject(hPen1);
DeleteObject(hPen2);
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
5.4 绘制填充区域
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
,//宽度
,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps;
static HBRUSH hBrush; switch (message) {
case WM_CREATE:
hBrush = GetStockObject(LTGRAY_BRUSH);//获取句柄
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, hBrush);//选入设备环境
Ellipse(hdc, , , , );
Ellipse(hdc, , , , );//小圆圈
Arc(hdc, , , , , , , , );//弧,逆时针绘制
Arc(hdc, , , , , , , , );
Ellipse(hdc, , , , );
DeleteObject(SelectObject(hdc, CreatePen(PS_DASH, , RGB(, , ))));
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
5.4.1 Polygon函数和多边形填充模式
Polygon按照点的顺序连接多边图形,如果数组中最后一个点与第一个点不同,则Windows会再添加一条线连接最后一个点与第一个点。
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//宽度
CW_USEDEFAULT,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static POINT apt[] = { , , , , , , , , , , , };
static int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps; switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, GetStockObject(GRAY_BRUSH));//获取灰色画刷并设置到环境设备中
Polygon(hdc, apt, );
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
PolyPolygon(hdc, apt, aiCounts, iPolyCount);
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//宽度
CW_USEDEFAULT,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static POINT apt[] = { , , , , , , , , , , , , , , , , , , , };//六边形(前6组坐标)和四边形
static int aiCounts[] = { , };//6个顶点,4个顶点
static int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps; switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, GetStockObject(GRAY_BRUSH));//获取灰色画刷并设置到环境设备中
PolyPolygon(hdc, apt, aiCounts, );
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//宽度
CW_USEDEFAULT,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static POINT aptFigure[] = { , , , , , , , , , , , , , , , , , , , };
static int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps;
int i;
static POINT apt[]; switch (message) {
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return ;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, GetStockObject(GRAY_BRUSH));//获取灰色画刷并设置到环境设备中
for (i = ; i < ; ++i) {
apt[i].x = cxClient * aptFigure[i].x / ;
apt[i].y = cyClient * aptFigure[i].y / ;
}
SetPolyFillMode(hdc, ALTERNATE);//设置填充模式为交替模式
Polygon(hdc, apt, );
for (i = ; i < ; ++i) {
apt[i].x += cxClient / ;
}
SetPolyFillMode(hdc, WINDING);//设置填充模式为螺旋模式
Polygon(hdc, apt, );
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
5.4.2 用画刷填充内部
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//宽度
CW_USEDEFAULT,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static POINT apt[] = { , , , , , , , , , , , };
HDC hdc;
PAINTSTRUCT ps;
HBRUSH hBrush;
static int i; switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//SetBkMode(hdc, TRANSPARENT);
hBrush = CreateSolidBrush(BLACK_BRUSH);//创建一个纯色画刷,但是这个画刷不一定为纯色
//SelectObject(hdc, GetStockObject(GRAY_BRUSH));//获取灰色画刷并设置到环境设备中
SelectObject(hdc, hBrush);//将画刷选入设备环境
Polygon(hdc, apt, );
for (i = ; i < ; ++i) {
apt[i].x += ;
}
hBrush = CreateHatchBrush(HS_FDIAGONAL, GRAY_BRUSH);//第一个参数是阴影线标记的外观
SelectObject(hdc, hBrush);
Polygon(hdc, apt, );
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
5.5 GDI映射模式
Windows定义了8种映像方式,它们在WINGDI.H中相应的标识符和含义如表
映像方式 | 逻辑单位 | 增加值 | |
x值 | y值 | ||
MM_TEXT | 图素 | 右 | 下 |
MM_LOMETRIC | 0.1 mm | 右 | 上 |
MM_HIMETRIC | 0.01 mm | 右 | 上 |
MM_LOENGLISH | 0.01 in. | 右 | 上 |
MM_HIENGLISH | 0.001 in. | 右 | 上 |
MM_TWIPS | 1/1440 in. | 右 | 上 |
MM_ISOTROPIC | 任意(x = y) | 可选 | 可选 |
MM_ANISOTROPIC | 任意(x != y) | 可选 | 可选 |
#include <Windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WNDCLASS NAME");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口创建失败!需要Windows NT!(传递消息为UNICODE)"), szAppName, MB_ICONERROR); return ;
} hwnd = CreateWindow(
szAppName,
TEXT("Hk_Mayfly"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,//宽度
CW_USEDEFAULT,//高度
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps;
static int iMapMode;
TCHAR szBuffer[] = L"Hk_Mayfly!!!!?"; switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
iMapMode = GetMapMode(hdc);//获取当前的映射模式
TextOut(hdc, , , szBuffer, lstrlen(szBuffer));//逻辑单位1像素, 一像素0.3mm int iLength = wsprintf(szBuffer, TEXT("Biu biu!!!"));
iMapMode = MM_TWIPS;
SetMapMode(hdc, iMapMode);//逻辑单位1/1440in, 一英寸2.54cm
TextOut(hdc, , -, szBuffer, iLength); iMapMode = MM_LOMETRIC;
SetMapMode(hdc, iMapMode);//逻辑单位0.1mm
TextOut(hdc, , -, szBuffer, wsprintf(szBuffer, TEXT("%s"), L"Test!!!"));
EndPaint(hwnd, &ps);
return ;
case WM_DESTROY:
PostQuitMessage();
return ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
5.5.1 设备坐标和逻辑坐标
在呼叫GetTextMetrics以取得关于字符的宽度和高度信息时,映像方式必须设定成根据这些信息输出文字时所使用的映像方式
5.5.2 设备坐标系统
「屏幕坐标」:当我们使用整个屏幕时,就根据「屏幕坐标」进行操作。屏幕的左上角为(0,0)点,屏幕坐标用在WM_MOVE消息(对于非子窗口)以及下列Windows函数中:CreateWindow和MoveWindow(都是对于非子窗口)、GetMessagePos、GetCursorPos、SetCursorPos、GetWindowRect以及WindowFromPoint(这不是全部函数的列表)。它们或者是与窗口无关的函数(如两个光标函数),或者是必须相对于某个屏幕点来移动(或者寻找)窗口的函数。如果以DISPLAY为参数呼叫CreateDC,以取得整个屏幕的设备内容,则内定情况下GDI呼叫中指定的逻辑坐标将被映像为屏幕坐标。
「全窗口坐标」:以程序的整个窗口为基准,如标题列、菜单、滚动条和窗口框都包括在内。而对于普通窗口,点(0,0)是缩放边框的左上角。全窗口坐标在Windows中极少使用,但是如果用GetWindowDC取得设备内容,GDI函数中的逻辑坐标就会转换为显示区域坐标。
「显示区域坐标系」:点(0,0)是显示区域的左上角。当使用GetDC或BeginPaint取得设备内容时,GDI函数中的逻辑坐标就会内定转换为显示区域坐标。
用函数ClientToScreen和ScreenToClient可以将显示区域坐标转换为屏幕坐标,或者反过来,将屏幕坐标转换为显示区域坐标。也可以使用GetWindowRect函数取得屏幕坐标下的整个窗口的位置和大小。这三个函数为一种设备坐标转换为另一种提供了足够的信息。
5.5.4 使用MM_TEXT
https://www.cnblogs.com/Mayfly-nymph/p/11414063.html
Windows程序设计--(五)绘图基础的更多相关文章
- windows游戏编程 绘图基础
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22451353 作者:jadeshu 邮箱: jades ...
- 关于《Windows程序设计(第五版)》中一个实例程序的疑问
最近一直在看Charlse Petzold的<Windows程序设计>,作为一个新得不能再新的新手,只能先照着书的抄抄源码了,之前的例子一直都很正常,但昨天遇到一个很诡异的BUG. 先看实 ...
- GDI+(一):GDI+ 绘图基础
一.GDI+绘图基础 编写图形程序时需要使用GDI(Graphics Device Interface,图形设备接口),从程序设计的角度看,GDI包括两部分:一部分是GDI对象,另一部分是GDI函数. ...
- Windows 程序设计(4) MFC 03 -系列学习
本文整体目录和绝大部门内容来自 [鸡啄米网站]的MFC系列文章,欢迎支持原创 (一)VS2010/MFC编程入门之前言 VC++全称是Visual C++,是由微软提供的C++开发工具,它与C++的根 ...
- windows 程序设计自学:添加图标资源
#include <windows.h> #include "resource.h" LRESULT CALLBACK MyWndProc( HWND hwnd, // ...
- 《Windows程序设计第5版》学习进度备忘
书签:另外跳过的内容有待跟进 __________________学习资源: <Windows程序设计第5版珍藏版> __________________知识基础支持: _________ ...
- windows 程序设计 SetPolyFillMode关于ALTERNATE、WINDING的详细解释
看windows程序第五章GDI编程部分.一直卡壳在这里了. 下面我来说下自己的想法.看是否对您有帮助. 首先我们来看一个图. SetPolyFillMode(ALTERNATE); // 系统默认 ...
- windows程序设计简介
大家好,非常高兴和大家一起分享Windows开发心得,Windows已经诞生很多年了,一直因为它的简单易用而深受欢迎,相信很多人在使用Windows的时候,一定有这样一个想法:希望自己将来可以写一个很 ...
- 愉快的开始 - Windows程序设计(SDK)000
愉快的开始 让编程改变世界 Change the world by program 参考教材 购买链接:Windows程序设计(第5版)(珍藏版)(附CD-ROM光盘1张) 学习环境 视频演示:W ...
- Android中Canvas绘图基础详解(附源码下载) (转)
Android中Canvas绘图基础详解(附源码下载) 原文链接 http://blog.csdn.net/iispring/article/details/49770651 AndroidCa ...
随机推荐
- ssh免口令密码登录及兼容性处理
1). client ---> server 客户端发起对服务器的连接,登录服务器. 2). 须在客户端生成密钥对 注意: 公钥加密私钥解:私钥加密公钥解. 可以发布公钥,但私钥是不能出本机的. ...
- Flutter-網絡請求
Flutter 请求网络的三种方式 flutter 请求网络的方式有三种,分别是 Dart 原生的网络请求 HttpClient.第三方网络请求 http以及 Flutter 中的 Dio.我们可以比 ...
- 对webpack的初步研究6
Plugins 插件是webpack 的支柱.webpack本身构建在您在webpack配置中使用的相同插件系统上! 它们也是这样做的目的别的,一个装载机无法做到的. Anatomy webpack ...
- jenkins解决python不是内部命令
1.在 Windows 提示符下运行是没有问题. 2.把Jenkins项目配置中 python main.py 修改成python可执行文件全路径:D:\Python35\python.exe m ...
- linux运维、架构之路-Zabbix监控
一.监控常用命令 1.物理服务器监控命令 ①添加yum源 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/rep ...
- vue框架搭建--移动端
由于Vue官方提供了vue-cli手脚架,所以快速构建出个简单的项目框架.在做移动端项目时,因为移动端的特性可能会用到些比较常用的插件,就在这里简单介绍如何使用 这里只介绍怎么在项目中安装引用和简单的 ...
- 20180805-Java ByteArrayInputStream类
ByteArrayInputStream bArray = new ByteArrayInputStream(byte [] a); ByteArrayInputStream bArray = new ...
- .NETFramework:System.Net.WebClient.cs
ylbtech-.NETFramework:System.Net.WebClient.cs 提供用于将数据发送到和接收来自通过 URI 确认的资源数据的常用方法 1.返回顶部 1. #region 程 ...
- 让dcef3支持mp3和h.264 mp4解码播放
嵌入式Chromium框架(简称CEF) 是一个由Marshall Greenblatt在2008建立的开源项目,它主要目的是开发一个基于Google Chromium的Webbrowser控件.CE ...
- LATERAL VIEW 语法
LATERAL VIEW 使用语法 原文链接: https://www.deeplearn.me/2892.html select a.id, b.son_order_path from f_jz_c ...