项目需求:
设计并完成年会抽奖系统。要求能完成以下功能。
1.可以将抽奖人的编号和姓名录入到系统中。
2.可以从已经录入的抽奖人中,随机抽取指定数量的获奖人,奖项包含一、二、三等奖。
3.每个抽奖人,只能中奖一次。例如:张三抽中过一次三等奖之后,不可以再去抽中一、二等奖。
4.能够正确设计菜单以及用户的输入流程。正确设计存储程序相关信息的数据结构。
5.能够对所有输入的信息进行正确的校验检查,如果输入的信息不合法,提示用户重新进行输入。
6.能够将抽奖人的编号和姓名保存,并在下次启动应用程序时读取上次保存的数据。可以通过文件进行存储,也可以通过其他方式。
7.能够通过文件将抽奖人信息导入到系统中。
选择easyx作为图形库做GUI,尽管提供的函数并不多,对于这个类型的系统不是很适用,但是胜在易于安装,建议以vc为基础进行开发(dev不是太稳定)。
运行窗口如下:
代码如下:
//Copyright©CYJ&QS,2022
#include <iostream>
#include<graphics.h>
#include<conio.h>
#include<stdio.h>
#include<easyx.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<math.h>
#define LEN 100
#define FIRST 100
#define SECOND 100
#define THIRD 100
using namespace std;
typedef struct data //定义结构体
{
int id; //编号
char name[10]; //姓名
int t; //t=0为未获奖,t!=0为已获奖
}Member;
typedef struct SequenceList //定义顺序表
{
Member data[LEN];
int length;
}SqList;
void DisplayList( SqList * L );
void Save_File( SqList * L );
void AddMember( SqList * L );
void Lottery( SqList * L, int prize, int grade );
void LoadData( SqList *L );
void RecrodWinner( SqList *L );
int ShowNum( int x, int y);
void button(int x,int y,int w,int h,TCHAR * text);
int main()
{
bool first = false;
bool second = false;
bool third = false;
char c;
int First=0;
int Second=0;
int Third=0;
//初始化成员顺序表
SqList *L;
L = (SqList *)malloc(sizeof(SqList));
L->length=0;
//从本地加载成员
LoadData( L );
//设置可视化窗口
initgraph(640, 480); // 创建绘图窗口,大小为 640x480 像素
setbkcolor(BLACK); //窗口背景色
TCHAR s[50] = "添加候选人";
TCHAR s1[50] = "开始抽奖";
TCHAR s2[50] = "一等奖";
TCHAR s3[50] = "二等奖";
TCHAR s4[50] = "三等奖";
TCHAR s5[50] = "返回主菜单";
TCHAR s6[50] = "退出程序";
TCHAR s7[50] = "获奖者名单";
DisplayList( L );
outtextxy(400, 400, "按下回车以继续");
system("pause");
Menu:
cleardevice();
flushmessage(EM_MOUSE);
button(220,50,170,50,s);
button(220, 150, 170, 50, s1);
button(220, 400, 170, 50, s6);
button(220, 250, 170, 50, s7);
ExMessage msg;
while (true)
{
if (peekmessage(&msg, EM_MOUSE))
{
switch (msg.message)
{
case WM_LBUTTONDOWN:
if (msg.x >= 220 && msg.x <= 220 + 170 && msg.y >= 50 && msg.y <= 50 + 50)//检测鼠标的位置 是否满足条件
{
AddMember( L ); //跳转到补充抽象人信息的页面
goto Menu;
}
if (msg.x >= 220 && msg.x <= 220 + 170 && msg.y >= 150 && msg.y <= 150 + 50)
{
Grade:
flushmessage(EM_MOUSE);
string str1;
cleardevice();
button(220,100,170,40,s2);
button(220,200,170,40,s3);
button(220,300,170,40,s4);
button(400,400,170,40,s5);
while (true)
{
if (peekmessage(&msg, EM_MOUSE))
{
switch (msg.message)
{
case WM_LBUTTONDOWN:
if (msg.x >= 220 && msg.x <= 220 + 170 && msg.y >= 100 && msg.y <= 100 + 40)//检测鼠标的位置 是否满足条件
{
if(first){
cleardevice();
outtextxy(100, 150, "一等奖已抽完!\n");
outtextxy(100, 200, "按下回车以继续\n");
system("pause");
goto Grade;
}
cleardevice();
First:
cleardevice();
outtextxy(100, 150, "请输入一等奖个数:\n");
rectangle(280, 140, 480, 180);
int num = ShowNum(290, 150);
if(num>L->length-First-Second-Third)
{
HWND hWnd = GetHWnd();
SetWindowText(hWnd,"警告");
MessageBox(hWnd, "输入人数过多,请重新输入!", "警告", MB_OKCANCEL);
goto First;
}
Lottery( L, num, 1 );
First = num;
first = true;
goto Grade;
}
else if (msg.x >= 220 && msg.x <= 220 + 170 && msg.y >= 200 && msg.y <= 200 + 40)//检测鼠标的位置 是否满足条件
{
if(second){
cleardevice();
outtextxy(100, 150, "二等奖已抽完!\n");
outtextxy(100, 200, "按下回车以继续\n");
system("pause");
goto Grade;
}
cleardevice();
Second:
cleardevice();
outtextxy(100, 150, "请输入二等奖个数:\n");
rectangle(280, 140, 480, 180);
int num = ShowNum(290, 150);
if(num>L->length-First-Second-Third)
{
HWND hWnd = GetHWnd();
SetWindowText(hWnd,"警告");
MessageBox(hWnd, "输入人数过多,请重新输入!", "警告", MB_OKCANCEL);
goto Second;
}
Lottery( L, num, 2 );
Second = num;
second = true;
goto Grade;
}
else if (msg.x >= 220 && msg.x <= 220 + 170 && msg.y >= 300 && msg.y <= 300 + 40)//检测鼠标的位置 是否满足条件
{
if(third){
cleardevice();
outtextxy(100, 150, "三等奖已抽完!\n");
outtextxy(100, 200, "按下回车以继续\n");
system("pause");
goto Grade;
}
cleardevice();
Third:
cleardevice();
outtextxy(100, 150, "请输入三等奖个数:\n");
rectangle(280, 140, 480, 180);
int num = ShowNum(290, 150);
if(num>L->length-First-Second-Third)
{
HWND hWnd = GetHWnd();
SetWindowText(hWnd,"警告");
MessageBox(hWnd, "输入人数过多,请重新输入!", "警告", MB_OKCANCEL);
goto Third;
}
Lottery( L, num, 3 );
Third = num;
third = true;
goto Grade;
}
else if (msg.x >= 400 && msg.x <= 400 + 170 && msg.y >= 400 && msg.y <= 400 + 40)//检测鼠标的位置 是否满足条件
{
if(first == second == third == true)
cleardevice();
goto Menu;
}
}
}
}
}
if(msg.x >= 220 && msg.x <= 220 + 170 && msg.y >= 250 && msg.y <= 250 + 50)
{
cleardevice();
RecrodWinner( L );
outtextxy(400, 400, "按下回车以继续\n");
system("pause");
cleardevice();
goto Menu;
}
if(msg.x >= 220 && msg.x <= 220 + 170 && msg.y >= 400 && msg.y <= 400 + 50)
{
exit(0);
}
}
}
}
Save_File(L);
return 0;
}
void button(int x,int y,int w,int h,TCHAR * text)
{
setbkmode(TRANSPARENT); //设置当前设备图案填充和文字输出时的背景模式为透明
setfillcolor(RED); //设置当前设备填充颜色:红
fillroundrect(x,y,x+w,y+h,10,10); //绘制按钮区域
TCHAR s1[] = "黑体";
settextstyle(20,0,s1); //设置字体样式
//settextcolor(BLACK);
TCHAR s[50] = "hello";
int tx = x + (w - textwidth(text)) / 2;
int ty = y + (h - textheight(text)) / 2;
outtextxy(tx, ty, text);
}
void LoadData( SqList *L ) //加载本地文件
{
//调入上次保存的人员数据
FILE *file=fopen("D:\\抽奖名单.txt","r+"); //打开文件并让file指向文件 (读取时需注意文件编码格式)
if(file==NULL)
{
fprintf(stderr,"文件打开失败.\n");
exit(EXIT_FAILURE);
}
char row[20];
char *token;
int i=0;
if(fgets(row,20,file)!=NULL) //以行读取,存在row内。
{
do
{
sscanf(row,"%d%s",&L->data[L->length].id,L->data[L->length].name);
L->data[L->length].t=0; //把数据存入结构体数组
printf("%d\t%s\t%d\n",L->data[L->length].id, L->data[L->length].name, L->data[L->length].t);
L->length++;
}
while(fgets(row,20,file)!=NULL);
}
fclose(file); //关闭文件
}
void DisplayList( SqList *L ) //打印所有候选人
{
int idx;
int j;
TCHAR str[16];//字符数组
outtextxy(100, 50, "名单导入成功!");
outtextxy(100, 100, "序号 姓名");
outtextxy(100, 120, "-------------------------------------------------------------");
for ( idx=0, j=180 ; idx < L->length ; idx++, j+=20 ) //遍历所有成员并打印
{
sprintf(str, "%d", L->data[idx].id);
outtextxy(100, j, str);
outtextxy(150, j, L->data[idx].name);
}
}
void Save_File( SqList * L ) //将内存中的数据写入本地
{
int i;
FILE *fp;
fp = fopen("D:\\抽奖名单.txt","w");
for(i=0 ; i<L->length ; i++)
{
fprintf(fp, "%d %s\n", L->data[i].id, L->data[i].name);
}
fclose(fp);
}
void Lottery( SqList * L, int prize, int grade ) //进行抽奖
{
if(prize)
srand((unsigned int)time(NULL));
outtextxy(100, 100, grade);
int j;
int i;
struct data a;
cleardevice();
outtextxy(100, 50, "获奖者为:\n");
for(j=0, i=100 ; j<prize ; j++)
{
int x;
x=rand()%L->length;
if(L->data[x].t==0)
{
outtextxy(100, i, L->data[x].name);
//printf("%s ",L->data[x].name);
L->data[x].t=grade;
i+=50;
}
else
{
prize++;
}
}
outtextxy(100, 400, "按下回车以继续\n");
system("pause");
}
int ShowNum( int x, int y)
{
string str1;
char c;
while ((c = _getch()) != '\r') //如果没按回车,接收一个c
{ //getch()头文件 conio.h
if (c == '\b') //如果c是退格符,str1删掉一个
str1 = str1.substr(0, str1.size() - 1);
else
str1 += (int)c;
outtextxy(x, y, str1.c_str());
}
return atoi(str1.c_str());
}
void AddMember( SqList * L ) //添加候选人
{
int i;
struct data a;
ExMessage msg;
Wrong:
cleardevice();
outtextxy(100, 50, "请输入人员信息\n");
rectangle(165, 90, 490, 130);
rectangle(165, 190, 490, 230);
outtextxy(100, 100, "编号:");
outtextxy(100, 200, "姓名:");
string str1; //str1用来放c的总内容 str2每次存放“显示内容:”+str1,方便输出
char c; //定义字符c接收键盘输入
//接收键盘数据 (序号)
while ((c = _getch()) != '\r') //如果没按回车,接收一个c
{ //getch()头文件 conio.h
if (c == '\b') //如果c是退格符,str1删掉一个
str1 = str1.substr(0, str1.size() - 1);
else
str1 += (int)c;
outtextxy(175, 100, str1.c_str()); //在窗口坐标为(100,100)的地方开始输出str2的内容
}
a.id = atoi(str1.c_str()); //赋给临时存储的结构体
//检验是否含负数或字母
int t=0;
for (i = 0;i < str1.size();i++)
{
if (str1.at(i) == '-' && str1.size() > 1) // 有可能出现负数
continue;
if (str1.at(i) > '9' || str1.at(i) < '0') // 判断是否为数字
{
outtextxy(100, 150, "输入格式有误,按下回车以重新输入!\n");
system("pause");
goto Wrong;
}
}
//检验是否重复
t = i = 0;
for( i=0 ; i<L->length ; i++ )
{
if(a.id == L->data[i].id)
{
outtextxy(100, 150, "该序号已存在,按回车以重新输入!\n");
system("pause");
goto Wrong;
break;
}
}
outtextxy(100, 150, "序号录入成功,请输入姓名\n");
//接收键盘数据(姓名)
string str2;
while ((c = _getch()) != '\r')
{
if (c == '\b')
str2 = str2.substr(0, str2.size() - 1);
else
str2 += (int)c;
outtextxy(175, 200, str2.c_str());
}
strcpy(a.name, str2.c_str());
outtextxy(100, 350, "录入成功\n");
outtextxy(100, 400, "按下回车以继续\n");
system("pause");
L->data[L->length] = a; // 将 a 的值赋给顺序表末位
L->length++;
Save_File(L);
}
void RecrodWinner( SqList *L ) //打印获奖者
{
int i,j;
int one=0, two=0, three=0;
Member third[THIRD]; //用三个结构体数组来记录各奖项的获奖者信息 (用结构体中的 t 来判断奖项等级)
Member second[SECOND]; //
Member first[FIRST]; //
for(i=0 ; i<L->length ; i++)
{
switch(L->data[i].t)
{
case 1:
first[one] = L->data[i];
one++;
break;
case 2:
second[two] = L->data[i];
two++;
break;
case 3:
third[three] = L->data[i];
three++;
break;
}
}
outtextxy(100, 50, "获奖者名单\n");
outtextxy(100, 150, "一等奖\n");
for( i=0,j=200 ; i<one ; i++, j+=50)
{
outtextxy(j, 150, first[i].name);
}
outtextxy(100, 200, "二等奖\n");
for( i=0,j=200 ; i<two ; i++,j+=50)
{
outtextxy(j, 200, second[i].name);
}
outtextxy(100, 250, "三等奖\n");
for( i=0,j=200 ; i<three ; i++,j+=50)
{
outtextxy(j, 250, third[i].name);
}
}