1、使用美图秀秀制作一些背景透明的bmp图片(生成的透明背景默认是黑色的)
生成的bmp图片:(因为图片本身是黑色的,透明背景也是黑色的,所以图片整体看起来是全黑的)
2、在工程中添加资源
3、修改桌面图标
参考链接:https://blog.csdn.net/u013630675/article/details/78883442
Turing_factory_testDlg.cpp文件CTuringfactorytestDlg函数做如下修改:(修改任务栏图标和窗口图标)
CTuringfactorytestDlg::CTuringfactorytestDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_TURING_FACTORY_TEST_DIALOG, pParent)
{
//************新修改:IDR_MAINFRAME -> IDI_ICON1
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1/*IDR_MAINFRAME*/);
}
任务栏图标效果如下:
窗口图标效果如下:
修改Resource.h文件宏定义:(修改桌面图标和exe图标)
//************新修改:130 -> 127
#define IDI_ICON1 127//130
exe图标效果如下:
桌面图标如下:
4、修改"关于Turing测试"对话框
其中位图设置如下:
5、修改系统"关于"选项的文字内容
修改Turingfactorytest.rc文件如下内容:
STRINGTABLE
BEGIN
//******************新修改:"关于 Turing_factory_test(&A)..." -> "关于Turing测试(A)"
IDS_ABOUTBOX "关于Turing测试(A)"//"关于 Turing_factory_test(&A)..."
END
效果图:
6、添加自动查询串口的功能(两种方法,可配合使用,优先采用方法二)
添加控件combobox,并添加变量:m_CombolPort,设置Type为下拉列表:
方法一:通过遍历设备列表中的所有串口0-255来实现检测(遍历每个串口花费约15ms时间,一次完整遍历有稍许延时,但是不存在权限、兼容性和适配性问题)
对话框类中添加与串口有关的公有成员函数和变量
CUIntArray ports/*所有存在串口*/, portse/*可用串口*/, portsu/*已占用串口*/;
void Get_COM_by_traversal(void);//采用遍历的方法来获取所有存在的串口,并添加到组合框中
xxDlg.cpp文件中添加Get_COM_by_traversal函数的具体实现内容:
//采用遍历的方法来获取所有存在的串口,并添加到组合框中
void CTuringfactorytestDlg::Get_COM_by_traversal(void)
{
m_CombolPort.ResetContent();//清空组合框的所有数据
//清空数组内容
ports.RemoveAll();//所有存在串口
portse.RemoveAll();//可用串口
portsu.RemoveAll();//已占用串口
//因为至多有255个串口,所以依次检查各串口是否存在
//如果能打开某一串口,或打开串口不成功,但返回的是 ERROR_ACCESS_DENIED错误信息,
//都认为串口存在,只不过后者表明串口已经被占用
//否则串口不存在
for (int i = 1; i < 256; i++)
{
//形成串口名称
CString sPort;
sPort.Format(_T("\\\\.\\COM%d"), i);
//尝试打开串口
BOOL bSuccess = FALSE;
HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (hPort == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
if (dwError == ERROR_ACCESS_DENIED)
{
bSuccess = TRUE;
portsu.Add(i); //已占用的串口
}
}
else
{
//The port was opened successfully
bSuccess = TRUE;
portse.Add(i); //可用的串口
//Don't forget to close the port, since we are going to do nothing with it anyway
CloseHandle(hPort);
}
//Add the port number to the array which will be returned
if (bSuccess)
ports.Add(i); //所有存在的串口
}
unsigned short uicounter;
unsigned short uisetcom;
CString str;
//获取可用串口个数
uicounter = ports.GetSize();
//如果个数大于0
if (uicounter > 0)
{
//初始化串口列表框
for (int i = 0; i < uicounter; i++)
{
uisetcom = ports.ElementAt(i);
str.Format(_T("COM%d "), uisetcom);
m_CombolPort.AddString(str);
}
}
}
在初始化函数OnInitDialog中添加串口相关代码
Get_COM_by_traversal();//采用遍历的方法来获取所有存在的串口,并添加到组合框中
//m_CombolPort.SetCurSel(0);//显示组合框中的第一行内容
方法二:读取注册表来实现检测(该方法响应速度很快,可增强用户体验感,但存在一定的权限、兼容性和适配性问题,并不是所有的windows系统均可采用该方法)
通过设备管理器我们可以看到可用串口号的列表,windows肯定有自己管理各种设备的方法,那就是大家所熟悉的注册表,注册表中记录各种设备信息以及其他重要信息。在HKEY_LOCAL_MACHINE下逐级展开到Hardware\\DeviceMap\\SerialComm,这里记录的就是串口信息。只要通过简单的注册表读取操作我们就可以得到串口列表
xxDlg.h头文件添加枚举变量
enum {//如果使用注册表的方式检测串口成功,则返回gy_traversal,失败则返回gy_register
gy_register = 0,//读取注册表的方式检测串口
gy_traversal,//采用遍历的方式检测串口
};
对话框类中添加与串口有关的公有成员函数声明
int Get_COM_by_register(void);//采用读取注册表的方法获取所有存在的串口,并添加到组合框中
xxDlg.cpp文件中添加Get_COM_by_register函数的具体实现内容:
//采用读取注册表的方法获取所有存在的串口,并添加到组合框中
int CTuringfactorytestDlg::Get_COM_by_register(void)
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Hardware\\DeviceMap\\SerialComm"), NULL, KEY_READ, &hKey) == ERROR_SUCCESS)
{
m_CombolPort.ResetContent();//清空组合框的所有数据
TCHAR szPortName[256], szComName[256];
DWORD dwLong, dwSize;
int nCount = 0;
while (true)
{
dwLong = dwSize = 256;
if (RegEnumValue(hKey, nCount, szPortName, &dwLong, NULL, NULL, (PUCHAR)szComName, &dwSize) == ERROR_NO_MORE_ITEMS)
break;
CString str;
/*str.Format(_T("%d"), nCount);//nCount表示读到的第几个串口
m_CombolPort.AddString(str);*/
str.Format(_T("%s "), szComName);
m_CombolPort.AddString(str);
nCount++;
}
RegCloseKey(hKey);
}
else
{
return gy_traversal;//如果读取注册表的方法检测串口失败,则返回该值,表示程序运行时使用遍历的方法检测串口
}
return gy_register;//如果读取注册表的方法检测串口成功,则返回该值,表示程序运行时使用注册表的方法检测串口
}
在初始化函数OnInitDialog中添加串口相关代码
//Get_COM_by_traversal();//采用遍历的方法来获取所有存在的串口,并添加到组合框中
//m_CombolPort.SetCurSel(0);//显示组合框中的第一行内容
Get_COM_by_register();//采用读取注册表的方法获取所有存在的串口,并添加到组合框中
方法一和方法二 配合使用时,可优先考虑方法二,当方法二不起作用时,再采用方法一
对话框类中添加与串口有关的公有成员函数声明
void Get_COM(void);//综合两种以上两种方式获取所有存在的串口,并添加到组合框中
xxDlg.cpp文件中添加Get_COM函数的具体实现内容:
//综合两种以上两种方式获取所有存在的串口,并添加到组合框中
void CTuringfactorytestDlg::Get_COM(void)
{
static BYTE get_COM_flag = gy_register;
if (get_COM_flag == gy_register)
{
get_COM_flag = Get_COM_by_register();
}
if (get_COM_flag == gy_traversal)
{
Get_COM_by_traversal();
}
}
在初始化函数OnInitDialog中添加串口相关代码
//Get_COM_by_traversal();//采用遍历的方法来获取所有存在的串口,并添加到组合框中
//m_CombolPort.SetCurSel(0);//显示组合框中的第一行内容
//Get_COM_by_register();//采用读取注册表的方法获取所有存在的串口,并添加到组合框中
Get_COM();//综合两种以上两种方式获取所有存在的串口,并添加到组合框中
7、添加GY_File.h和GY_File.cpp两个文件,存放全局变量和全局函数
注意:GY_File.cpp文件必须包含pch.h头文件(VS2019需要添加)
#include "pch.h"//该头文件必须添加
#include"GY_File.h"
8、GY_File.cpp文件中定义如下全局变量和全局函数(全局函数要在头文件声明),作用:其他全局函数可以使用此变量调用主对话框的功能
CTuringfactorytestDlg* gy_main_dlg = NULL;//记录主对话框对象
void gy_main_dlg_init(void* Dlg)//在OnInitDialog函数中调用:gy_main_dlg_init(this);
{
void* main_dlg = Dlg;
gy_main_dlg = (CTuringfactorytestDlg*)main_dlg;
}
9、串口打开、关闭、读取数据、写入数据功能实现
GY_File.h添加串口相关宏定义、枚举变量、结构体:
#define UART_READ_NUMBER 10240//输入缓冲区大小
#define UART_WRITE_NUMBER 100//输出缓冲区大小
#define UART_BAUD_RATE 115200//波特率
#define CMD_DATA_NUMBER 50//设置串口接收BUFF的长度
/*
enum {//uart_state
gy_uart_state_unknown,//串口连接未知,串口已打开,但是规定时间内还没有接收到串口返回的数据
gy_uart_state_success,//串口连接正常,串口已打开,并且接收到串口返回的数据
gy_uart_state_error,//串口连接错误,串口已打开,但是超过规定时间仍然没有接收到串口返回的数据
};
*/
typedef struct {
HANDLE hCom;//串口句柄
BOOL com_flag;//串口是否可以正常使用的标志位当重新选择串口时,必须置零,当串口正常打开之后置1
CString hname;//串口名字
CWinThread* uart_recv_pThread;//接收串口数据的线程
BYTE uart_data[CMD_DATA_NUMBER];//存储一个完整的串口命令数据
int count;//记录uart_data数组中已经存储的数据数量
// BYTE uart_state;//打开串口之后记录串口状态
}GY_COMX;
extern GY_COMX gy_comx;//GY_File.cpp文件中定义,这里属于外部声明
GY_File.cpp文件中添加串口初始化函数:(创建接收串口数据的线程,接收数据的最终处理函数是gy_uart_receive)
void gy_uart_init(void)//初始化串口相关事宜(包括串口变量初始化、多线程函数执行)(初始化函数OnInitDialog中调用)
{
gy_comx.hCom = NULL;
gy_comx.com_flag = FALSE;
gy_comx.hname = _T("");
gy_comx.count = 0;
gy_main_dlg->Get_COM();//向组合框中添加串口设备
gy_create_uart_recv_pThread();//创建线程,用于串口接收数据使用,下面是该函数的定义
}
static int gy_create_uart_recv_pThread(void)//创建线程,用于串口接收数据使用
{
gy_comx.uart_recv_pThread = new CWinThread();//创建线程
gy_comx.uart_recv_pThread->m_bAutoDelete = false;//设置是否自动删除为false
gy_comx.uart_recv_pThread = AfxBeginThread(gy_uart_recv_pThread_func, NULL);//启动线程,线程函数下面有定义
if (gy_comx.uart_recv_pThread == NULL)
{
gy_main_dlg->MessageBox(_T("串口接收数据线程启动失败!"));
exit(-1);
}
return 0;
}
static UINT gy_uart_recv_pThread_func(LPVOID pParam)//串口数据接收线程执行函数
{
while (1)
{
//Sleep(100);//屏蔽掉该处的延时,因为串口通信为异步通信,一次接收的数据量越大,出错的概率也就越大
if (gy_comx.com_flag)//如果标志位为TRUE,表示串口正常,可正常读取串口数据
{
//gy_set_timer_clock();//设置定时控灯demo,临时测试添加,纯属娱乐,娱乐之后请注释掉该代码
//main_dlg->OnBnClickedallopen();//无线开灯关灯,测试时使用,测试完毕请注释掉该代码
BYTE str[UART_READ_NUMBER];
memset(str, '\0', UART_READ_NUMBER);
DWORD wCount = UART_READ_NUMBER;//读取的字节数
BOOL bReadStat;
bReadStat = ReadFile(gy_comx.hCom, str, wCount, &wCount, NULL);
if (!bReadStat && gy_comx.com_flag == TRUE)
{
gy_comx.com_flag = FALSE;//该代码必须写在弹框之前,如果写在弹框之后,如果弹框还没被点击消失,此时其他线程执行写入串口数据,会提示写串口数据失败(现在不需要该提示)
gy_main_dlg->MessageBox(_T("dongle可能被拔出!!!\n读串口失败!!!"), _T("错误"));
gy_main_dlg->Get_COM();//向组合框中添加串口设备
gy_edit_clean();//清空编辑控件的内容,下面有定义
//exit(-1);
}
//注释掉清空串口缓存函数,因为这里不应该用到
/*PurgeComm(gy_comx.hCom, PURGE_TXABORT |
PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);*/
gy_uart_data_operation(str, wCount);//处理串口接收的缓存数据,下面有定义
}
}
return 0;
}
static int gy_edit_clean(void)//清空相关控件的内容
{
return 0;
}
static int gy_uart_data_operation(BYTE* str, DWORD wCount)//处理串口接收的缓存数据
{
DWORD i = 0;
for (; i< wCount; i++)
{
gy_uart_receive(str[i]);//下面有定义
}
return 0;
}
void gy_uart_receive(BYTE rcv_data)//读取串口数据,串口接收数据的最终处理函数
{
return;
}
GY_File.cpp文件添加打开串口相关函数:
int gy_uart_open(void)//打开一个串口
{
gy_edit_clean();//清空静态文本控件的内容
gy_comx.com_flag = FALSE;//置0,供串口读取线程使用
gy_uart_close();//关闭串口
gy_main_dlg->UpdateData(TRUE);//将控件中输入的值更新到变量中
gy_comx.hname = gy_main_dlg->m_com_str;//获得串口数据******m_com_str是组合框的值类型变量,下面会说明如何添加
if (gy_comx.hname.GetLength() > 4)
{
gy_comx.hname = _T("\\\\.\\") + gy_comx.hname;
}
gy_comx.hCom = CreateFile(gy_comx.hname,//串口名称
GENERIC_READ | GENERIC_WRITE,//允许读和写
0,//独占方式
NULL,
OPEN_EXISTING,//打开而不是创建
0,//同步方式
NULL);
if (gy_comx.hCom == (HANDLE)-1)
{
gy_comx.hCom = NULL;
gy_main_dlg->MessageBox(_T("打开 COM 失败!!!\n请确认串口是否选择正确!!"), _T("错误"));
gy_main_dlg->m_CombolPort.ResetContent();//清空组合框的所有数据
return -1;
}
SetupComm(gy_comx.hCom, UART_READ_NUMBER, UART_WRITE_NUMBER);//输入缓冲区大小是 10240 输出缓冲区的大小是 100
COMMTIMEOUTS TimeOuts;
//设定读超时
TimeOuts.ReadIntervalTimeout = MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier = 0;
TimeOuts.ReadTotalTimeoutConstant = 0;
//在读一次输入缓冲区的内容后读操作就立即返回,
//而不管是否读入了要求的字符.
//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier = 100;
TimeOuts.WriteTotalTimeoutConstant = 500;
SetCommTimeouts(gy_comx.hCom, &TimeOuts);//设置超时
//配置串口
DCB dcb;
if (!GetCommState(gy_comx.hCom, &dcb))
{
gy_uart_close();//关闭串口
gy_main_dlg->MessageBox(_T("获取串口DCB失败!!!"), _T("错误"));
return -1;
}
dcb.BaudRate = UART_BAUD_RATE;//波特率为 115200
dcb.ByteSize = 8;//每个字节有 8 位
dcb.Parity = NOPARITY;//无奇偶校验位
dcb.StopBits = ONESTOPBIT;//1个停止位
if (!SetCommState(gy_comx.hCom, &dcb))
{
gy_uart_close();//关闭串口
gy_main_dlg->MessageBox(_T("设置串口DCB失败!!!"), _T("错误"));
return -1;
}
if (!PurgeComm(gy_comx.hCom, PURGE_TXCLEAR | PURGE_RXCLEAR))
{
gy_uart_close();//关闭串口
gy_main_dlg->MessageBox(_T("清空串口缓冲区失败!!!"), _T("错误"));
return -1;
}
gy_comx.com_flag = TRUE;//当串口正常打开之后置1,供串口读取线程使用
return 0;
}
其中,m_com_str是组合框的值类型变量,通过如下方式添加:
GY_File.cpp文件添加关闭串口相关函数:
int gy_uart_close()//关闭一个串口
{
gy_edit_clean();//清空编辑控件的内容
if (gy_comx.hname.Compare(_T("0")) != 0)
{
gy_comx.hname.Format(_T("0"));
if (gy_comx.hCom != NULL)
{
CloseHandle(gy_comx.hCom);
gy_comx.hCom = NULL;
gy_comx.com_flag = FALSE;//置0,供串口读取线程使用
}
}
return 0;
}
GY_File.cpp文件添加写串口数据相关函数:
void gy_uart_write(BYTE* gy_uart_tx, DWORD dwBytesWrite)//向串口写入数据
{
if (gy_comx.com_flag == FALSE)//如果没有打开串口或者串口异常,则直接返回,不做任何写串口操作
{
return;
}
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(gy_comx.hCom, &dwErrorFlags, &ComStat);
bWriteStat = WriteFile(gy_comx.hCom, gy_uart_tx, dwBytesWrite, &dwBytesWrite, NULL);
if (!bWriteStat)
{
MessageBox(NULL, _T("写串口失败!"), _T("错误警告"), MB_OK);
}
return;
}
10、通过组合框打开一个串口
组合框重载函数OnCbnSelchangeCombo1,当组合框控件的选择发生变化时,触发此消息:打开对应串口。在选中组合框的一个串口时,执行该函数,函数将选中的串口打开、设置OK。
void CTuringfactorytestDlg::OnCbnSelchangeCombo1()//当组合框控件的选择发生变化时,触发此消息:打开对应串口
{
// TODO: 在此添加控件通知处理程序代码
gy_uart_open();//打开选中的串口
}
演示效果图:
11、刷新组合框列表中的串口
当用户要下拉组合框控件的列表框部分中的字符串时,刷新列表内容:
void CTuringfactorytestDlg::OnCbnDropdownCombo1()//当用户要下拉组合框控件的列表框部分中的字符串时,执行该函数
{
// TODO: 在此添加控件通知处理程序代码
Get_COM();//综合两种以上两种方式获取所有存在的串口,并添加到组合框中
}
效果图:
12、添加定时器功能
GY_File.h添加定时器相关的结构体:
typedef struct {
CWinThread* timer_1s_pThread;//1秒定时器的线程
UINT timer_1s_count;//每执行一次1秒定时器,该值加1
}GY_TIMER;
extern GY_TIMER gy_timer;//GY_File.cpp文件中定义,这里属于外部声明
GY_File.cpp添加定时器相关的函数:
///gy_timer///
GY_TIMER gy_timer;//定时器相关变量
static int gy_create_1s_timer_pThread(void);//创建线程,用于一秒钟执行一次相关函数,在ado_init函数中调用
static UINT gy_1s_timer_pThread_func(LPVOID pParam);//串口数据接收线程执行函数,在create_timer_pThread函数中调用
static void gy_1s_timer(UINT count);
void gy_timer_init(void)//(初始化函数OnInitDialog中调用)
{
gy_create_1s_timer_pThread();//1秒定时器
return;
}
static int gy_create_1s_timer_pThread(void)//创建线程,用于一秒钟执行一次相关函数,在ado_init函数中调用
{
gy_timer.timer_1s_count = 0;
gy_timer.timer_1s_pThread = new CWinThread();//创建线程
gy_timer.timer_1s_pThread->m_bAutoDelete = false;//设置是否自动删除为false
gy_timer.timer_1s_pThread = AfxBeginThread(gy_1s_timer_pThread_func, NULL);//启动线程
if (gy_timer.timer_1s_pThread == NULL)
{
gy_main_dlg->MessageBox(_T("1秒函数线程启动失败!"));
exit(-1);
}
return 0;
}
static UINT gy_1s_timer_pThread_func(LPVOID pParam)//串口数据接收线程执行函数,在create_timer_pThread函数中调用
{
while (1)
{
Sleep(1000);//每隔1秒钟执行一次下面的函数
gy_1s_timer(gy_timer.timer_1s_count++);
}
return 0;
}
static void gy_1s_timer(UINT count)
{
//*****************此处添加用户功能
return;
}
13、添加测试配置信息的相关功能
GY_File.h添加测试配置信息结构体:
typedef struct {
//WORD light_dim;//控灯时发送的亮度值
BYTE light_dim_percent;//亮度值百分比
WORD adc_dim_min_value;//设置该亮度状态下读取dim引脚对应ADC下限值
WORD adc_dim_max_value;//设置该亮度状态下读取dim引脚对应ADC上限值
WORD light_temp;//控灯时发送的色温值
WORD adc_temp_min_value;//设置该色温状态下读取temp引脚对应ADC下限值
WORD adc_temp_max_value;//设置该色温状态下读取temp引脚对应ADC上限值
}GY_CTL_LIGHT_INFO;//测试控灯数据和ADC读取范围
typedef struct {
char user_name[20];//设备名称
char password[20];//设备密钥
}GY_USER_INFO;//用户信息
#define GY_CTL_LIGHT_NUMBER 3//测试时改变模组状态的次数
typedef struct {
char rssi_min_value;//设置过滤的RSSI值(低于该值的设备将被过滤)
GY_CTL_LIGHT_INFO ctl_light_info[GY_CTL_LIGHT_NUMBER];//提供测试数据(目前测试3组数据)
GY_USER_INFO user_info;//修改测试配置信息需要用户登录
}GY_TEST_CONFIG_INFO;//工厂测试配置信息(包括用户)
extern GY_TEST_CONFIG_INFO gy_test_config_info;
GY_File.cpp添加测试配置信息的相关函数:(配置信息存储在配置文件中)
GY_TEST_CONFIG_INFO gy_test_config_info;
void gy_test_config_info_init(void)//测试配置信息初始化(初始化函数OnInitDialog中调用)
{
CFile file;
if (!file.Open(_T("./gy_config/test_config_info.dat"), CFile::modeRead))//如果文件不存在
{
if (!file.Open(_T("./gy_config/test_config_info.dat"), CFile::modeCreate | CFile::modeWrite))
{
gy_main_dlg->MessageBox(_T("test_config_info.dat文件打开失败!"), _T("错误"));
return;
}
else
{
gy_test_config_info.rssi_min_value = -50;
strcpy_s(gy_test_config_info.user_info.user_name, "Turing");
strcpy_s(gy_test_config_info.user_info.password, "TPADSZ123456");
//gy_test_config_info.ctl_light_info[0].light_dim = 0;
gy_test_config_info.ctl_light_info[0].light_dim_percent = 50;
gy_test_config_info.ctl_light_info[0].adc_dim_min_value = 0;
gy_test_config_info.ctl_light_info[0].adc_dim_max_value = 3300;
gy_test_config_info.ctl_light_info[0].light_temp = 2700;
gy_test_config_info.ctl_light_info[0].adc_temp_min_value = 0;
gy_test_config_info.ctl_light_info[0].adc_temp_max_value = 3300;
//gy_test_config_info.ctl_light_info[1].light_dim = 0;
gy_test_config_info.ctl_light_info[1].light_dim_percent = 80;
gy_test_config_info.ctl_light_info[1].adc_dim_min_value = 0;
gy_test_config_info.ctl_light_info[1].adc_dim_max_value = 3300;
gy_test_config_info.ctl_light_info[1].light_temp = 6500;
gy_test_config_info.ctl_light_info[1].adc_temp_min_value = 0;
gy_test_config_info.ctl_light_info[1].adc_temp_max_value = 3300;
//gy_test_config_info.ctl_light_info[2].light_dim = 0;
gy_test_config_info.ctl_light_info[2].light_dim_percent = 30;
gy_test_config_info.ctl_light_info[2].adc_dim_min_value = 0;
gy_test_config_info.ctl_light_info[2].adc_dim_max_value = 3300;
gy_test_config_info.ctl_light_info[2].light_temp = 5400;
gy_test_config_info.ctl_light_info[2].adc_temp_min_value = 0;
gy_test_config_info.ctl_light_info[2].adc_temp_max_value = 3300;
file.SeekToBegin();
file.Write(&gy_test_config_info, sizeof(gy_test_config_info));
}
file.Close();
}
else//如果文件存在
{
file.SeekToBegin();
file.Read(&gy_test_config_info, sizeof(gy_test_config_info));
file.Close();
}
return;
}
void gy_test_config_info_read(void)
{
CFile file;
if (!file.Open(_T("./gy_config/test_config_info.dat"), CFile::modeRead))//如果文件不存在
{
gy_main_dlg->MessageBox(_T("test_config_info.dat文件打开失败!"), _T("错误"));
return;
}
file.SeekToBegin();
file.Read(&gy_test_config_info, sizeof(gy_test_config_info));
file.Close();
return;
}
void gy_test_config_info_write(void)
{
CFile file;
if (!file.Open(_T("./gy_config/test_config_info.dat"), CFile::modeRead))//如果文件不存在
{
gy_main_dlg->MessageBox(_T("test_config_info.dat文件打开失败!"), _T("错误"));
return;
}
file.SeekToBegin();
file.Write(&gy_test_config_info, sizeof(gy_test_config_info));
file.Close();
return;
}
14、添加控件,设置整体布局
15、调整对话框字体大小
xxxDlg.h文件中添加公有成员函数和变量:
//窗口大小
void ReSize();
POINT old;
afx_msg void OnSize(UINT nType, int cx, int cy);
CFont textSize;
xxxDlg.cpp文件中实现新添加的共有成员函数:
void CTuringfactorytestDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
if (nType == SIZE_RESTORED || nType == SIZE_MAXIMIZED)
{
ReSize();
}
}
void CTuringfactorytestDlg::ReSize()
{
float fsp[2];
POINT Newp; //获取现在对话框的大小
CRect recta;
GetClientRect(&recta); //取客户区大小
Newp.x = recta.right - recta.left;
Newp.y = recta.bottom - recta.top;
fsp[0] = (float)Newp.x / old.x;
fsp[1] = (float)Newp.y / old.y;
CRect Rect;
int woc;
CPoint OldTLPoint, TLPoint; //左上角
CPoint OldBRPoint, BRPoint; //右下角
HWND hwndChild = ::GetWindow(m_hWnd, GW_CHILD); //列出所有控件
//int size = int(Newp.x) / 8;
//textSize.CreatePointFont((size<100)?100:size, _T("宋体"));
while (hwndChild)
{
woc = ::GetDlgCtrlID(hwndChild);//取得ID
GetDlgItem(woc)->GetWindowRect(Rect);
//GetDlgItem(woc)->SetFont(&textSize);
ScreenToClient(Rect);
OldTLPoint = Rect.TopLeft();
TLPoint.x = long(OldTLPoint.x * fsp[0]);
TLPoint.y = long(OldTLPoint.y * fsp[1]);
OldBRPoint = Rect.BottomRight();
BRPoint.x = long(OldBRPoint.x * fsp[0]);
BRPoint.y = long(OldBRPoint.y * fsp[1]);
Rect.SetRect(TLPoint, BRPoint);
GetDlgItem(woc)->MoveWindow(Rect, TRUE);
hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT);
}
textSize.Detach();
old = Newp;
}
xxxDlg.cpp文件OnInitDialog函数中添加设置字体大小的代码:
// TODO: 在此添加额外的初始化代码
textSize.CreatePointFont(150, _T("宋体"));
HWND hwndChild = ::GetWindow(m_hWnd, GW_CHILD); //列出所有控件
while (hwndChild)
{
int woc = ::GetDlgCtrlID(hwndChild);//取得ID
GetDlgItem(woc)->SetFont(&textSize);
hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT);
}
m_CombolPort.SetItemHeight(-1, 20);//设置组合列表框
效果展示图: