新建一个mfc项目,名称任意,在此以myapp_1命名,如图所示
点击完成,至此应用创建完毕。
这一步的功能是,点击开始考试按钮,时间开始倒计时
首先给开始考试按钮修改一下ID,在其属性界面更改ID,如图更改成IDC_BEGIN_TEST,主要是为了更好辨认
给这个按钮添加一个与之关联的变量
选中这个按钮右键->添加变量 变量名:btn_begin_test
双击按钮添加处理程序,定位到这段代码
void Cmyapp_1Dlg::OnBnClickedBeginTest()
{
// TODO: 在此添加控件通知处理程序代码
}
添加以下几行代码
//这里需要判断用户输入的准考证信息,身份证信息是否合法,暂时先省略
btn_begin_test.EnableWindow(FALSE);//让按钮无法点击
SetTimer(1,1000,NULL);//设置一个定时器,这里有三个参数,第一个参数:定时器id,第二个参数:时间间隔,第三个参数:需要触发的函数,当值为NULL交给系统处理
最后应该是这个样子的
void Cmyapp_1Dlg::OnBnClickedBeginTest()
{
// TODO: 在此添加控件通知处理程序代码
//这里需要判断用户输入的准考证信息,身份证信息是否合法,暂时先省略
btn_begin_test.EnableWindow(FALSE);//让按钮无法点击
SetTimer(1,1000,NULL);//设置一个定时器,这里有三个参数,第一个参数:定时器id,第二个参数:时间间隔,第三个参数:需要触发的函数,当值为NULL交给系统处理
}
然后复写一个监听时间变化消息的函数
右键CmyApp_1Dlg->类向导->消息 添加 WM_TIMER
添加处理程序,应该多出一个方法
添加一个记录时间的变量,time_sum
添加一个函数 getFormatTime, 参数 int,返回值CString
应该多一个方法,类似于
CString Cmyapp_1Dlg::getFormatTime(int time_left)
{
return CString();
}
复写这个方法
CString Cmyapp_1Dlg::getFormatTime(int time_left)
{
int sum = 15*60 - time_left;
int second = sum % 60;
int minute = sum / 60;
CString t;
t.Format(L"%d分%d秒",minute,second);
return t;
}
并且添加变量 tv_time_left,类别选Value
复写OnTimer函数
void Cmyapp_1Dlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDialogEx::OnTimer(nIDEvent);
}
最后应该是:
void Cmyapp_1Dlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
UpdateData(TRUE);
tv_time_left = getFormatTime(++time_sum);
UpdateData(FALSE);
CDialogEx::OnTimer(nIDEvent);
}
现在运行程序,点击开始考试,就能开始倒计时了,倒计时功能至此完成,附图:
如果不行,请检查以上步骤。
开发目标:准考证号为11位数字,身份证号为18位,还应该判断年龄,如果不符合则提示用户修改。
为准考证的输入框,以及身份证的输入框添加变量,et_zkz , et_sfz 如图(注意 类别为Value 不是 Control):
设置准考证只能输入数字:
准考证输入框->属性->Number = True
现在我们添加两个函数来判断:
int check_zkz(CString zkz) //返回值为0 为正常,下同
int check_sfz(CString sfz)//同上
添加check_zkz(CString zkz)函数的过程:
类视图->Cmyapp_1Dlg->添加函数
添加完应该是这样的
int Cmyapp_1Dlg::check_zkz(CString zkz)
{
return 0;
}
复写这个函数,判断准考证位数是不是11位,不是返回1,是返回0
int Cmyapp_1Dlg::check_zkz(CString zkz)
{
int length = zkz.GetLength();
if(length == 11)
return 0;
return 1;
}
在点击“开始考试”按钮时调用准考证判断函数
修改前的函数
void Cmyapp_1Dlg::OnBnClickedBeginTest()
{
// TODO: 在此添加控件通知处理程序代码
//这里需要判断用户输入的准考证信息,身份证信息是否合法,暂时先省略
btn_begin_test.EnableWindow(FALSE);//让按钮无法点击
SetTimer(1,1000,NULL);//设置一个定时器,这里有三个参数,第一个参数:定时器id,第二个参数:时间间隔,第三个参数:需要触发的函数,当值为NULL交给系统处理
}
可以把之前暂时省略的判断代码加上去
void Cmyapp_1Dlg::OnBnClickedBeginTest()
{
// TODO: 在此添加控件通知处理程序代码
//这里需要判断用户输入的准考证信息,身份证信息是否合法,暂时先省略
//判断用户的准考证号
UpdateData(TRUE);
int zkz_result = check_zkz(et_zkz);
if (zkz_result == 1)
{
MessageBox(_T("准考证为11位数字"));
return;
}
btn_begin_test.EnableWindow(FALSE);//让按钮无法点击
SetTimer(1,1000,NULL);//设置一个定时器,这里有三个参数,第一个参数:定时器id,第二个参数:时间间隔,第三个参数:需要触发的函数,当值为NULL交给系统处理
}
至此,完成了验证输入的准考证号码是否为11位的功能,测试如图:
判断身份证号的有效性
大致流程与上面一样
添加一个函数 ,int check_sfz(CString sfz)
去类视图->Cmyapp_1Dlg->添加函数,如图:
复写这个函数:
int Cmyapp_1Dlg::check_sfz(CString sfz)
{
return 0;
}
现在确定返回值以及其代表的状态
0.身份证号正常
1.身份证号为18位数字(最后一位可以是x,支持大小写)
2.对不起,您的年龄不在合法的职工年龄范围
3.身份证号码错误
由于我懒得写这么复杂的身份证号码的判断逻辑,所以一下我简略判断,我只是判断一下长度,其他的在此不做判断,请读者自行补充代码。
int Cmyapp_1Dlg::check_sfz(CString sfz)
{
//此处代码不完整,需自行补充,对于不同的错误,应该返回不同的状态值,例如,年龄不满18岁,应该返回2,身份证号码错误,应返回3
int length = sfz.GetLength();
if (length != 18)
{
return 1;
}
return 0;
}
对于“开始考试” 按钮添加调用验证身份证格式的代码,如下:
void Cmyapp_1Dlg::OnBnClickedBeginTest()
{
// TODO: 在此添加控件通知处理程序代码
//这里需要判断用户输入的准考证信息,身份证信息是否合法,暂时先省略
//判断用户的准考证号
UpdateData(TRUE);
int zkz_result = check_zkz(et_zkz);
if (zkz_result == 1)
{
MessageBox(_T("准考证为11位数字"));
return;
}
int sfz_result = check_sfz(et_sfz);
if (sfz_result == 1)
{
MessageBox(_T("身份证号为18位数字(最后一位可以是x,支持大小写)"));
return;
}
if (sfz_result == 2)
{
MessageBox(_T("对不起,您的年龄不在合法的职工年龄范围"));
return;
}
if (sfz_result == 3)
{
MessageBox(_T("身份证号码错误"));
return;
}
btn_begin_test.EnableWindow(FALSE);//让按钮无法点击
SetTimer(1,1000,NULL);//设置一个定时器,这里有三个参数,第一个参数:定时器id,第二个参数:时间间隔,第三个参数:需要触发的函数,当值为NULL交给系统处理
}
目前考题这个下拉框的内容为空,往里面添加01 02 03 三个选项
方式如下:
找到下拉框的属性页面
在Data里面添加 01;02;03
Type 选择:Drop List
完成以后效果如下:
由pdflib模块提供支持。
pdflib模块包含:pdflib.h pdflib.lib pdflib.dll
把三个文件同时加到工程目录的debug目录
#include "stdafx.h"
#include "myapp_1.h"
#include "myapp_1Dlg.h"
#include "afxdialogex.h"
#include "pdflib.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#pragma comment(lib, "PDFLib.lib")
添加了以下两行
#include "pdflib.h"
#pragma comment(lib, "PDFLib.lib")
开始写调用代码:
图片上的参数列表显示的并不完整:
完整的参数列表如下:
CString zkz, CString sfz, double zhun_que_lv, double da_zi_su_du, double cheng_ji, CString nei_rong
生成的函数如下:
void Cmyapp_1Dlg::write_pdf(CString zkz, CString sfz, double zhun_que_lv, double da_zi_su_du, double cheng_ji, CString nei_rong)
{
}
变量名设置为:et_content
否则会影响后面调用。
myapp_1Dlg.cpp 添加头文件:
#include
#include
using namespace std;
添加完之后是这样的
#include "stdafx.h"
#include "myapp_1.h"
#include "myapp_1Dlg.h"
#include "afxdialogex.h"
#include "pdflib.h"
#include <string>
#include <stdio.h>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#pragma comment(lib, "PDFLib.lib")
是时候往里面添加写pdf的代码了
复写write_pdf函数
复写完是这样的:
void Cmyapp_1Dlg::write_pdf(CString zkz, CString sfz, double zhun_que_lv, double da_zi_su_du, double cheng_ji, CString nei_rong)
{
remove("成绩单.pdf");
PDF *p;
if ((p = PDF_new()) == (PDF *) 0){
printf("Couldn't create PDFlib object (out of memory)!/n");
return;
}
PDF_TRY(p) {
/* This means we must check return values of load_font() etc. */
//PDF_set_parameter(p, "errorpolicy", "return");
if (PDF_begin_document(p, "./成绩单.pdf", 0, "") == -1) {
printf("Error: %s/n", PDF_get_errmsg(p));
return;
}
/* This line is required to avoid problems on Japanese systems */
PDF_set_parameter(p, "hypertextencoding", "host");
//PDF_set_parameter(p, "fakebold", "true");
PDF_set_info(p, "Creator", "hello.c");
PDF_set_info(p, "Author", "Thomas Merz");
PDF_set_info(p, "Title", "Hello, world (C)!");
PDF_begin_page_ext(p, a4_width, a4_height, "");
int font_song = PDF_findfont(p,"STSong-Light", "GB-EUC-H", 0);
PDF_setfont(p,font_song, 12);
PDF_set_text_pos(p,50, a4_height - 50);
USES_CONVERSION;
string s = T2A(( zkz.GetBuffer()));
s = "准考证号:" + s;
PDF_show(p,s.c_str());
PDF_set_text_pos(p,50, a4_height - 65);
s = T2A(( sfz.GetBuffer()));
s = "身份证号:" + s;
PDF_show(p,s.c_str());
PDF_setfont(p,font_song, 8);
PDF_set_text_pos(p,50, a4_height - 85);
CString cs;
cs.Format(L"您打字的正确率是%f,速度是%f字/分钟,本次考试的成绩是%f分",zhun_que_lv,da_zi_su_du,cheng_ji);
s = T2A(cs.GetBuffer());
PDF_show(p,s.c_str());
PDF_setfont(p,font_song, 8);
PDF_set_text_pos(p,50, a4_height - 100);
s="以下是您本次考试录入的内容:";
PDF_show(p,s.c_str());
PDF_set_text_pos(p,50, a4_height - 130);
s = T2A(nei_rong.GetBuffer());
PDF_show(p,s.c_str());
//PDF_setcolor(p, "fill", "cmyk", 1, 0,0,0);
//PDF_rect(p, 250,250, 250, 250);
//PDF_fill(p);
PDF_end_page_ext(p, "");
PDF_end_document(p, "");
}
PDF_CATCH(p) {
printf("PDFlib exception occurred in sample:/n");
printf("[%d] %s: %s/n",
PDF_get_errnum(p), PDF_get_apiname(p), PDF_get_errmsg(p));
CString cs;
cs.Format(L"[%d] %s: %s/n",
PDF_get_errnum(p), PDF_get_apiname(p), PDF_get_errmsg(p));
PDF_delete(p);
return;
}
PDF_delete(p);
return;
}
双击 提交 按钮:
加入一下两行
UpdateData(TRUE);
write_pdf(et_zkz,et_sfz,100.0,88.0,100,et_content);
最后应该是差不多这个样子的(函数名可能有些不同 ,这个不重要)
void Cmyapp_1Dlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
//CDialogEx::OnOK();
UpdateData(TRUE);
write_pdf(et_zkz,et_sfz,100.0,88.0,100,et_content);
}
目前的代码还存在的一些问题:
- 调用函数 write_pdf(et_zkz,et_sfz,100.0,88.0,100,et_content); 里面的打字速度,正确率,成绩等没有经过计算就传进去了一个默认值,实际中需要根据用户的输入来进行计算。(读者自己可以完善此功能)
- 没有读取配置文件的信息,也没有写此模块,后期可能会加入此功能。
bug修复记录:
- void Cmyapp_1Dlg::OnTimer(UINT_PTR nIDEvent)存在一个bug,描述:在按下开始考试按钮时,下面的输入框无法输入内容。目前已经修复。