取名字: 玉玉云音乐播放器

就叫玉玉云音乐播放器吧(组长起的名。。)

玉玉云Github项目传送门 ==> xiao-luo17/Music-Player: 一个基于C/C++的音乐播放器

项目需求

  • 一个功能齐全的音乐播放器包括但不限于以下几点:

    • 完成基础的播放/暂停、切歌、倍速播放、快进/快退、循环播放
    • 能够实现指定文件读取MP3文件
    • 批量导入MP3文件,并可以指定编号增删音乐列表中的音乐
  • 之后我们希望能够实现一个功能:读取文件夹中的音乐MP3文件,这样用户就可以在文件夹中直接指定自己想播放的音乐。同时希望用户做出选择时可以弹出文件资源管理器进行选择

    • 读取到的MP3文件存储在播放列表中,这样可以方便的从链表中获取到文件的路径和文件名等信息
    • 使用可视化的图形界面进行操作,包括文件资源管理器的弹窗

项目记录

项目时间戳

2022

07-11

C语言项目规范、统一编码风格。被说困了属于是。

07-12

初步实现播放/暂停、循环播放、快进快退、倍速播放、自定义播放位置功能,对未来的功能添加开放了很多可扩展的接口

07-13

完成几乎所有播放音乐的基本功能,实现不包含音频文件读取功能的音乐播放列表,可以自由进行切歌操作(此时仍需要在播放列表中指定文件),以及进度条的显示。

07-14

实现使用文件资源管理器指定读取MP3文件信息到播放列表,通过链表存储。基本完成完整的基于控制台音乐播放器的所有逻辑。

07-15

发现只有逻辑还是太拉了,决定做可视化页面。痛苦选择方向,mfc和qt摇摆不定,拖了一天决定还是采用easyx图形库,简单好用。

07-16

界面开始越来越接近网易云音乐,实现了进度条的无缝刷新。实现歌曲列表的界面,解决easyx界面刷新和进度条刷新的矛盾。

07-17

添加网易云热评,加入关于页,实现播放模式的切换

07-18

完成音量加减逻辑和日志打印

07-19

忙里偷闲

07-20

今日无事

项目基础

基于windows的一款音乐播放器

学习了解mciSendString函数:

有关链表的增删改查操作、文件读写操作、UI的设计、MFC库easyx库

设计思路

  1. 基于Windows控制台C程序的音乐播放器其实是通过调用Windows上的一些API实现的,那就只需要通过函数对mciSendString传输字符串参数为命令控制Windows程序播放MP3文件。

  2. 基于这个想法,可以对音乐播放器的各个功能模块在原生API的基础上再加工,封装成一个个小demo,然后再做一个简陋的界面去操控。

  3. 那么一切合理了起来:也就是说相当于把各种本来要手打的命令行变成按钮或者键盘输入字符,按一下就往这里面输出一些命令,也就能实现音乐播放器了。但是

    • 文件不可能飞过来让你使用,那么该怎么读取呢?
    • 有没有办法可以指定文件读取?批量导入?
    • 既然要读取,那么用什么东西来装它呢?
    • 装进去了能不能删除、增添、改变?
    • 能不能读取装进去之后里面的信息?
  4. (显然)由题可知,我们可以使用链表作为这种数据结构(数据量不大),方便完成各种操作。那链表存储可以实现了,文件又怎么读取呢?

  5. 那当然是采用直接呼出文件资源管理器的方式去读取文件的路径,这个的实现我们之后再说,这样也更加友好和人性化,有图形界面的操作手感

    • 文件读取的时候总是读取失败是为什么
    • 通过断点发现文件路径参数是正确的,为什么mci无法成功播放呢?
    • 呼出管理器后操作返回数据为空有没有处理?
  6. 所以,需求里难弄的的东西来了。图形界面,用C做图形界面,完全陌生的领域。摆在面前的有种选择:

    • Easyx.h图形库
    • MFC框架
    • QT框架
    • WPF框架

    这些都是在C环境下做UI的好点子。但是MFC太拉了,UI奇丑,代码可读性差的离谱。人家微软自己都放弃了我还用吗(其实是太难不会)。QT可以说是功能强大齐全,但是学习成本高,或者说一个小播放器还不至于用QT,有点大材小用。WPF是基于C#的。

    那么综上所述,我们组采取Easyx.h图形库方案,UI这种东西全靠审美。审美上去了拿什么做都好看,也就是说只要你会PS,界面这种东西不成问题,靠队友的时候到了。

  7. 那么这时根据需求,我们所有的技术选择都已经齐全,可以开始着手写代码了。

  • HwcPlayer中有一个很不错的点子,把要用的所有include全写在一个头文件里每个都引一次,很不错的想法,懒人必备噢。

UI背后的逻辑问题

  • 函数接收什么样的参数?
  • 命令都是什么样的?
  • 如何组合字符串成为一个命令?
  • 如何读取文件并输入到播放列表中?
  • 每一个功能需要几个API?
  • 什么是alias别名?如何通过别名简化命令?
  • 这些API尽可能多地能组成什么样的功能?
  • 所以。。有谁会做UI吗?最后还是决定自己做

解决方案

mci函数参数
1
2
3
4
5
6
MCIERROR mciSendString(
      LPCTSTR lpszCommand,    //MCI命令字符串
      LPTSTR lpszReturnString, //存放反馈信息的缓冲区
      UINT cchReturn, //缓冲区的长度
      HANDLE hwndCallback  //回调窗口的句柄,一般为NULL
); //若成功则返回0,否则返回错误码。
MCI命令
命令 解释
open 打开设备
close 关闭设备
play 开始设备播放
stop 停止设备的播放或记录
record 开始记录
save 保存设备内容
pause 暂停设备的播放或记录
resume 恢复暂停播放或记录的设备
seek 改变媒体的当前位置
status 查询设备状态信息
capacility 查询设备能力
info 查询设备的信息
将字符串相互拼接产生可以被系统理解的MCI指令
  • strcpy和strcat任君选择
1
2
3
4
5
6
strcpy: char *strcpy(char* dest, const char *src);
//把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
//src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串
//返回指向dest的 指针。
strcat: extern char *strcat(char *dest, const char *src);
//把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')
呼出文件资源管理器实现读取文件路径并存放到指定链表节点
  • 需要注意最下方链表插入的路径不能为空,加一个if判断防止插入空数据报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void add()
{
TCHAR szBuffer[MAX_PATH] = { 0 };
OPENFILENAME file = { 0 };
file.hwndOwner = NULL;
file.lStructSize = sizeof(file);
file.lpstrFilter = "*文件(*.*)\0*.*\0";//要选择的文件后缀
file.lpstrFile = szBuffer;//存放文件的缓冲区
file.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
file.nFilterIndex = 0;
file.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;//标志如果是多选要加上OFN_ALLOWMULTISELECT
BOOL bSel = GetOpenFileName(&file);
Media* music = createMedia(file.lpstrFile);//创建的链表
if (music != NULL) {
headInsert(list, *music);
}
}
获取播放信息和播放位置
命令 解释
“status movie position” 播放位置
“status movie length” 播放总长度
“status movie mode” 播放状态
“seek movie to “ 指定位置
“seek movie to start” 定位到开头位置
“seek movie to end” 定位到最后位置
alias别名
  • 为长命令设置别名更有助于写代码

  • 由于对MCI的操作实际上就是命令操作,所以可以通过设置别名来进行操作mcisendstring函数

1
2
3
4
5
@doskey ls=dir /b $*
@doskey l=dir /od/p/q/tw $*
//命令 alias 别名
@REM notepad++工具设置别名为:npp
@doskey npp="C:\Program Files1\Notepad++\notepad++.exe" $

一些难点(许是太菜了)

  • 控制台页面时期的双缓冲刷新已经是过去式了
  • 文件读取路径包含空格无法读取
  • 通过呼出文件资源对话框实现导入文件(上文已提到)
  • 对话框式导入文件和easyx界面刷新冲突
  • 如何通过图片实现伪造的按钮特效
  • easyx图形界面的进度条和刷新页面的矛盾

解决方案

双缓冲原理有些复杂,命令行使用一个更简单的方案
  • 这种刷新是通过“不刷新”实现的,当字符在相同位置更新的时候会出现上一次未刷新而字符重叠的现象。可以通过使用长空白字符覆盖未刷新区域来实现“伪刷新”
1
2
3
4
5
6
//消除cls频闪函数
void cls() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coordScreen = { 0, 0 }; // home for the cursor
SetConsoleCursorPosition(hConsole, coordScreen);
}
MCI文件路径空格问题
  • mci读取文件的路径如果包含空格需要采用双引号包住整个路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int openMusic(const char* url)
{
if (url != NULL)
{
char cmd[500] = "";
strcpy_s(cmd, "open \"");//引号需要被转义
strcat_s(cmd, url);
strcat_s(cmd, "\"");//引号需要被转义
strcat_s(cmd, " alias MyMusic");
if (mciSendStringUtil(cmd, NULL) == 0)
{
return 0;
}
}
}
对话框式导入文件和easyx界面刷新冲突
  • 一个奇怪的bug,最后通过绝对路径解决,有大佬知道问题的可以评论区见
  1. 执行如下呼出文件资源管理器代码后正常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void add() {
TCHAR szBuffer[MAX_PATH] = { 0 };
OPENFILENAME file = { 0 };
file.hwndOwner = NULL;
file.lStructSize = sizeof(file);
file.lpstrFilter = "*文件(*.*)\0*.*\0";//要选择的文件后缀
file.lpstrFile = szBuffer;//存放文件的缓冲区
file.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
file.nFilterIndex = 0;
file.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;//标志如果是多选要加上OFN_ALLOWMULTISELECT
BOOL bSel = GetOpenFileName(&file);
Media* music = createMedia(file.lpstrFile);
if (music != NULL) {
headInsert(list, *music);
}
}
  1. 再执行刷新界面
1
2
3
4
HWND hwnd = initgraph(720, 960, 0);
//或者屏幕刷新等类似函数
loadimage(&play2, ".\\*.png", 81, 81);
loadimage(&pause, ".\\*.png", 81, 81);
  • 结果:页面变黑,有鼠标点击事件,图片无法加载
  1. 解决方案:所有加载的图片都指定绝对路径
1
2
loadimage(&play2, "D:\\visual studio project\\Project_List\\Project_List\\picture\\*.png", 81, 81);
loadimage(&pause, "D:\\visual studio project\\Project_List\\Project_List\\picture\\*.png", 81, 81);
伪造按钮特效
  • 提前准备好两张透明背景的png图片,执行鼠标点击动作时两种不同颜色的图层依次刷新,就可以实现鼠标点击的伪动态效果
1
2
3
4
5
6
7
8
9
10
11
12
13
void transimg(IMAGE* dstimg, int x, int y, IMAGE* srcimg)
{
HDC dstDC = GetImageHDC(dstimg);
HDC srcDC = GetImageHDC(srcimg);
int w = srcimg->getwidth();
int h = srcimg->getheight();
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
//半透明位图
AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
transimg(NULL, 334, 652, &IMAGE);//一种颜色的按钮
Sleep(100);
transimg(NULL, 334, 652, &IMAGE);//另一种颜色的按钮
进度条的制作
  • 刷新页面与刷新进度条
1
2
3
4
5
6
7
8
9
10
11
12
//进度条
while(1)
{
t = getMusicLength();
t1 = getMusicPosition();
if (t != 0)
{
c = t1 / t;
}
progress_length = c * 523 + 90;
fillroundrect(90, 830, progress_length, 825, 10, 10);
}

模块化设计

ListPage.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "all.h"
#include <wtypes.h>
void add();

int getNumOfNode();

char* getName(int num);

char* getPath(int num);

void del();

void printList();

ListPage.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "ListPage.h"
#include "FileToList.h"
#include <wtypes.h>
#include "playerWindow.h"
mediaNode* list = createList();
void add() {

TCHAR szBuffer[MAX_PATH] = { 0 };
OPENFILENAME file = { 0 };

file.hwndOwner = NULL;
file.lStructSize = sizeof(file);
file.lpstrFilter = "mp3文件(*.mp3)\0*.mp3\0";//要选择的文件后缀
file.lpstrFile = szBuffer;//存放文件的缓冲区
file.nMaxFile = sizeof(szBuffer) / sizeof(*szBuffer);
file.nFilterIndex = 0;
file.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;//标志如果是多选要加上OFN_ALLOWMULTISELECT
BOOL bSel = GetOpenFileName(&file);
Media* music = createMedia(file.lpstrFile);
if (music != NULL) {
headInsert(list, *music);
}
}

int getNumOfNode()
{
int num = 0;
mediaNode* pMove = list->next;
while (pMove != NULL) {
num++;
pMove = pMove->next;
}
return num;
}

//传入编号和主函数和链表返回歌曲名字
char* getName(int num) {

char name[200];
mediaNode* pMove = list->next;
if (pMove == NULL)
{
return (char*)"等待播放列表暂时还没有歌曲噢";
}
while (pMove != NULL) {
if (num == pMove->num) {
strcpy_s(name, sizeof(name), pMove->media.name);
break;
}
pMove = pMove->next;
}
return name;
}

char* getPath(int num) {
char path[200];
mediaNode* pMove = list->next;
while (pMove != NULL) {
if (num == pMove->num) {
strcpy_s(path, sizeof(path), pMove->media.path);
break;
}
pMove = pMove->next;
}
return path;
}

void printList()
{
mediaNode* pMove = list->next;
int i=0;
while (pMove != NULL)
{
printtext(320,60+i, pMove->media.name);
pMove = pMove->next;
i += 60;
}
}


void del()
{
deleteNode(list);
}


所有针对文件读取的操作(耦合播放列表的CRUD):

FileToList.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<stdlib.h>
#include<stdio.h>
#include <iostream>
#include <io.h>

typedef struct Media {
char name[200]; //歌曲名字
char path[500]; //绝对路径
char short_path[500]; //短路径
int length; //时长
};

typedef struct mediaNode {
Media media;
int num; //编号
struct mediaNode* pre;
struct mediaNode* next;
};

mediaNode* createList();

mediaNode* createNode(Media music);

void headInsert(mediaNode* headNode, Media music);

Media* createMedia(const char* path);

int deleteNode(mediaNode* headNode);

FileToList.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "FileToList.h"

mediaNode* createList()
{
mediaNode* headNode = (mediaNode*)malloc(sizeof(mediaNode));
headNode->next = NULL;
headNode->pre = NULL;
headNode->num = 0;
return headNode;
}
//创建结点
mediaNode* createNode(Media music)
{
mediaNode* newNode = (mediaNode*)malloc(sizeof(mediaNode));
newNode->media = music;
newNode->next = NULL;
newNode->pre = NULL;
newNode->num = 0;
return newNode;
}
//从头部插入结点
void headInsert(mediaNode* headNode, Media music)
{
mediaNode* node = createNode(music);
node->media = music;
if (headNode->next == NULL)
{
//链表为空
node->next = NULL;
node->pre = headNode;
headNode->next = node;
node->num = 1;
for (int i = 2; node->next != NULL; i++)
{
node = node->next;
node->num = i;
}
}
else
{
node->pre = headNode;
node->next = headNode->next;
headNode->next->pre = node;
headNode->next = node;
node->num = 1;
for (int i = 2; node->next != NULL; i++)
{
node = node->next;
node->num = i;
}
}
}

Media* createMedia(const char* path)
{
struct _finddata_t* musicInfo = (struct _finddata_t*)malloc(sizeof(struct _finddata_t));
long handle = _findfirst(path, musicInfo);
if (handle == -1)
{
return NULL; //未找到文件则返回NULL
}
else
{
// 为新建的Media结构体分配一块内存
Media* newMedia = (Media*)malloc(sizeof(Media));
// 初始化Media结构体中的参数
strcpy_s(newMedia->name, sizeof(newMedia->name), musicInfo->name);
strcpy_s(newMedia->path, sizeof(newMedia->path), path);
return newMedia;
}
}
//尾部删除结点
int deleteNode(mediaNode* headNode) {
mediaNode* node = headNode->next;
if (node == NULL)
{
return -1;
}
while (node->next != NULL)
{
node = node->next;
}
node->pre->next = NULL;
free(node);
return 0;
}

playerWindow.h

1
2
3
4
5
6
7
8
9
#pragma once
#include "all.h"
#include "util.h"
# include "ListPage.h"
void createWindow();
void fundmantual();
void printtext(int x, int y, char text[100]);
int getnum();
void setnum(int n);

playerWindow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
#include "playerWindow.h"
#include "playerPage.h"
#include "menuPage.h"

char nowName[100];

// 播放模式全局枚举
enum PLAY_STATUS play_mode = STATUS_PLAY_SEQUENCE;
char play_status[1000];
// 播放状态全局枚举
enum STATUS status = STATUS_STOPPED;
char status_now[1000];
int num = 0;
int progress_length = 90;//进度条长度
double t = 0;
double t1 = 0;
double c = 0;

void createWindow()
{
initgraph(720, 960,0);
char a[1000] = "";
strcpy(a, getPath(num));

openMusic(a);

setbkcolor(WHITE);

change();

//设置背景图片
IMAGE image;
loadimage(&image, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\background.png");
putimage(0, 0, &image);
transparentimage(NULL,0, 0, &image);

//暂停按钮
IMAGE pause;
IMAGE play2;
IMAGE play;
loadimage(&play2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\play2.png", 81, 81);
loadimage(&pause, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\play.png", 81, 81);
transparentimage(NULL, 334, 652, &pause);

//上一曲图标
IMAGE last;
loadimage(&last, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\last.png", 50, 50);
IMAGE last2;
loadimage(&last2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\last2.png", 50, 50);
transparentimage(NULL, 194, 666, &last);

//下一曲图标
IMAGE next;
loadimage(&next, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\next.png", 50, 50);
IMAGE next2;
loadimage(&next2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\next2.png", 50, 50);
transparentimage(NULL, 498, 671, &next);

//改模式图标
IMAGE change;
loadimage(&change, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\change.png",30,30);
IMAGE change2;
loadimage(&change2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\change2.png",30,30);
transparentimage(NULL, 92, 678, &change);

//快进图标
IMAGE up;
loadimage(&up, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\up.png", 36, 36);
IMAGE up2;
loadimage(&up2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\up2.png", 36, 36);
transparentimage(NULL, 618, 748, &up);

//快退图标
IMAGE down;
loadimage(&down, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\down.png", 36, 36);
IMAGE down2;
loadimage(&down2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\down2.png", 36, 36);
transparentimage(NULL, 94, 748, &down);

//音量加图标
IMAGE add1;
loadimage(&add1, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add.png", 40, 40);
IMAGE add2;
loadimage(&add2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add2.png", 40, 40);
transparentimage(NULL, 170, 870, &add1);

//音量减少图标
IMAGE add1_lr;
loadimage(&add1_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut.png", 40, 40);
IMAGE add2_lr;
loadimage(&add2_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut2.png", 40, 40);
transparentimage(NULL, 230, 870, &add1_lr);

IMAGE back;
loadimage(&back, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\back.png", 30, 30);
transparentimage(NULL, 15, 12, &back);

IMAGE circle;
loadimage(&circle, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\BREATHE.png", 340, 340);
transparentimage(NULL, 110, 40, &circle);

IMAGE issue;
loadimage(&issue, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\issue.png", 36, 36);
transparentimage(NULL, 608, 675, &issue);

setbkmode(TRANSPARENT);//设置文字输出时背景为透明

while (1)//要用个循环来不断监测鼠标事件
{
strcpy(nowName, getName(num));
printtext(242, 755, nowName);
printtext(91, 598, play_status);

//进度条
t = getMusicLength();
t1 = getMusicPosition();
if (t != 0)
c = t1 / t;
progress_length = c * 523 + 90;
fillroundrect(90, 830, progress_length, 825, 10, 10);

if (MouseHit())
{
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg)
{

case WM_LBUTTONDOWN:
if (msg.x >= 334 && msg.x <= 412 && msg.y <= 732 && msg.y >= 652)//播放按钮
{
printtext(2222, 755, getName(num));
printtext(91, 598, play_status);
strcpy(a, (const char*)getPath(num));//传歌曲路径
openMusic(a);
if (status == STATUS_STOPPED)
{

transparentimage(NULL, 334, 652, &play2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 334, 652, &pause);
playMusic();
status = STATUS_PLAY;
strcpy(status_now, "正在播放中");
}
else if (status == STATUS_PLAY)
{
transparentimage(NULL, 334, 652, &play2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 334, 652, &pause);
pauseMusic();
status = STATUS_PAUSE;
strcpy(status_now, "暂停中");
}
else if (status == STATUS_PAUSE)
{
transparentimage(NULL, 334, 652, &play2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 334, 652, &pause);
resumeMusic();
status = STATUS_PLAY;
strcpy(status_now, "正在播放中");
}

}//点击播放键

if (msg.x >= 202 && msg.x <= 236 && msg.y <= 709 && msg.y >= 676)//上一首
{
transparentimage(NULL, 194, 666, &last2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 194, 666, &last);
if (num > 1)
{
num -= 1;
}
//处理逻辑
fillroundrect(96, 830, 613, 825, 10, 10);

closeMusic();
fundmantual();

printtext(91, 598, play_status);
strcpy(a, (const char*)getPath(num));//传歌曲路径

openMusic(a);
playMusic();
}

if (msg.x >= 506 && msg.x <= 542 && msg.y <= 711 && msg.y >= 676)//下一首
{
transparentimage(NULL, 498, 671, &next2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 498, 671, &next);
if (num < getNumOfNode())
{
num += 1;
}
fillroundrect(96, 830, 613, 825, 10, 10);
closeMusic();
fundmantual();

printtext(91, 598, play_status);
strcpy(a, (const char*)getPath(num));//传歌曲路径

openMusic(a);
playMusic();
}

if (msg.x >= 618 && msg.x <= 654 && msg.y <= 784 && msg.y >= 748)//快进
{
transparentimage(NULL, 618, 748, &up2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 618, 748, &up);
//处理逻辑
upTo10s();
}

if (msg.x >= 94 && msg.x <= 130 && msg.y <= 784 && msg.y >= 748)//快退
{
transparentimage(NULL, 94, 748, &down2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 94, 748, &down);
//处理逻辑
downTo10s();
fundmantual();
}

//三种播放模式
if (msg.x >= 92 && msg.x <= 122 && msg.y <= 708 && msg.y >= 678)
{
transparentimage(NULL, 92, 678, &change2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 92, 678, &change);
if (play_mode == STATUS_PLAY_SEQUENCE)
{
play_mode = STATUS_PLAY_RANDOM;
strcpy(play_status, "当前播放状态: 随机播放");
fundmantual();
}
else if (play_mode == STATUS_PLAY_RANDOM)
{
play_mode = STATUS_PLAY_REPEAT;
strcpy(play_status, "当前播放状态: 循环播放");
fundmantual();
}
else if (play_mode == STATUS_PLAY_REPEAT)
{
play_mode = STATUS_PLAY_SEQUENCE;
strcpy(play_status, "当前播放状态: 列表播放");
fundmantual();
}
}

if (getMusicLength() == getMusicPosition() && play_mode == STATUS_PLAY_SEQUENCE)//列表播放状态的逻辑
{
if (num > 1)
{
num -= 1;
}
//处理逻辑
fillroundrect(96, 830, 613, 825, 10, 10);
closeMusic();
fundmantual();
printtext(91, 598, play_status);
strcpy(a, (const char*)getPath(num));//传歌曲路径

openMusic(a);
playMusic();
}

if (getMusicLength() == getMusicPosition() && play_mode == STATUS_PLAY_REPEAT)
{
fundmantual();
playMusicRepeat();
}
if (getMusicLength() == getMusicPosition() && play_mode == STATUS_PLAY_SEQUENCE)
{

}
if (msg.x >= 15 && msg.x <= 45 && msg.y <= 42 && msg.y >= 12)//返回
{
closegraph();
menu();

}//点击返回

if (msg.x >= 170 && msg.x <= 210 && msg.y <= 910 && msg.y >= 870)//加音量
{
transparentimage(NULL, 170, 870, &add2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 170, 870, &add1);
addVolume();
}

if (msg.x >= 230 && msg.x <= 270 && msg.y <= 910 && msg.y >= 870)//减音量
{
transparentimage(NULL, 230, 870, &add2_lr);//灰色的按钮
Sleep(100);
transparentimage(NULL, 230, 870, &add1_lr);
lowVolume();
}

if (msg.x >= 608 && msg.x <= 644 && msg.y <= 711 && msg.y >= 675)//网易云热评
{

/* transparentimage(NULL, 608, 675, &issue);*/
//处理逻辑
WinExec("C:\\Program Files\\Internet Explorer\\IExplore.exe https://www.musicbooks.cn/", 1);
}

break;
}
}

if (getMusicLength() == getMusicPosition() && play_mode == STATUS_PLAY_SEQUENCE && num > 0)//列表播放状态的逻辑
{
if (num > 1)
{
num -= 1;
}
//处理逻辑
fillroundrect(96, 830, 613, 825, 10, 10);
closeMusic();
fundmantual();
printtext(91, 598, play_status);
strcpy(a, (const char*)getPath(num));//传歌曲路径
openMusic(a);
playMusic();
}
if (getMusicLength() == getMusicPosition() && play_mode == STATUS_PLAY_REPEAT && num > 0)
{
playMusicRepeat();
}
if (getMusicLength() == getMusicPosition() && play_mode == STATUS_PLAY_SEQUENCE && num > 0)
{
/* printf("随机播放");*/
}
}
}

void fundmantual()
{
initgraph(720, 960, 0);
char a[1000] = "";
strcpy(a, getPath(num));

openMusic(a);
setbkcolor(WHITE);

change();

//设置背景图片
IMAGE image;
loadimage(&image, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\background.png");
putimage(0, 0, &image);
transparentimage(NULL, 0, 0, &image);

//暂停按钮
IMAGE pause;
IMAGE play2;
IMAGE play;
loadimage(&play2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\play2.png", 81, 81);
loadimage(&pause, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\play.png", 81, 81);
transparentimage(NULL, 334, 652, &pause);

//上一曲图标
IMAGE last;
loadimage(&last, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\last.png", 50, 50);
IMAGE last2;
loadimage(&last2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\last2.png", 50, 50);
transparentimage(NULL, 194, 666, &last);

//下一曲图标
IMAGE next;
loadimage(&next, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\next.png", 50, 50);
IMAGE next2;
loadimage(&next2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\next2.png", 50, 50);
transparentimage(NULL, 498, 671, &next);

//改模式图标
IMAGE change;
loadimage(&change, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\change.png", 30, 30);
IMAGE change2;
loadimage(&change2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\change2.png",30, 30);
transparentimage(NULL, 92, 678, &change);

//快进图标
IMAGE up;
loadimage(&up, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\up.png", 36, 36);
IMAGE up2;
loadimage(&up2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\up2.png", 36, 36);
transparentimage(NULL, 618, 748, &up);

//快退图标
IMAGE down;
loadimage(&down, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\down.png", 36, 36);
IMAGE down2;
loadimage(&down2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\down2.png", 36, 36);
transparentimage(NULL, 94, 748, &down);

IMAGE back;
loadimage(&back, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\back.png", 30, 30);
transparentimage(NULL, 15, 12, &back);

IMAGE circle;
loadimage(&circle, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\BREATHE.png", 340, 340);
transparentimage(NULL, 110, 40, &circle);

//音量加图标
IMAGE add1;
loadimage(&add1, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add.png", 40, 40);
IMAGE add2;
loadimage(&add2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add2.png", 40, 40);
transparentimage(NULL, 170, 870, &add1);

//音量减少图标
IMAGE add1_lr;
loadimage(&add1_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut.png", 40, 40);
IMAGE add2_lr;
loadimage(&add2_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut2.png", 40, 40);
transparentimage(NULL, 230, 870, &add1_lr);

IMAGE issue;
loadimage(&issue, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\issue.png", 36, 36);
transparentimage(NULL, 608, 675, &issue);

}

char* attainlength(int time) {
int fen = 0;
int miao = 0;
miao = (int)time / 1000;
fen = (int)miao / 60;
miao = (int)miao - fen * 60;
char f[100];//分
char m[100];//秒
char tatol[100];//总的
itoa(miao, m, 10);
itoa(fen, f, 10);
strcpy(tatol, f);
strcat(tatol, " : ");
if (miao < 10)
{
strcat(tatol, "0");
}
strcat(tatol, m);
return tatol;
}

void printtext(int x, int y,char text[100])
{
settextcolor(WHITE);
setbkmode(TRANSPARENT);//设置文字输出时背景为透明
outtextxy(x, y, text);
}

int getnum()
{
return num;
}

void setnum(int n)
{
num = n;
}

定义大多数常用接口:

util.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#pragma once
#include "all.h"

// 代表三种不同的播放模式
enum PLAY_STATUS
{
STATUS_PLAY_SEQUENCE = 0,
STATUS_PLAY_REPEAT,
STATUS_PLAY_RANDOM,
};

// 代表当前音乐的播放状态
enum STATUS
{
STATUS_PLAY = 0,
STATUS_PAUSE,
STATUS_STOPPED,
};

//通过MCI接口API指令操作音乐文件
// 成功: return 0
// 失败: return !=0
// returnString: 返回错误字符串信息
//
int mciSendStringUtil(const char* url, char* returnString);

//打开设备: 默认MP3
// 通过MCI接口API指令操作音乐文件
// 其中mciSendString指令被封装于mciSendStringUtil中
// 通过open字符串拼接传参并赋予别名"MyMusic"
// 后续相同操作只需指明别名
// 成功: return 0
// 失败: return !=0
//
int openMusic(const char* url);

//以下函数中将包含MyMusic别名
// 通过别名对mciSendString接口传参
// 即包含了open命令:
// 定义open设备操作为MyMusic
//

//设备开始播放音乐
int playMusic();

//设备暂停播放音乐
int pauseMusic();

//设备继续播放音乐
int resumeMusic();

//设备停止播放音乐
int stopMusic();

//设备重复播放音乐
int playMusicRepeat();

//设备关闭
// 设备关闭接口,而非音乐停止接口
//
int closeMusic();

//返回当前播放位置
int getMusicPosition();

//返回播放音乐的总长度
int getMusicLength();

//设置指定播放位置
// 通过外部传参position实现
// 执行"seek 别名 to 位置"指令
// 使音乐到达指定位置:
// 参数说明:
// //任意位置: position
// //定位音乐开头位置: start
// //定位音乐最后位置: end
//
int gotoPosition(int position);

int getMusicSpeed();

void setMusicSpeed(int speed);

void transparentimage(IMAGE* dstimg, int x, int y, IMAGE* srcimg);

void change();

void addVolume();

void lowVolume();

//集成绝大多数MCI的API指令封装为简单的接口
// mci集成工具集: util.cpp
//

util.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include "util.h"
#include<graphics.h>

using namespace std;

//通过MCI接口API指令操作音乐文件
// 成功: return 0
// 失败: return !=0
// returnString: 返回错误字符串信息
//
int mciSendStringUtil(const char* url, char* returnString)
{
if (url == NULL)
{
if (0 != mciSendString(url, NULL, 0, NULL))
{
return -1;
}
else {
return 0;
}
}
else
{
if (0 != mciSendString(url, returnString, 1024, NULL)) {
return -2;
}
else {
return 0;
}
}
}

//打开设备: 默认MP3
// 通过MCI接口API指令操作音乐文件
// 其中mciSendString指令被封装于mciSendStringUtil中
// 通过open字符串拼接传参并赋予别名"MyMusic"
// 后续相同操作只需指明别名
// 成功: return 0
// 失败: return !=0
//
int openMusic(const char* url)
{
if (url != NULL)
{
char cmd[500] = "";
strcpy_s(cmd, "open \"");
strcat_s(cmd, url);
strcat_s(cmd, "\"");
strcat_s(cmd, " alias MyMusic");
if (mciSendStringUtil(cmd, NULL) == 0)
{
return 0;
}
}
}

//以下函数中将包含MyMusic别名
// 通过别名对mciSendString接口传参
// 即包含了open命令:
// 定义open设备操作为MyMusic
//

//设备开始播放音乐
int playMusic()
{
char cmd[500] = "play MyMusic";
return mciSendStringUtil(cmd, NULL);
}

//设备暂停播放音乐
int pauseMusic()
{
char cmd[500] = "pause MyMusic";
return mciSendStringUtil(cmd, NULL);
}

//设备继续播放音乐
int resumeMusic()
{
char cmd[500] = "resume MyMusic";
return mciSendStringUtil(cmd, NULL);
}

//设备停止播放音乐
int stopMusic()
{
char cmd[500] = "stop MyMusic";
return mciSendStringUtil(cmd, NULL);
}

//设备重复播放音乐
int playMusicRepeat()
{
char cmd[1000] = "play MyMusic repeat";
return mciSendStringUtil(cmd, NULL);
}

//设备关闭
// 设备关闭接口,而非音乐停止接口
int closeMusic()
{
char cmd[1000] = "close MyMusic";
return mciSendStringUtil(cmd, NULL);
}

//返回当前播放位置
int getMusicPosition()
{
char szTimeBuffer[1024];
mciSendStringUtil("status MyMusic position", szTimeBuffer);
return atoi(szTimeBuffer);
}

//返回播放音乐的总长度
int getMusicLength()
{
char szTimeBuffer[1024];
mciSendStringUtil("status MyMusic length", szTimeBuffer);
return atoi(szTimeBuffer);
}

//设置指定播放位置
// 通过外部传参position实现
// 执行"seek 别名 to 位置"指令
// 使音乐到达指定位置:
// 参数说明:
// //任意位置: position
// //定位音乐开头位置: start
// //定位音乐最后位置: end
//
int gotoPosition(int position)
{
char cmd[1000] = "";
sprintf(cmd, "seek MyMusic to %d", position);
return mciSendStringUtil(cmd, NULL);
}

int getMusicSpeed()
{
char szSpeedBuffer[1024];
mciSendStringUtil("status MyMusic speed", szSpeedBuffer);
return atoi(szSpeedBuffer);
}

void setMusicSpeed(int speed)
{
char cmd[1000] = "";
sprintf(cmd, "set MyMusic speed %d", speed);
mciSendStringUtil(cmd, NULL);
}

void transparentimage(IMAGE* dstimg, int x, int y, IMAGE* srcimg)
{
HDC dstDC = GetImageHDC(dstimg);
HDC srcDC = GetImageHDC(srcimg);
int w = srcimg->getwidth();
int h = srcimg->getheight();

// 结构体的第三个成员表示额外的透明度,0 表示全透明,255 表示不透明。
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
// 使用 Windows GDI 函数实现半透明位图
AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}

void change() //实现无边框窗口
{
HWND hnd = GetHWnd();//获取窗口句柄
SetWindowText(hnd, "玉玉云音乐播放器");
}

void upTo10s()
{
int time = getMusicPosition() + 10000;
if (time > getMusicLength())
{
time = getMusicLength();
}
gotoPosition(time);
playMusic();
}

void downTo10s()
{
int time = getMusicPosition() - 10000;
if (time < 0)
{
time = 0;
}
gotoPosition(time);
playMusic();
}

void addVolume()
{
char vo[20];
char res[260];
char file1[100] = "setaudio MyMusic volume to "; // to后面一定要有空格,不然会报错

mciSendString("status MyMusic volume", res, 260, NULL);
int volume = 0;
volume = atoi(res); // 转化语句
volume += 200;
if (volume >= 1000)
volume = 1000;
itoa(volume, vo, 10); //转化语句
strcat(file1, vo); // 将vo接在file1后面
mciSendString(file1, 0, 0, 0); // 设定成功
}

void lowVolume()
{
char vo[20];
char res[260];
char file1[100] = "setaudio MyMusic volume to "; // to后面一定要有空格,不然会报错
mciSendString("status MyMusic volume", res, 260, NULL);
int volume = 0;
volume = atoi(res); // 转化语句
volume -= 200;
if (volume <= 0)
volume = 0;
itoa(volume, vo, 10); //转化语句
strcat(file1, vo); // 将vo接在file1后面
mciSendString(file1, 0, 0,0); // 设定成功
}

//集成绝大多数MCI的API指令封装为简单的接口
// mci集成工具集: util.cpp
//

定义大多数常用头文件(偷懒):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma once
#include <Audioclient.h>
#include <ShlObj.h>
#include <Windows.h>
#include <conio.h>
#include <cstdbool>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <endpointvolume.h>
#include <fstream>
#include <io.h>
#include <iostream>
#include <mmdeviceapi.h>
#include <mmsystem.h>
#include <string>
#include <strsafe.h>
#include <vector>
#include <graphics.h>
#pragma comment(lib, "winmm.lib")

menuPage.h

1
2
3
4
#pragma once
#include "all.h"
void copyright();
void menu();

menuPage.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "menuPage.h"
#include "util.h"
#include "playerWindow.h"
#include "listmenu.h"

void menu()
{
int logostatus = 0;
initgraph(640, 480, 0);
//背景图片
IMAGE img1;
loadimage(&img1, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\mainmenu.png");
putimage(0, 0, &img1);

IMAGE choice;
loadimage(&choice, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\menuchoice.png");

while (1) {
//鼠标操作
if (MouseHit()) {
MOUSEMSG msg = GetMouseMsg();

//显示灰色块块
if (msg.x >= 369 && msg.x <= 583 && msg.y >= 69 && msg.y <= 160 && logostatus == 0) {
transparentimage(NULL, 369, 69, &choice);
logostatus = 1;

}
else if (msg.x >= 369 && msg.x <= 583 && msg.y >= 195 && msg.y <= 264 && logostatus == 0)
{
transparentimage(NULL, 369, 195, &choice);
logostatus = 1;
}
else if (msg.x >= 369 && msg.x <= 583 && msg.y >= 321 && msg.y <= 390 && logostatus == 0)
{
transparentimage(NULL, 369, 321, &choice);
logostatus = 1;
}
else
{
putimage(0, 0, &img1);
logostatus = 0;
}

switch (msg.uMsg)
{
case WM_LBUTTONDOWN:

if (msg.x >= 369 && msg.x <= 583 && msg.y >= 69 && msg.y <= 160) {
closegraph();
createWindow();

}
else if (msg.x >= 369 && msg.x <= 583 && msg.y >= 195 && msg.y <= 264)
{
closegraph();
listmenu();
}
else if (msg.x >= 369 && msg.x <= 583 && msg.y >= 321 && msg.y <= 390)
{
closegraph();
copyright();
}
break;
default:
break;
}
}
}
}

void copyright() {
initgraph(720,960, 0);
setbkmode(TRANSPARENT);

//背景图片
IMAGE im;
loadimage(&im, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\copyright.png");
putimage(0, 0, &im);

//返回按钮
IMAGE back;
loadimage(&back, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\back.png", 30, 30);
transparentimage(NULL, 15, 12, &back);

while (1)//要用个循环来不断监测鼠标事件
{
if (MouseHit())
{
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg)
{
case WM_LBUTTONDOWN:
if (msg.x >= 15 && msg.x <= 45 && msg.y <= 42 && msg.y >= 12)//返回
{
closegraph();
menu();

}//点击返回
if (msg.x >= 114 && msg.x <= 584 && msg.y >= 805 && msg.y <= 853) {
WinExec("C:\\Program Files\\Internet Explorer\\IExplore.exe https://github.com/xiao-luo17", 1);
}
}
}
}
}

main.h

1
2
3
#pragma once
#include "playerPage.h"
#include "all.h"

main.cpp

1
2
3
4
5
#include "main.h"
int main()
{
playerPage();
}

listmenu.h

1
2
3
4
5
6
#include "playerWindow.h"
#include "playerPage.h"
#include "menuPage.h"

void listmenu();
void fundmantual2();

listmenu.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include"listmenu.h"

void listmenu()
{
initgraph(640, 480, 0);

//背景图片
IMAGE img;
loadimage(&img, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\musiclist.png");
putimage(0, 0, &img);
transparentimage(NULL, 0, 0, &img);

//返回图标
IMAGE back;
loadimage(&back, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\back.png", 30, 30);
transparentimage(NULL, 15, 12, &back);
printList();

//添加图标
IMAGE add1;
loadimage(&add1, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add.png", 40, 40);
IMAGE add2;
loadimage(&add2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add2.png", 40, 40);
transparentimage(NULL, 238, 284, &add1);

//减少图标
IMAGE add1_lr;
loadimage(&add1_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut.png", 40, 40);
IMAGE add2_lr;
loadimage(&add2_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut2.png", 40, 40);
transparentimage(NULL, 238, 359, &add1_lr);

while (1)
{

if (MouseHit())
{
MOUSEMSG msg = GetMouseMsg();
switch (msg.uMsg)
{
case WM_LBUTTONDOWN:
if (msg.x >= 15 && msg.x <= 45 && msg.y <= 42 && msg.y >= 12)//返回
{
closegraph();
menu();

}//点击返回

if (msg.x >= 238 && msg.x <= 278 && msg.y <= 324 && msg.y >= 284)//添加
{
transparentimage(NULL, 92, 576, &add2);//灰色的按钮
Sleep(100);
transparentimage(NULL, 92, 576, &add1);
setnum(getnum() + 1);
add();
//设置背景图片
fundmantual2();
}

if (msg.x >= 238 && msg.x <= 278 && msg.y <= 419 && msg.y >= 359)//删除
{
transparentimage(NULL, 612, 576, &add2_lr);//灰色的按钮
Sleep(100);
transparentimage(NULL, 612, 576, &add1_lr);
if (getnum() == getNumOfNode()) {
setnum(getnum() - 1);
closeMusic();
}
del();
//设置背景图片
fundmantual2();
}
}
}
}
}

void fundmantual2()
{
initgraph(640, 480, 0);

//背景图片
IMAGE img;
loadimage(&img, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\musiclist.png");
putimage(0, 0, &img);
transparentimage(NULL, 0, 0, &img);

//返回图标
IMAGE back;
loadimage(&back, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\back.png", 30, 30);
transparentimage(NULL, 15, 12, &back);
printList();

//添加图标
IMAGE add1;
loadimage(&add1, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add.png", 40, 40);
IMAGE add2;
loadimage(&add2, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\add2.png", 40, 40);
transparentimage(NULL, 238, 284, &add1);

//减少图标
IMAGE add1_lr;
loadimage(&add1_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut.png", 40, 40);
IMAGE add2_lr;
loadimage(&add2_lr, "D:\\visual studio project\\yuyucloudmusic v2.4\\Project_List\\picture\\cut2.png", 40, 40);
transparentimage(NULL, 238, 359, &add1_lr);
}

playerPage.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once
#include "all.h"
#include "util.h"
#include "FileToList.h"
#include "ListPage.h"
void playerPage();
void playerPagePrint();
void upTo10s();
void downTo10s();
void printMusicPosition();
void aboutPagePrint();
void ListPagePrint();
void cls();

playerPage.cpp

1
2
3
4
5
6
7
8
9
10
#include "playerPage.h"
#include "playerWindow.h"
#include "menuPage.h"
#pragma comment( lib, "MSIMG32.LIB")
using namespace std;

void playerPage()
{
menu();
}