EasyX学习

天天玩黑白界面,前段时间突然看到一个图形界面库,虽然是各位前辈玩烂的东西,但是还是勾起了我的兴致。做了一个音乐播放器的。(有点像工作中在展讯平台画MMI)。还有几个问题未解决的问题以及纰漏的地方,要是被大佬翻到了,还请帮忙指正。

先来一张定妆照,界面比较丑,就随便找了几张现有的UI画了一下

EasyX的绘制函数,可以看看EasyX_Help,里面分类的也比较清楚。贴吧也有很多大佬踩过的坑可以参考。

#include <graphics.h>
#include <conio.h>
#pragma comment(lib,"Winmm.lib")

音乐播放调用了mciSendString接口。用起来方便是方便,但是有两个问题现在改没解决

1、获取不到播放总时间以及当前时间

//sprintf(mci_cmd, "%s %s%s %s", "status", MMI_PLAYER_MUSIC_PATCH, name_obj.name_list[Cur_player_index], "position");
		sprintf(mci_cmd, "%s %s %s", "status", name_obj.name_list[Cur_player_index], "position");
		mciSendString(mci_cmd, cur_timer, strlen(cur_timer), wnd);
		cur_timer_int = atoi(cur_timer);
		memset(cur_timer, 0, sizeof(cur_timer));
		
		
		sprintf(cur_timer, "%.2ld:%.2ld:%.2ld", cur_timer_int/3600, (cur_timer_int / 60) % 60, (cur_timer_int % 3600) % 60);
		music_name_width = textwidth(cur_timer);
		outtextxy(MMI_TIMER_CUR_X , MMI_TIMER_Y, cur_timer);

    //sprintf(mci_cmd, "%s %s%s %s", "status", MMI_PLAYER_MUSIC_NAME, name_obj.name_list[Cur_player_index], "length");
		sprintf(mci_cmd, "%s %s %s", "status", name_obj.name_list[Cur_player_index], "length");
		mciSendString(mci_cmd, total_timer, strlen(total_timer), wnd);
		total_timer_int = atoi(total_timer);
		memset(total_timer, 0, sizeof(total_timer));
		
		
		sprintf(total_timer, "%.2ld:%.2ld:%.2ld", total_timer_int/3600, (total_timer_int / 60) % 60, (total_timer_int % 3600) % 60);
		music_name_width = textwidth(total_timer);
		outtextxy(MMI_WINDOWS_WIDTH - MMI_TIMER_CUR_X - music_name_width , MMI_TIMER_Y, total_timer);

返回的时间毫无意外都是0。

2、关于循环播放的问题,

一开始考虑用播放时间以及当前时间老判断是否播放下一首(或者重新播放当前歌曲),这个想法在第一个问题发现无法获取到播放时间只能毙了。

而后翻看前辈们的资料,发现可以这样操作

sprintf(mci_cmd, "%s %s %s", mci_cmd_string[play_state] ,name_obj.name_list[Cur_player_index - 1], "notify");
mciSendString(mci_cmd, NULL, 0, wnd);

这样就可以在 播放完成之后,向窗口的handle发送消息,我在这个消息里处理循环播放问题。由于创建窗口是直接调用了

initgraph(MMI_WINDOWS_WIDTH, MMI_WINDOWS_HEIGHT);

这代码又封装在库里,无从得知当前窗口的handle是哪个?怎么注册的?以及怎么在handle里获取这个消息。愚钝,到现在还没找到解决方案。。。

主逻辑代码

void main(int argc, char *argv[])
{
	MOUSEMSG  cur_mouse = {0};
	char mci_cmd[64] = {0};
	EASYX_STATE_INFO  play_state = EASYX_STATE_STOP;
	HWND wnd = GetHWnd();
	int timer_count = 0;
	
	//char cur_timer[]
	
	EasyxPlayerWindowsInit();
	//initgraph(MMI_WINDOWS_WIDTH, MMI_WINDOWS_HEIGHT);
	
	sprintf(mci_cmd, "%s %s", "open", name_obj.name_list[Cur_player_index - 1]);
	mciSendString(mci_cmd, NULL, 0, NULL);
	
	EasyxDisplayProgressTimer(play_state);
    
    while(1)
	{
		while(MouseHit())  //检测到鼠标动作
		{
			 cur_mouse = GetMouseMsg();  // 获取当前的鼠标消息
			 switch(cur_mouse.uMsg)
			 {
				case WM_LBUTTONDOWN:  //鼠标左键按下
				{
					switch(EasyxCheckMouseArea(cur_mouse.x, cur_mouse.y))  //检测鼠标位置
					{
						case MOUSE_AREA_INFO_PLAYER:
						{
                            if(EASYX_STATE_STOP == play_state)
							{
								play_state = EASYX_STATE_PLAY;	
							}else if((EASYX_STATE_RESUME == play_state) || (EASYX_STATE_PLAY == play_state))
							{
								play_state = EASYX_STATE_PAUSE;
							}else  //pause
							{
								play_state = EASYX_STATE_RESUME;
							}
							memset(mci_cmd, 0, sizeof(mci_cmd));
							if(EASYX_STATE_PLAY == play_state)
							{
								sprintf(mci_cmd, "%s %s %s", mci_cmd_string[play_state] ,name_obj.name_list[Cur_player_index - 1], "notify");
								mciSendString(mci_cmd, NULL, 0, wnd);  // 需要播放完了发消息回来MCI_NOTIFY_SUCCESSFUL
							}else
							{
								sprintf(mci_cmd, "%s %s", mci_cmd_string[play_state], name_obj.name_list[Cur_player_index - 1]);
								mciSendString(mci_cmd, NULL, 0, NULL);
							}
							
							EasyxUpdateButton(play_state);
						}
						break;
                       case MOUSE_AREA_INFO_LEFT:
							//处理播放
							EasyxPlayerHanldeLeftOrRight(MOUSE_AREA_INFO_LEFT, play_state);
							//EasyxPlayerDisplayTiteName(name_obj);
							//更新界面
							EasyxPlayerMainWindowsDsplay(play_state);
							
						break;
						
						case MOUSE_AREA_INFO_RIGHT:
							//处理播放
							EasyxPlayerHanldeLeftOrRight(MOUSE_AREA_INFO_RIGHT, play_state);
							//EasyxPlayerDisplayTiteName(name_obj);
							//更新界面
							EasyxPlayerMainWindowsDsplay(play_state);
						break;
					}
				}
				break;
			 }
		}
        Sleep(200);
	  }
    closegraph();
}

播放->鼠标检测->鼠标操作

一、关于鼠标操作的问题,在EasyX官网找到鼠标操作不灵敏的解决方案

// 定义变量,保存鼠标消息
MouseMsg msg;

// 游戏的主循环
while(true)
{
	while (MouseHit())			// 当有鼠标消息的时候执行
	{
		msg = GetMouseMsg();	// 获取鼠标消息

		switch(msg.uMsg)		// 根据不同的鼠标消息,执行不同的代码
		{
			case xxxx: 进行游戏运算(); break;
			case xxxx: 进行游戏运算(); break;
		}
	}

	绘制游戏内容();

	Sleep(xx);					// 延时,降低 CPU 占用率
}

二、关于界面属性,造成闪烁的问题。

进度条我是做了假数据的,在刷新进度条的过程中,发现会闪烁,采用如下解决方案

    IMAGE windows_buffer(MMI_WINDOWS_WIDTH, MMI_WINDOWS_HEIGHT);
    SetWorkingImage(&windows_buffer);  //下面的绘制动作都将画到当前的buffer里面
	
	putimage(0, 0, &bg_image);  //draw bg_image
	putimage(MMI_BUTTON_LEFT_START_X, MMI_BUTTON_START_Y, &left_image);
	putimage(MMI_BUTTON_RIGHT_START_X, MMI_BUTTON_START_Y, &right_image);
	// 初始化状态先画暂停的图标
	putimage(MMI_BUTTON_PLAYER_START_X, MMI_BUTTON_START_Y, &tmp_image);
	putimage(MMI_PROGRESS_BAR_X, MMI_PROGRESS_BAR_Y, &progress_bar_empty_image);
	//putimage(MMI_PROGRESS_BAR_X, MMI_PROGRESS_BAR_Y - 3, &progress_sild_image);
	
	//画title
	EasyxPlayerDisplayTiteName(name_obj);
	
	// 画列表
	EasyxPlayerDisplayNameList(name_obj);
	//画播放的歌曲数量
	EasyxPlayerDisplayIndex(name_obj);
	
	EasyxDisplayProgressTimer(state);
	
	SetWorkingImage();  //回到默认的绘制设备
	
	putimage(0, 0, &windows_buffer);  // 一次画上去,避免闪烁

先将EasyX的工作空间设置到windows_buffer,此时绘制的图标就会在windows_buffer,全都绘制完成后,回到当前的工作空间。putimage将buffer的数据写倒当前空座空间,就能解决闪烁的问题

三、关于图片资源的问题。

为了把图片资源打包到生成的exe文件中,运行的时候只要拷贝exe即可,无需拷贝对应的图片资源。我使用的是VC6.0,VC6.0添加资源的方法如下

下面是 VC6 嵌入资源的操作步骤:
1. 创建资源文件
     1.1 打开 VC6,建立控制台应用程序,并建立相应 cpp 程序,确保可以正确编译执行。
     1.2 点菜单:File -> New...,选择 Files 中的 Resource Script,并在右侧 File 中写入名称 test,点 OK 添加到项目中。VC 会默 
认打开 test.rc 文件,先关闭它,我们可以 FileView 找到新添加的 test.rc 文件。
     1.3 双击 test.rc,会在 Workspace 区中打开 ResourceView 视图,这里就是资源列表,起初是空的。
2. 添加图片到资源文件中
     1.1 为了整齐,我们在项目路径下建立 res 文件夹,并将图片放入该文件夹内。举例,我们放入一个 bk.jpg 文件。
     1.2 切换到 ResourceView 视图,右击 test resources,选择 Import...,导入 res\bk.jpg 文件,之后再 Custom Resource Type 中 
为资源取一个类型名称,例如"IMAGE",点 OK。此时 VC 会在"IMAGE"下默认创建一个 IDR_IMAGE1 的资源,并以二进制形式打开,关掉它。
     1.3 下面需要重命名资源。右击 IDR_IMAGE1,选 Properties,将 ID 一栏的 IDR_IMAGE1 修改为符合其意义的名称,例 
如"Background",切忌,一定要加上英文的双引号。这时,资源中可以看到 "IMAGE" / "Background" (注意都有双引号)。
3. 加载资源中的图片
     打开图片很简单,需要指定 资源类型 和 资源名称。例如我们前面的例子,资源类型是 "IMAGE",资源名称是 "Background",这样读 
取:
     IMAGE img;
     loadimage(&img, "IMAGE", "Background");
     然后再 putimage 使用就可以了。

备注:
另外一种常用的加载资源的方法,就是资源名称直接使用 ID(不加双引号),我们需要用宏 MAKEINTRESOURCE 将 ID 转换为字符串。例如资源名 
称修改为 IDR_BACKGROUND,可以这样加载:
     getimage(&img, "IMAGE", MAKEINTRESOURCE(IDR_BACKGROUND));
后面就都一样了。

最后,编译程序,资源文件会自动和 exe 打包在一起。

注意加载资源的时候loadimage(&bg_image, "IMAGE", "IMAGE_EASYX_PLAY_BG");,要用加载资源的方式加载了,不然还是会以来目录下的图片资源

四、windows下的文件搜索(只搜索一个文件夹)

#define  MMI_PLAYER_MUSIC_NAME		".\\Music\\background.mp3"
#define  MMI_PLAYER_MUSIC_PATCH    		".\\Music\\"

bool EasyxPlayerSearchAllMusicFile(const char *patch, EASYX_NAME_LIST_INFO *name_obj)
{
	HANDLE hFind = 0;
	WIN32_FIND_DATA FindFileData = {0};
	char  searchFilePath[MAX_PATH] = {0};
	int filename_count = 0;
	bool ret_val = false;
	
	strcpy(searchFilePath, patch);
    strcat(searchFilePath, "*"); //必须在搜索路径后加入通配符(*), FindFirstFile才能正常运行
 
    hFind=FindFirstFile(searchFilePath, &FindFileData);
	
    if (hFind != INVALID_HANDLE_VALUE)
	{
		do{
            if(FindFileData.dwFileAttributes!=FILE_ATTRIBUTE_DIRECTORY)//如果为文件,则打印文件名
			{ 
                //fprintf(outfile, "%s\n",FindFileData.cFileName);
				if(EasyxPlayerIsMp3File(FindFileData.cFileName))
				{
					//strcpy(name_list[filename_count], FindFileData.cFileName);
					strcpy(name_obj->name_list[name_obj->name_count], MMI_PLAYER_MUSIC_PATCH);
					strcat(name_obj->name_list[name_obj->name_count], FindFileData.cFileName);
					name_obj->name_count ++;
					
					if(!ret_val)
					{
						ret_val = true;
					}
				}
            }
        }while(FindNextFile(hFind, &FindFileData));
	}

	return ret_val;
}

bool EasyxPlayerIsMp3File(char *Full)
{
	char suffix[4] = {'m', 'p', '3', 0};
	char Upper_suffix[4] = {'M', 'P', '3', 0};
	bool is_mp3 = false;
	
	if(NULL == Full)
		return false;
	
	if((NULL != strstr(Full, suffix)) || (NULL != strstr(Full, Upper_suffix)))
		is_mp3 = true;
	else
		is_mp3 = false;
	
	return is_mp3;
}

char  *EasyxGetFullPatchByname(char *Full, char **name)
{
	char *p = NULL;
	char find_char[] = "\\";
	
	// 入参检查
	if((NULL == Full) || (NULL == *name))
		return NULL;
	
	if(strstr(Full, find_char))
	{
		p = strrchr(Full, '\\');  //查找最后一个出现目标字符的指针
		if(NULL == p)
		{
			return NULL ;  // 查找失败,返回NULL
		}else
		{
			p ++;  // 需要丢弃这个查找的字符。查找返回的指针会包含这个查找的字符
			strcpy(*name, p);
			return p;
		}
	}else  //  完整路径中没有包含\\目录结构,那么这个完整路径可以作为文件名称返回
	{
		strcpy(*name, Full);
		return Full;
	}
	
}

以上

发布了22 篇原创文章 · 获赞 9 · 访问量 8831

猜你喜欢

转载自blog.csdn.net/ljm_c_bok/article/details/82978674