Turing工厂测试PC软件开发(VS2019)

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);//设置组合列表框

效果展示图:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值