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()

至此,登录对话框部分已经完成。下篇博客来完成主界面的部分功能…..

坚持原创技术分享,您的支持将鼓励我继续创作!
0%