windows API 开发飞机订票系统(二)

呐,上回书说到写代码过程中遇到不少问题,在这里就一点一点慢慢道来吧。

首先,定义的结构体、全局变量和函数如下:

// Flight.c : 定义应用程序的入口点。
//
#include "stdafx.h"

//订单
typedef struct OrderForm{
	TCHAR IdNum[32];									//订单用户身份证号
	int Order_Number;									//订单号
	int Tickets_Num;									//订票数量
	TCHAR Flight_Number[16];							//航班号
	TCHAR Departure[16];								//出发地
	TCHAR Destination[16];								//目的地
	TCHAR Date[16];										//出发日期
	TCHAR TakeOff_Time[16];								//起飞时间
	TCHAR Landing_Time[16];								//降落时间
	struct OrderForm *Next;								//所有订单链表next
	struct OrderForm *psgNext;							//用户订单链表next
}OrderForm;

//乘客订单链表
typedef struct PsgOrderLink{
	int OrderNum;										//订单数目
	OrderForm *head;									//头结点
	OrderForm *tail;									//尾结点
}PsgOrderLink;

//所有订单列表
typedef struct AllOrderLink{
	int AllOrderNum;									//所有订单数目
	OrderForm *head;									//头结点
	OrderForm *tail;									//尾结点
}AllOrderLink;

//乘客
typedef struct Passenger{
	TCHAR Name[16];								        //姓名
	TCHAR IdNum[32];									//身份证号码
	TCHAR PassWord[32];							    	//密码
	int TicketNum;										//订单数目
	PsgOrderLink OrderLink;								//用户所有订单
	struct Passenger *Next;
}Passenger;

//乘客链表
typedef struct PsgLinkList{
	int PsgNum;											//账户数量
	Passenger *head;									//头结点
	Passenger *tail;									//尾结点
}PsgLinkList;

//航班
typedef struct Flight{
	double Fare;										//票价
	int Seat_Number;									//座位数
	int Vacant_Seat;									//空余座位数
	TCHAR Discount[16];									//折扣
	TCHAR Flight_Number[16];							//航班号
	TCHAR Departure[16];								//出发地
	TCHAR Destination[16];								//目的地
	TCHAR Date[16];										//出发日期
	TCHAR TakeOff_Time[16];								//起飞时间
	TCHAR Landing_Time[16];								//降落时间
	struct Flight *Next;
}Flight;

//航班链表
typedef struct FlightLinkList{
	Flight *head;										//头结点
	Flight *tail;										//尾结点
	int Flight_Number;									//航班数目
}FilghtLinkList;


// 全局变量: 
HICON hIcon;
HINSTANCE hInst;										//当前实例
static TCHAR szBuffer[256];								//缓冲区
static PsgLinkList psglink;								//所有账户_链表
static Passenger *passenger;							//登陆账户信息
static AllOrderLink allorder;							//所有订单_链表
static FilghtLinkList flightlink;						//所有航班_链表



//函数声明
BOOL AccountLogIn(HWND);										//账户登陆
BOOL AccountRegister(HWND);										//注册账户
BOOL ReadFlightData(HWND);										//读入航班信息
BOOL ReadAccountData(HWND);										//读入账户资料
BOOL ReadAccountOrder(HWND,Passenger*);							//读入所有订单、账户订单
BOOL SearchFlight(HWND);										//查询航班
BOOL BookTickets(HWND);											//订票
BOOL _Book_Tickets(HWND,Flight*,int);							//订票
BOOL Recommend(HWND,Flight*,int);								//航班建议
BOOL ReturnTickets(HWND);										//退票
BOOL EntryFlight(HWND);											//录入航班
BOOL ModifyFlight(HWND);										//修改航班信息
BOOL PrintFlight(HWND, Flight*);								//输出航班信息
BOOL WriteFlightData(HWND);										//保存航班信息
BOOL WriteAccountData(HWND);									//保存账户资料
BOOL WriteOrderData(HWND);										//保存订单信息
BOOL CALLBACK LogInDlgProc(HWND, UINT, WPARAM, LPARAM);			//登陆窗口窗口过程
BOOL CALLBACK MainDlgProc(HWND, UINT, WPARAM, LPARAM);			//主界面窗口过程
BOOL CALLBACK NameDlgProc(HWND, UINT, WPARAM, LPARAM);			//获取新注册用户姓名窗口过程
BOOL CALLBACK FlightNumDlgProc(HWND, UINT, WPARAM, LPARAM);		//获取用户输入机票数量窗口过程
BOOL CALLBACK EntryFlightProc(HWND, UINT, WPARAM, LPARAM);		//录入航班窗口过程
BOOL CALLBACK ModifyFlightProc(HWND, UINT, WPARAM, LPARAM);		//修改航班信息窗口过程
主函数如下:

//主函数
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int iCmdShow)
{			
	
	hInst = hInstance;
	InitCommonControls();
	hIcon=LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
	return DialogBox(hInst, MAKEINTRESOURCE(IDD_LOGINDLG), NULL, (DLGPROC)LogInDlgProc);
}//WinMain

登陆界面窗口过程:

//登陆窗口_窗口过程
BOOL CALLBACK LogInDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{
	switch (uMsg)
	{
		//WM_INITDIALOG是当其对话框和子控件全部创建完毕,将要显示内容的时候发送的消息
		//因此可以在WM_INITDIALOG消息响应函数中添加对编辑框控件的初始化和修改
		case WM_INITDIALOG:  
		{
			if (hIcon)
				SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
			ReadAccountData(hwndDlg);					//登陆对话框初始化时读入账户资料
			ReadFlightData(hwndDlg);					//登陆对话框初始化时读入航班信息
		}//WM_INITDIALOG
		return TRUE;

		case WM_CLOSE:
		{
			EndDialog(hwndDlg, 0);
		}//WM_CLOSE
		return TRUE;

		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
			case IDC_LOGIN:
				AccountLogIn(hwndDlg);					//登陆
				break;
			case IDC_REGISTER:
				AccountRegister(hwndDlg);				//注册
				break; 
			}//switch
		}//WM_COMMAND
		return TRUE;

	}//switch
	return FALSE;
}//LogInDlgProc()

我在对话框初始化时调用了下述函数来加载程序标题栏的图标:

 

if (hIcon)
	SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);

接下来就该读取文件了。

那么问题就来了,挖掘机...额,不对,应该怎么读入账户资料和航班信息?

我把账户资料和航班信息储存在了.txt文件里,每一行是结构体的一个成员,一个一个读入。

两个读入函数代码如下:

//读入账户信息
BOOL ReadAccountData(HWND hwndDlg){						
	
	FILE *fp;

	passenger = (Passenger *)malloc(sizeof(Passenger));										//为登录账户分配内存
	if (!passenger){
		MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);
		EndDialog(hwndDlg, 0);
		return FALSE;
	}//if
	 
	psglink.head = NULL;
	psglink.tail = NULL;
	psglink.PsgNum = 0;

	if ((fp = fopen(".\\AccountData.txt", "r+")) == NULL){		//打开文件
		MessageBox(hwndDlg, TEXT("账户文件读入错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);
		EndDialog(hwndDlg, 0);
	}//if		

	while (!feof(fp)){
		Passenger *p = (Passenger *)malloc(sizeof(Passenger));
		if (!p){
			MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);
			EndDialog(hwndDlg, 0);
			return FALSE;
		}//if

		//读入账户姓名、身份证号、密码
		if (fscanf(fp, "%s%s%s", p->Name, p->IdNum, p->PassWord) == EOF){
			free(p); break;
		}

		p->Next = NULL;
		if (psglink.head == NULL)						//读入第一个账户信息时,头、尾结点均指向p
			psglink.head = p;
		else
			psglink.tail->Next = p;						//否则,尾结点Next指向p
		psglink.tail = p;								//尾结点指向p
		psglink.PsgNum++;								//已注册账户个数

	}//while
	fclose(fp);											//关闭文件
	return TRUE;
}//ReadAccountData(HWND)


//读入航班信息
BOOL ReadFlightData(HWND hwndDlg){						

	int flag = 0;
	FILE *fp;

	flightlink.Flight_Number = 0;
	flightlink.head = NULL;
	flightlink.tail = NULL;

	if ((fp = fopen(".\\FlightData.txt", "r")) == NULL){		//打开文件
		MessageBox(hwndDlg, TEXT("账户文件读入错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);
		EndDialog(hwndDlg, 0);
	}//if

	while (!feof(fp)){
		Flight *p = (Flight *)malloc(sizeof(Flight));
		if (!p){
			MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);
			EndDialog(hwndDlg, 0);
			return FALSE;
		}//if
		//读入航班信息
		if (fscanf(fp, "%s%lf%s%d%d%s%s%s%s%s",
			p->Flight_Number,
			&p->Fare,
			p->Discount,
			&p->Seat_Number,
			&p->Vacant_Seat,
			p->Departure,
			p->Destination,
			p->Date,
			p->TakeOff_Time,
			p->Landing_Time) == EOF)
		{
			free(p);
			break;
		}
		p->Next = NULL;
		if (flightlink.head == NULL)					//添加至链表
			flightlink.head = p; 
		else
			flightlink.tail->Next = p;
		flightlink.tail = p;
		flightlink.Flight_Number++;

	}//while
	fclose(fp);											//关闭文件
	return TRUE;
}//ReadFlightData()

编译运行的时候会报错,报错信息是大体是说fopen()函数不安全,根据提示信息,解决办法是在文件头部做如下定义:

#define _CRT_SECURE_NO_WARNINGS

或者是在项目->属性->c/c++->预处理器->预处理器定义,后面加上_CRT_SECURE_NO_WARNINGS就行了。

结下来又遇到问题了:程序退出把数据写入txt文件时每行末尾都会有一个\n,读入数据的时候用的是feof()函数,而feof()返回的其实是"最后一次读操作的内容",与数据库中的eof()不同,eof()读取的是当前指针位置。因此在读到文件末尾的时候,程序会多执行一次循环,为了防止这种情况,我采取的是检查fscanf()返回值的方法,在此以读入账户资料时为例:

//读入账户姓名、身份证号、密码
if (fscanf(fp, "%s%s%s", p->Name, p->IdNum, p->PassWord) == EOF){
<span style="white-space:pre">	</span>free(p); break;
}
下面继续贴函数代码:
//登陆用户验证
BOOL AccountLogIn(HWND hwndDlg){						
	
	int flag = 0;																//flag!=0则该用户已注册,flag==0则该用户尚未注册
	Passenger *p;

	GetDlgItemText(hwndDlg, IDC_IDEDIT, passenger->IdNum, 256);					//获取用户输入ID
	GetDlgItemText(hwndDlg, IDC_PSWEDIT, passenger->PassWord, 256);				//获取用户输入密码
	
	p = psglink.head;
	while (p){																	//在用户链表查找登陆用户ID
		if (!lstrcmp(passenger->IdNum, p->IdNum)){		
			flag++;																//该用户已注册
			if (!lstrcmp(passenger->PassWord, p->PassWord)){					//密码匹配,登陆成功
				lstrcpy(passenger->Name, p->Name);
				MessageBox(hwndDlg, TEXT("登陆成功,单击确定进入程序主界面"), TEXT("登陆成功"), MB_OK | MB_ICONINFORMATION);
				break;
			}//if
			else{																//密码错误,退出循环
				MessageBox(hwndDlg, TEXT("密码错误,请重新输入"), TEXT("密码错误"), MB_OK | MB_ICONERROR);
				return FALSE;
			}//else
		}//if
		p = p->Next;
	}//while
	if (!flag){																	//用户尚未注册
		if (lstrlen(passenger->PassWord)==0)
			MessageBox(hwndDlg, TEXT("请输入密码!"), TEXT("信息"), MB_OK | MB_ICONINFORMATION);
		else
			MessageBox(hwndDlg, TEXT("该账户尚未注册,请先注册"), TEXT("信息"), MB_OK | MB_ICONINFORMATION);
	}//if
	else{																		//关闭登陆界面,弹出主界面
		EndDialog(hwndDlg, TRUE);
		if (ReadAccountOrder(hwndDlg, passenger))								//读取用户订单
			DialogBox(hInst, MAKEINTRESOURCE(IDD_MAINDLG), NULL, (DLGPROC)MainDlgProc);
	}//else

	return TRUE;
}//AccountLogIn(HWND)
//用户注册
BOOL AccountRegister(HWND hwndDlg){

	GetDlgItemText(hwndDlg, IDC_IDEDIT, passenger->IdNum, 256);			//获取用户输入ID
	GetDlgItemText(hwndDlg, IDC_PSWEDIT, passenger->PassWord, 256);		//获取用户输入密码

	if (lstrlen(passenger->PassWord) == 0){
		MessageBox(hwndDlg, TEXT("请输入注册用户密码!"), TEXT("信息"), MB_OK | MB_ICONINFORMATION);
		return FALSE;
	}

	DialogBox(hInst, MAKEINTRESOURCE(IDD_NAMEDLG), NULL, (DLGPROC)NameDlgProc);	//获取新注册用户姓名

	if (lstrlen(passenger->Name) == 0)
		return FALSE;

	passenger->Next = NULL;

	if (psglink.head == NULL)										//该注册账户为第一个账户时,头、尾结点均指向passenger
		psglink.head = passenger;
	else
		psglink.tail->Next = passenger;								//将新注册账户资料添加至账户链表
	psglink.tail = passenger;										//链表尾指针指向链表尾
	psglink.PsgNum++;												//注册用户数目加1
	passenger->TicketNum = 0;							
	passenger->OrderLink.head = NULL;								//乘客订单链表初始化
	passenger->OrderLink.tail = NULL;
	passenger->OrderLink.OrderNum = 0;

	MessageBox(hwndDlg, TEXT("注册成功!请单击确定进入主界面"), TEXT("注册成功"), MB_OK | MB_ICONINFORMATION);
	
	EndDialog(hwndDlg, TRUE);													//关闭登陆界面

	DialogBox(hInst, MAKEINTRESOURCE(IDD_MAINDLG), NULL, (DLGPROC)MainDlgProc); //弹出主界面

	return TRUE;
}//AccountRegister(HWND)

//获取新注册用户姓名_窗口过程
BOOL CALLBACK NameDlgProc(HWND hNameDlg, UINT uMsg, WPARAM wParam, LPARAM lParam){

	switch (uMsg)
	{
	case WM_INITDIALOG:
	{
		if (hIcon)
			SendMessage(hNameDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
	}
	return TRUE;

	case WM_CLOSE:
	{
		wsprintf(passenger->IdNum, TEXT("\0"));
		EndDialog(hNameDlg, 0);
	}//WM_CLOSE
	return TRUE;

	case WM_COMMAND:
	{
		switch (LOWORD(wParam))
		{
		case IDC_GETNAMEOK:
		{
			GetDlgItemText(hNameDlg, IDC_GETNAME, passenger->Name, 16);
			EndDialog(hNameDlg, TRUE);
			break;
		}//GETNAME
		case IDC_GETNAMECANCEL:
		{
			wsprintf(passenger->IdNum, TEXT("\0"));
			EndDialog(hNameDlg, TRUE);
			break;
		}//GETNAMECANCEL

		}//stitch

	}//WM_COMMAND
	return TRUE;

	}//stitch

	return FALSE;

}//NameDlgProc()
//读取订单信息
BOOL ReadAccountOrder(HWND hwndDlg, Passenger *passenger){	

	FILE *fp;
	allorder.AllOrderNum = 0;							//订单链表初始化
	allorder.head = NULL;								
	allorder.tail = NULL;
	passenger->TicketNum = 0;							//乘客订单链表初始化
	passenger->OrderLink.head = NULL;
	passenger->OrderLink.tail = NULL;
	passenger->OrderLink.OrderNum = 0;

	if ((fp = fopen(".\\OrderForm.txt", "r")) == NULL){	//打开存储订单信息文件
		MessageBox(hwndDlg, TEXT("订单文件读入错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);
		return FALSE;
	}

	while (!feof(fp)){
		OrderForm *p = (OrderForm *)malloc(sizeof(OrderForm));
		if (!p){
			MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);
			EndDialog(hwndDlg, 0);
			return FALSE;
		}//if
		if (fscanf(fp, "%s%d%d%s%s%s%s%s%s",
			p->IdNum,									//读取订单信息
			&p->Order_Number,
			&p->Tickets_Num,
			p->Flight_Number,
			p->Departure,
			p->Destination,
			p->Date,
			p->TakeOff_Time,
			p->Landing_Time) == EOF)
		{
			free(p);
			break;
		}
		p->Next = NULL;
		p->psgNext = NULL;

		if (allorder.head == NULL){						//将结点添至订单链表末尾
			allorder.head = p; 
		}
		else
			allorder.tail->Next = p;
		allorder.tail = p;
		allorder.AllOrderNum++;							//订单数目增加

		if (!lstrcmp(p->IdNum, passenger->IdNum)){		//若该订单为当前登录账户订单,则添至用户订单链表末尾
			if (passenger->OrderLink.head == NULL){		//将结点添至用户订单链表末尾
				passenger->OrderLink.head = p;
			}
			else
				passenger->OrderLink.tail->psgNext = p;
			passenger->OrderLink.tail = p;
			passenger->TicketNum += p->Tickets_Num;		
			passenger->OrderLink.OrderNum++;			//订单数目增加
		}//if
	}//while
	fclose(fp);
	return TRUE;
}//ReadAccountOrder()

至此,登录对话框部分已经完成。下篇博客来完成主界面的部分功能.....
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值