栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

纯C语言用Windows api写画函数图像

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

纯C语言用Windows api写画函数图像

!!!如有转载 请注明出处!!!

主要功能介绍:
1、输入函数的解析式,可以在窗口中画出解析式的函数图像。
2、解析式只能以x为自变量。
3、解析式目前只能写数字、括号、加减乘除四则运算(±*/),不能写乘方、开方、各种函数(三角函数、对数等等)。
4、输入解析式时,程序禁用中文输入法,也不能输入中文括号。.
5、输入解析式语法错误时,程序弹出对话框并告知哪里有错误,允许重新输入。
6、输入解析式的窗口在任务栏不显示。
7、输入解析式的窗口一旦打开,主窗口就不响应任何操作,直到输入解析式的窗口关闭。关闭以后,主窗口重画所有函数图像和x、y轴。
8、x、y轴为黑色,图像红色。

环境:
Windows10 64位,MinGW-POSIX-64位。

注:
1、若为32位系统,据说需要将SetWindowLongPtr换为SetWindowLong,里面参数GWLP_WNDPROC需要换为GWL_WNDPROC(我也没试过,所以不能那么肯定。大家可以自己试一试)

2、如果编译不通过,在makefile.bat中编译可执行文件的一行手动链接pthread库。

3、如果报错不支持WinMain函数入口,可以百度下载msys64(大概就是这么一个东西)来支持win32应用程序,至于如何安装百度都有,这里不赘述。

截图:






代码如下:

//libtranslateexpression.c
#include 
#include 
#include 
#include 
#include 

#define SGR_MAX_EXPR 1024

#define CHECKFUNC_NO_ERROR				0x00
#define CHECKFUNC_FOUND_TIMEADDBR		0x01
#define CHECKFUNC_FOUND_TIMESUBBR		0x02
#define CHECKFUNC_FOUND_DIVADDBR		0x03
#define CHECKFUNC_FOUND_DIVSUBBR		0x04
#define CHECKFUNC_BRACKET_ERROR			0x05
#define CHECKFUNC_NONUMBERAFTERSIGN		0x06
#define CHECKFUNC_NONUMBERBEFORESIGN	0x07
#define CHECKFUNC_DECIMALPOINT_ERROR	0x08
#define CHECKFUNC_VARIBLEHASNOSIGN		0x09

BOOL CheckFuncExpr(const char* expr)
{
	if(strstr(expr,"*+(")!=NULL)	return CHECKFUNC_FOUND_TIMEADDBR;
    if(strstr(expr,"*-(")!=NULL)	return CHECKFUNC_FOUND_TIMESUBBR;
    if(strstr(expr,"/+(")!=NULL)	return CHECKFUNC_FOUND_DIVADDBR;
    if(strstr(expr,"/-(")!=NULL)	return CHECKFUNC_FOUND_DIVSUBBR;
    
	int i=0,bracket=0;
    for(;expr[i]!='';i++)
    {
		if(expr[i]=='(')	bracket++;
        if(expr[i]==')')	bracket--;
        if(bracket<0)		return CHECKFUNC_BRACKET_ERROR;
        if(expr[i]=='+' || expr[i]=='-')
        {
			if(expr[i+1]!='(' && expr[i+1]>'9' && expr[i+1]<'0' && expr[i+1]!='x')	return CHECKFUNC_NONUMBERAFTERSIGN;
        }
        if(expr[i]=='*' || expr[i]=='/')
        {
			if(i==0)																return CHECKFUNC_NONUMBERBEFORESIGN;
			if(expr[i+1]!='(' && expr[i+1]>'9' && expr[i+1]<'0' && expr[i+1]!='x')	return CHECKFUNC_NONUMBERAFTERSIGN;
            if(expr[i-1]!='(' && expr[i-1]>'9' && expr[i-1]<'0' && expr[i-1]!='x')	return CHECKFUNC_NONUMBERBEFORESIGN;
        }
        if(expr[i]=='.')
        {
			if(expr[i+1]<'0' && expr[i+1]>'9') return CHECKFUNC_DECIMALPOINT_ERROR;
            if(expr[i-1]<'0' && expr[i-1]>'9') return CHECKFUNC_DECIMALPOINT_ERROR;
        }
        if(expr[i]=='x')
        {
			if((expr[i+1]>'0' && expr[i+1]<'9') || expr[i+1]=='.') return CHECKFUNC_VARIBLEHASNOSIGN;
            if(i!=0)
				if((expr[i-1]>'0' && expr[i-1]<'9') || expr[i-1]=='.') return CHECKFUNC_VARIBLEHASNOSIGN;
        }
    }
    if(bracket!=0)
		return CHECKFUNC_BRACKET_ERROR;
    return CHECKFUNC_NO_ERROR;
}

BOOL CheckNum(double x)
{
	switch(fpclassify(x))
    {
	case FP_ZERO:return TRUE;
    case FP_NORMAL:return TRUE;
    default:return FALSE;
    }
}

void ReplaceAddSign(char* expr,char*out)
{
	memset(out,0,sizeof(char)*SGR_MAX_EXPR);
	char *k=expr;
	char *p=out;

	if(*expr!='+' && *expr!='-')
    {
		*p='+';p++;
        *p=*k;
    }

    while(*k!='')
    {
		if(*k!='+' && *k!='-')
        {
			*p=*k;p++;k++;
        }
        else
        {
			if(*(k-1)!='+' && *(k-1)!='-')*p=*k;
            if(*k=='-' && (*(k-1)=='+' || *(k-1)=='-'))*p=(*p=='+')?'-':'+';
            if(*(k+1)!='+' && *(k+1)!='-')p++;
            k++;
        }
    }
    p=out;
    while(*p!='')
    {
		if(*p>='9' && *p<='0' && *p!='.' && *(p+1)=='+')
			memmove(p+1,p+2,strlen(p+2)+1);
        p++;
    }
}

double GetResult_addsub(char* expr)
{
	double a=0,b=0;
    char* p=expr;
    if(*p=='+' ||*p=='-')p++;
    sscanf(p,"%lf",&a);
    if(*(p-1)=='-')a=-a;
    while(1)
    {
        while(*p!='+' && *p!='-')
        {
			p++;
            if(*p==0)break;
        }
        if(sscanf(++p,"%lf",&b)==0)break;
        switch(*(p-1))
        {
			case '+':a+=b;break;
			case '-':a-=b;break;
        }
    }
    return a;
}

double GetResult_timediv(char* expr)
{
	double a=0,b=0;
    char* p=expr;
    sscanf(p,"%lf",&a);
    while(1)
    {
        while(*p!='/' && *p!='*')
        {
			p++;
            if(*p==0)break;
        }
        if(sscanf(++p,"%lf",&b)<=0)break;
        switch(*(p-1))
        {
			case '*':a*=b;break;
			case '/':a/=b;break;
            case '-':
				switch(*(p-2))
                {
					case '*':a*=-b;break;
                    case '/':a/=-b;break;
                }
                break;
        }
    }
    return a;
}

void gettimedivexpr(const char*expr,char*out)
{
	for(int i=0;expr[i]!='';i++)
    {
		if(((expr[i]>='0' && expr[i]<='9') || expr[i]=='.' || expr[i]=='*' || expr[i]=='/') || (expr[i]=='-' && (expr[i-1]=='*' || expr[i-1]=='/')))out[i]=expr[i];
        else	break;
    }
}

double nonebracket_Translateexpression(char*expr)
{
	char RepAS[SGR_MAX_EXPR]={0};
    ReplaceAddSign(expr,RepAS);

    char*p=RepAS;
	char**p_sep;
    
    double a=0;
    double res[SGR_MAX_EXPR/2]={0.0};
    int n=0,i;
    
    char**sep=(char**)malloc(SGR_MAX_EXPR/2*sizeof(char*));

	for(i=0;i=1)decomp[strlen(decomp)]=expr[i];
		if(expr[i]=='(')
        {
			bracket++;
        }
        if(bracket==0)laststr[strlen(laststr)]=expr[i];
    }
    return nonebracket_Translateexpression(laststr);
}

double GetIndependent(char*func,char indep,double volue)
{
	char expr[SGR_MAX_EXPR]={''};
	for(int i=0;func[i]!='';i++)
    {
		if(func[i]==indep)
			sprintf(expr+strlen(expr),"%lf",volue);
        else
			expr[strlen(expr)]=func[i];
    }
    return Translateexpression(expr);
}


这是一个库的代码,具体就是表达式求值功能。

还有def文件(libtranslateexpression.def):

LIBRARY libtranslateexpression.dll
EXPORTS
	CheckFuncExpr		@1
	CheckNum			@2	
	Translateexpression	@3
	GetIndependent		@4

接下来是exe文件的代码:

#include 
#include 
#include 
#include 
#include 
#include 

#define HMENU_PAINT_FUNC 1

#define HMENU_func_TEXTFX 2
#define HMENU_func_EDITFX 3
#define HMENU_func_BUTTONOKAY 4
#define HMENU_func_BUTTONCANCEL 5

#define SGR_MAX_EXPR 1024

#define CHECKFUNC_NO_ERROR				0x00
#define CHECKFUNC_FOUND_TIMEADDBR		0x01
#define CHECKFUNC_FOUND_TIMESUBBR		0x02
#define CHECKFUNC_FOUND_DIVADDBR		0x03
#define CHECKFUNC_FOUND_DIVSUBBR		0x04
#define CHECKFUNC_BRACKET_ERROR			0x05
#define CHECKFUNC_NONUMBERAFTERSIGN		0x06
#define CHECKFUNC_NONUMBERBEFORESIGN	0x07
#define CHECKFUNC_DECIMALPOINT_ERROR	0x08
#define CHECKFUNC_VARIBLEHASNOSIGN		0x09

BOOL CheckFuncExpr(const char*expr);
BOOL CheckNum(double x);
double GetIndependent(char*func,char indep,double volue);

char functions[64][SGR_MAX_EXPR]={{0}};
int funcnum=0;

void paintfunc(int enlarge,HWND hwnd)
{
	static PAINTSTRUCT ps;
    static HPEN hpen;
    static RECT rect;
	static HDC hdc;
    hdc=BeginPaint(hwnd,&ps);
    hpen=CreatePen(PS_SOLID,1,RGB(255,0,0));
    GetClientRect(hwnd,&rect);
	SelectObject(hdc,hpen);
    
    static int i;
    static int j;
    static BOOL paint;
    static double y;

    for(j=0;j0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
        Sleep(50);
	}
	return msg.wParam;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow) 
{ 
    ShowWindow(GetForegroundWindow(),SW_HIDE);
    DestroyWindow(GetForegroundWindow());
    
	static TCHAR szAppName[]=TEXT("MathPaint");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;
    
    hInst=hInstance;

	wndclass.style=CS_HREDRAW|CS_VREDRAW;
	wndclass.lpfnWndProc=WndProc; 
	wndclass.cbClsExtra=0; 
	wndclass.cbWndExtra=0;
	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; 
	RegisterClass(&wndclass);
    
	Main_hwnd=hwnd=CreateWindow(szAppName,TEXT("MathPaint"),WS_MAXIMIZE|WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
	ShowWindow(hwnd,SW_SHOW);
	UpdateWindow(hwnd);

	while(GetMessage(&msg,hwnd,0,0)>0)
	{
		if(MAINWINDOW_RESP==FALSE && NEWWINDOWEXISTS==FALSE)
        {
			NEWWINDOWEXISTS=TRUE;
			pthread_create(&FuncInput_pth,NULL,(void*)CreateFuncInputWindow,FuncInput_hwnd);
        }
		TranslateMessage(&msg);
		DispatchMessage(&msg);
        Sleep(50);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	static HMENU hmenu_paint;
    static HMENU hmenu_paint_func;
    
    if(MAINWINDOW_RESP==TRUE)
	{
		EnableMenuItem(hmenu_paint,0,MF_BYPOSITION|MF_ENABLED);
		switch(message) 
		{ 
		case WM_CREATE: 
			GetWindowRect(hwnd,&MAINWINDOW_RECT);
            hmenu_paint=CreateMenu();
            hmenu_paint_func=CreateMenu();
            AppendMenu(hmenu_paint_func,MF_ENABLED|MF_STRING,HMENU_PAINT_FUNC,TEXT("绘制新函数..."));
            AppendMenu(hmenu_paint,MF_ENABLED|MF_STRING|MF_POPUP,(UINT_PTR)hmenu_paint_func,TEXT("作图(p)"));
            SetMenu(hwnd,hmenu_paint);
            return 0;
        case WM_COMMAND:
			switch(LOWORD(wParam))
            {
			case HMENU_PAINT_FUNC:
				MAINWINDOW_RESP=FALSE;
                EnableMenuItem(hmenu_paint,0,MF_BYPOSITION|MF_GRAYED);
				return 0;
            }
            return 0;
        case WM_PAINT:
			GetWindowRect(hwnd,&MAINWINDOW_RECT);
            break;
		}
    }
    
    else
    {
		switch(message)
        {
        case WM_CLOSE:
			return 0;
        case WM_MOVE:
			MoveWindow(hwnd,MAINWINDOW_RECT.left,MAINWINDOW_RECT.top,MAINWINDOW_RECT.right-MAINWINDOW_RECT.left,MAINWINDOW_RECT.bottom-MAINWINDOW_RECT.top,TRUE);
            return 0;
        }
    }
    switch(message)
    {
	case WM_PAINT:
		paintfunc(50,hwnd);
        break;
    }
    return DefWindowProc(hwnd,message,wParam,lParam);
}

LRESULT CALLBACK func_hEDITfx_WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	ImmAssociateContext(hwnd,NULL);
	switch(message)
    {
    case WM_CHAR:
		switch(wParam)
        {
		case '(':break;
        case ')':break;
        case 'x':break;
        case '+':break;
        case '-':break;
        case '*':break;
        case '/':break;
        case 8:break;
        default:
			if(wParam>='0' && wParam<='9')	break;
            else return 0;
        }
        break;
    case WM_PASTE:
		return 0;
    }
	return func_hEDITfx_old_WndProc(hwnd,message,wParam,lParam);
}

LRESULT CALLBACK func_WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	static RECT rect;
    static HWND hTEXTfx;
    static HWND hEDITfx;
    static HWND hBUTTONokay;
    static HWND hBUTTONcancel;
    
	static HFONT hfont;
    
    static int width;
    static int height;
    
    static char FuncExpr[SGR_MAX_EXPR];
	
	switch(message)
    {
    case WM_CREATE:
		GetClientRect(hwnd,&rect);
        
        width=rect.right-rect.left;
        height=rect.bottom-rect.top;
        
        hfont=CreateFont(-15,-7.5,0,0,400,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,TEXT("微软雅黑"));
        
		hTEXTfx=CreateWindow(TEXT("static"),TEXT("y="),WS_CHILD|WS_VISIBLE|SS_CENTERIMAGE|SS_LEFT,width/16,height/8,width/4,height/8,hwnd,(HMENU)HMENU_func_TEXTFX,hInst,NULL);
        hEDITfx=CreateWindow(TEXT("edit"),TEXT(""),WS_CHILD|WS_VISIBLE|WS_BORDER|ES_AUTOVSCROLL|ES_MULTILINE,width/16,height/4,width/2,height/2,hwnd,(HMENU)HMENU_func_EDITFX,hInst,NULL);
        
        hBUTTONcancel=CreateWindow(TEXT("button"),TEXT("取消"),WS_CHILD|WS_VISIBLE|WS_BORDER|BS_CENTER,width*11/16,height/8,width/4,height*3/10,hwnd,(HMENU)HMENU_func_BUTTONCANCEL,hInst,NULL);
        hBUTTONokay=CreateWindow(TEXT("button"),TEXT("确定"),WS_CHILD|WS_VISIBLE|WS_BORDER|BS_CENTER,width*11/16,height*23/40,width/4,height*3/10,hwnd,(HMENU)HMENU_func_BUTTONOKAY,hInst,NULL);

		SendMessage(hTEXTfx,WM_SETFONT,(WPARAM)hfont,(LPARAM)NULL);
        SendMessage(hEDITfx,WM_SETFONT,(WPARAM)hfont,(LPARAM)NULL);
		SendMessage(hBUTTONcancel,WM_SETFONT,(WPARAM)hfont,(LPARAM)NULL);
        SendMessage(hBUTTONokay,WM_SETFONT,(WPARAM)hfont,(LPARAM)NULL);
        
        func_hEDITfx_old_WndProc=(WNDPROC)SetWindowLongPtr(hEDITfx,GWLP_WNDPROC,(LONG)func_hEDITfx_WndProc);
        break;
    case WM_COMMAND:
		switch(LOWORD(wParam))
        {
		case HMENU_func_BUTTONCANCEL:
			DestroyWindow(hwnd);
            break;
        case HMENU_func_BUTTONOKAY:
			memset(FuncExpr,0,strlen(FuncExpr));
			GetWindowText(hEDITfx,FuncExpr,sizeof(FuncExpr));
            switch(CheckFuncExpr(FuncExpr))
            {
            case CHECKFUNC_FOUND_TIMEADDBR   :MessageBox(NULL,TEXT("乘号(*)后面不可以跟随加号(+)。"),TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            case CHECKFUNC_FOUND_TIMESUBBR   :MessageBox(NULL,TEXT("乘号(*)后面不可以跟随减号(-)。"),TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            case CHECKFUNC_FOUND_DIVADDBR    :MessageBox(NULL,TEXT("除号(/)后面不可以跟随加号(+)。"),TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
			case CHECKFUNC_FOUND_DIVSUBBR    :MessageBox(NULL,TEXT("除号(/)后面不可以跟随减号(-)。"),TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            case CHECKFUNC_BRACKET_ERROR     :MessageBox(NULL,TEXT("括号错误")					    ,TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            case CHECKFUNC_NonUMBERAFTERSIGN :MessageBox(NULL,TEXT("运算符后无数字")				,TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            case CHECKFUNC_NONUMBERBEFORESIGN:MessageBox(NULL,TEXT("运算符前无数字")				,TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            case CHECKFUNC_DECIMALPOINT_ERROR:MessageBox(NULL,TEXT("小数点错误")					,TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            case CHECKFUNC_VARIBLEHASNOSIGN	 :MessageBox(NULL,TEXT("自变量不能与数字直接连接")	    ,TEXT("函数语法错误"),MB_OK|MB_ICONERROR);return 0;
            }
            if(strlen(FuncExpr)!=0)	sprintf(functions[funcnum++],"%s",FuncExpr);
			DestroyWindow(hwnd);
            break;
        }
        break;
    case WM_DESTROY:
		NEWWINDOWEXISTS=FALSE;
		MAINWINDOW_RESP=TRUE;
        PostQuitMessage(0);
        InvalidateRect(Main_hwnd,NULL,TRUE);
        break;
    }
	return DefWindowProc(hwnd,message,wParam,lParam);
}


makefile.bat:

gcc -c -O3 libtranslateexpression.c
dllwrap --def libtranslateexpression.def -o libtranslateexpression.dll libtranslateexpression.o --output-lib libtranslateexpression.a
gcc mathpaint.c -o mathpaint.exe -lgdi32 -limm32 libtranslateexpression.dll
pause

大约花了一周左右,现在忙于学业还要上网课,也就做到这个程度。
接下来方向是准备实现ln log sin cos tan cot sec csc arcsin arccos arctan arcsec arccsc sqrt abs 根号 乘方。

感谢阅读 希望大家看一看代码而不是仅仅复制。
如有转载 请注明出处。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/457688.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号