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程序设计--(五)绘图基础的更多相关文章

  1. windows游戏编程 绘图基础

    本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22451353 作者:jadeshu   邮箱: jades ...

  2. 关于《Windows程序设计(第五版)》中一个实例程序的疑问

    最近一直在看Charlse Petzold的<Windows程序设计>,作为一个新得不能再新的新手,只能先照着书的抄抄源码了,之前的例子一直都很正常,但昨天遇到一个很诡异的BUG. 先看实 ...

  3. GDI+(一):GDI+ 绘图基础

    一.GDI+绘图基础 编写图形程序时需要使用GDI(Graphics Device Interface,图形设备接口),从程序设计的角度看,GDI包括两部分:一部分是GDI对象,另一部分是GDI函数. ...

  4. Windows 程序设计(4) MFC 03 -系列学习

    本文整体目录和绝大部门内容来自 [鸡啄米网站]的MFC系列文章,欢迎支持原创 (一)VS2010/MFC编程入门之前言 VC++全称是Visual C++,是由微软提供的C++开发工具,它与C++的根 ...

  5. windows 程序设计自学:添加图标资源

    #include <windows.h> #include "resource.h" LRESULT CALLBACK MyWndProc( HWND hwnd, // ...

  6. 《Windows程序设计第5版》学习进度备忘

    书签:另外跳过的内容有待跟进 __________________学习资源: <Windows程序设计第5版珍藏版> __________________知识基础支持: _________ ...

  7. windows 程序设计 SetPolyFillMode关于ALTERNATE、WINDING的详细解释

    看windows程序第五章GDI编程部分.一直卡壳在这里了. 下面我来说下自己的想法.看是否对您有帮助. 首先我们来看一个图. SetPolyFillMode(ALTERNATE);  // 系统默认 ...

  8. windows程序设计简介

    大家好,非常高兴和大家一起分享Windows开发心得,Windows已经诞生很多年了,一直因为它的简单易用而深受欢迎,相信很多人在使用Windows的时候,一定有这样一个想法:希望自己将来可以写一个很 ...

  9. 愉快的开始 - Windows程序设计(SDK)000

    愉快的开始 让编程改变世界 Change the world by program  参考教材 购买链接:Windows程序设计(第5版)(珍藏版)(附CD-ROM光盘1张)  学习环境 视频演示:W ...

  10. Android中Canvas绘图基础详解(附源码下载) (转)

    Android中Canvas绘图基础详解(附源码下载) 原文链接  http://blog.csdn.net/iispring/article/details/49770651   AndroidCa ...

随机推荐

  1. ssh免口令密码登录及兼容性处理

    1). client ---> server 客户端发起对服务器的连接,登录服务器. 2). 须在客户端生成密钥对 注意: 公钥加密私钥解:私钥加密公钥解. 可以发布公钥,但私钥是不能出本机的. ...

  2. Flutter-網絡請求

    Flutter 请求网络的三种方式 flutter 请求网络的方式有三种,分别是 Dart 原生的网络请求 HttpClient.第三方网络请求 http以及 Flutter 中的 Dio.我们可以比 ...

  3. 对webpack的初步研究6

    Plugins 插件是webpack 的支柱.webpack本身构建在您在webpack配置中使用的相同插件系统上! 它们也是这样做的目的别的,一个装载机无法做到的. Anatomy webpack  ...

  4. jenkins解决python不是内部命令

    1.在 Windows 提示符下运行是没有问题. 2.把Jenkins项目配置中 python main.py   修改成python可执行文件全路径:D:\Python35\python.exe m ...

  5. linux运维、架构之路-Zabbix监控

    一.监控常用命令 1.物理服务器监控命令 ①添加yum源 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/rep ...

  6. vue框架搭建--移动端

    由于Vue官方提供了vue-cli手脚架,所以快速构建出个简单的项目框架.在做移动端项目时,因为移动端的特性可能会用到些比较常用的插件,就在这里简单介绍如何使用 这里只介绍怎么在项目中安装引用和简单的 ...

  7. 20180805-Java ByteArrayInputStream类

    ByteArrayInputStream bArray = new ByteArrayInputStream(byte [] a); ByteArrayInputStream bArray = new ...

  8. .NETFramework:System.Net.WebClient.cs

    ylbtech-.NETFramework:System.Net.WebClient.cs 提供用于将数据发送到和接收来自通过 URI 确认的资源数据的常用方法 1.返回顶部 1. #region 程 ...

  9. 让dcef3支持mp3和h.264 mp4解码播放

    嵌入式Chromium框架(简称CEF) 是一个由Marshall Greenblatt在2008建立的开源项目,它主要目的是开发一个基于Google Chromium的Webbrowser控件.CE ...

  10. LATERAL VIEW 语法

    LATERAL VIEW 使用语法 原文链接: https://www.deeplearn.me/2892.html select a.id, b.son_order_path from f_jz_c ...