电子相册实验

第一部分:电子相册,界面及功能展示如下

image-20210125120234567

1.1交互互动高亮显示

image-20210125120346046

1.2点击出现方框,方框内小图对应的大图预览

image-20210125120408573

1.3点击箭头,小图边框向下切换,同时大图显示切换

image-20210125120554045

1.4背景音乐


第二部分:项目分析

2.1ToDO清单:

2.1.1实现基本界面

2.1.2两个按钮绘制及功能实现

①按钮功能,鼠标进入黄色高亮

② 点击一下,出现矩形方框并切换

③点击,方框内的小图与切换的大图同步显示

2.1.3加载音乐


2.2难点:如何让小图和大图同步,以及点击翻页逻辑实现


2.3需要提前掌握的C基础知识

①数组

②函数的声明,调用及全局变量

③for,while循环语句

④if,else-if, switch选择语句


2.4需要额外掌握的技能分析

①窗口可视化编程

②贴图


2.5项目流程:

《1》 加载资源
《2》 画按钮
《3》 交互处理①(进入高亮,点击按钮事件,小图显示方框)
《4》 交互处理②-小图显示的方框切换对应大图片

第三部分:项目代码实战

3.1 《加载资源》

3.1.1基本可视化编程教程——利用graphcis.h库的initgraph()函数,比如创建一个800*600大小的窗口

/****************************
    具备能力:
    1.基本可视化编程
        1.1  initgraph(800,600); 比如创建一个800*600的窗口
        1.2  关闭窗口 closegraph()
***************************/
#include<stdio.h> //基本库
#include<graphics.h> //图形库
int main()
{
    initgraph(800, 600); //创建一个800*600的窗口
    getchar();//输入等待,不然窗口一闪而过,
    //或者可以使用死循环
    //while(1);//代替
    closegraph();//一般程序退出之前关闭窗口
    return 0;
}

执行如下图

image-20210125121503400

如果没有graphics.h库文件编译可能会报错,可以通过EasyX插件安装

image-20210125121649010

3.1.2贴图(三步曲,创建变量,加载,显示)

#include<stdio.h>
#include<graphics.h>
int main()
{
    initgraph(932, 538); // 根据素材像素大小创建同样大小窗口
    IMAGE backImg;//第一步,创建一个名为backImg的背景图变量
    loadimage(&backImg, "jiemian.jpg"); //第二步,加载界面背景框,注意资源文件路径为相对路径,为当前工作目录。注意&,传入变量名的地址
    //loadimage(&backImg, "jiemian.jpg",600,400);//缩放的形式,缩放到600,400
    putimage(0, 0, &backImg);//第三步,在坐标有0,0处,放置图片
    getchar();
    closegraph();
    return 0;
}

Tips: 素材拷入工程目录下(VC++6.0)

image-20210125123914051

或者是vs2015

image-20210125123951710

执行效果如下

image-20210125124007938

3.1.3贴图功能封装为drawMap()函数(思考一下,为什么要封装函数)

#include<stdio.h>
#include<graphics.h>
/*****************************************
*   初始化界面
*   画界面, 画背景,画按钮, 画文字
*   drawMap();
******************************************/
void drawMap()
{
    IMAGE backImg,smallCar0,smallCar1,bigCar0; // 第一步,创建IMAGE类型变量,4个
    //第二步,定义图片加载的方式
    loadimage(&backImg,"jiemian.jpg");
    loadimage(&smallCar0,"0.jpg",150,160);
    loadimage(&smallCar1,"1.jpg",150,160);
    loadimage(&bigCar0,"0.jpg",500,400);
    //第三步,在具体坐标显示图片
    putimage(0, 0, &backImg);
    putimage(80, 130, &smallCar0); //具体位置,用截图工具去测量,需要在哪里画 记住大致的位置 取整数即可
    putimage(80, 330, &smallCar1); //位置计算, 加上每一张小图的大小, 160+130=290,稍微大一点到310
    putimage(345,100,&bigCar0);
    
}

---

封装为函数之后,不调用是不会有效果的

```c
int main()
{
    initgraph(932, 538); // 根据素材像素大小创建同样大小窗口
    drawMap(); //封装的函数一定要记得在main里面调用,绘制界面
    getchar();
    closegraph();
    return 0;
}


观察上面的代码会发现,我们把基础图片的功能做出来了。但是这个功能封装完之后不完善:

①只显示了第0张和第1张照片

②代码冗余,如果有8张照片,我们的IMAGE变量要有8个,loadimage()函数和putimage()函数就要放8个

解决办法

封装一个加载资源的函数loadResource(),复用loadimage()函数, 同时将变量图片作为数组保存下来


3.1.4封装loadResouce()函数,加载资源

部分代码如下

```c
//全局变量
IMAGE backImg; //存放背景变量
IMAGE carBig[8];//存放大车
IMAGE carSmall[8];//存放小车
/*****************************************
*   初始化资源
*   封装一个函数,初始化数据:初始化变量
*   loadResource(); 没有返回值
******************************************/
void loadResource()
{

    loadimage(&backImg, "jiemian.jpg");
    //笨方法写
    loadimage(carSmall+0, "0.jpg",150, 160);  //注意这里,数组名就是地址,不需要对变量名取地址了
    loadimage(carSmall+1, "1.jpg",150, 160);
    loadimage(carSmall+2, "2.jpg",150, 160);
    loadimage(carSmall+3, "3.jpg",150, 160);
    loadimage(carSmall+4, "4.jpg",150, 160);  //注意这里,数组名就是地址,不需要对变量名取地址了
    loadimage(carSmall+5, "5.jpg",150, 160);
    loadimage(carSmall+6, "6.jpg",150, 160);
    loadimage(carSmall+7, "7.jpg",150, 160);

    loadimage(carBig+0,"0.jpg", 500, 400);  //注意这里,数组名就是地址,不需要对变量名取地址了
    loadimage(carBig+1,"1.jpg", 500, 400);
    loadimage(carBig+2,"2.jpg", 500, 400);
    loadimage(carBig+3,"3.jpg", 500, 400);
    loadimage(carBig+4,"4.jpg", 500, 400);  //注意这里,数组名就是地址,不需要对变量名取地址了
    loadimage(carBig+5,"5.jpg", 500, 400);
    loadimage(carBig+6,"6.jpg", 500, 400);
    loadimage(carBig+7,"7.jpg", 500, 400);
}
/*****************************************
*   初始化界面
*   画界面, 画背景,画按钮, 画文字
*   drawMap();
******************************************/
void drawMap()
{
    //画背景
    putimage(0, 0, &backImg); //传入地址 ,后面是carSmall数组名本身就是地址
    //画小图 第0张和第1张
    putimage(80, 130, carSmall + 0); //具体位置,用截图工具去测量,需要在哪里画 记住大致的位置 取整数即可
    putimage(80, 330, carSmall + 1); //位置计算, 加上每一张小图的大小, 160+130=290,稍微大一点到310
    //画大图
    putimage(345,100,carBig+0);
}

同时要注意,main()函数中要调用刚刚封装的函数


int main()
{
    initgraph(932, 538); // 根据素材像素大小创建同样大小窗口
    loadResource(); //依然要记得调用刚刚的函数,加载整个资源
    drawMap();
    getchar();
    closegraph();
    return 0;
}
image-20210125151325293
    ①观察loadResource()代码,发现这是一个笨方法,我们只是实现了图片以不同大小的方式穷举加载

    ②简化loadResource()代码,我们就需要循环,但是循环中,路径是不断的变化的,我们传递进去的图片名是0开头,7结尾的数字

    ③用for循环中的i变量 替代 0,1,2,3,4,5,6,7这些数字

    ④思考一下,我们可以简单的 loadimage(carBig+i,"i.jpg",500,400)和 loadimage(carsmall+i,"i.jpg",150,160)吗?

该库中的函数,并没有这种传递i的功能

介绍一个新的系统函数 sprintf(),把路径在for循环里面加上i的变化,以写入字符串的方式来加载


3.1.5循环处理loadResource()函数代码

void loadResource()
{
    loadimage(&backImg, "jiemian.jpg");
    //for循环批量加载:因为文件名有规律格式 从0.jpg到7.jpg
    for (int i = 0; i <= 7; i++)
    {
        char fileName[20] = "";
        // 0.jpg 1.jpg 2.jpg .....
        sprintf(fileName, "%d.jpg", i); //把文件名 *.jpg 这个作为路径名写入数组, 那么循环8次,就初始化了8次
        loadimage(carBig + i, fileName, 500, 400);
        loadimage(carSmall + i, fileName, 150, 160);
    }
}

Tips:使用sprintf()函数,VS2015会需要在最开头加上一个宏定义#define _CRT_SECURE_NO_WARNINGS
避免安全检查错误


drawMap()函数代码不变,main函数()代码不变


3.2《画按钮》

3.2.1按钮是一个填充圆,内嵌一个空心圆,以及箭头。那么我们就需要掌握,画圆和画线的函数

①solidcircle(x,y,r) 实心圆及填充颜色参数设置 setfillcolor(BLACK)

②circle(x,y,r)空心圆

③line(x,y,xx,yy)两点确定一条线,以及设置线型setlinestyle(PS_SOLID,pixel_width,0)及线颜色setlinecolor(BLACK)

//此段代码复制进入drawButton()函数
    setfillcolor(BLACK);// 设置填充颜色为黑色
    solidcircle(50, 50, 20);//在x,y的位置画一个半径为20的圆
    setlinecolor(BLACK);//设置线的颜色为白色
    setlinestyle(PS_SOLID, 3, 0);//设置线的格式, 实线,3个像素宽,0为自适应
    line(50,60,100,60); 

画按钮的功能比较复杂,所以我们要封装进一个函数,以后再遇到需要画按钮的地方,直接复制粘贴就可以了

3.2.2drawButton()函数封装

问题分析,画2个按钮,需要在相应的坐标放置,同时是左右两个按钮,可以通过传递按钮标记,实现不同按钮的箭头方向绘制

/*****************************************
*   画按钮
*   drawButton();
*   有三个参数,坐标及左右按钮标记
*   画线函数 line(int x,int y,int xx,int yy) 两点确定一条线,三条线画一个箭头
*   画圆,实心圆solidcircle(x,y,R),空心圆 circle(x,y,R)
*   实心圆填充颜色 setfillcolor(),空心圆线条颜色 setlinecolor()
******************************************/
void drawButton(int x,int y, char postion) //x,y传递进来按钮的坐标, postion传递朝向标记 <--- l   ---> r  
{
    setfillcolor(BLACK);// 设置填充颜色为黑色
    solidcircle(x, y, 20);//在x,y的位置画一个半径为20的圆
    setlinecolor(WHITE);//设置线的颜色为白色
    setlinestyle(PS_SOLID, 3, 0);//设置线的格式, 实线,3个像素宽,0为自适应
    if (postion == 'r')
    {
        circle(x, y, 15);//圆中圆,半径比20小一点,定位15
    }
    else if (postion == 'l') //左按钮的箭头及圆待完善
    {
    }
}

现在,右边的按钮实现了一半的功能,我们边写代码 变调试,画画看样子,删除main()中关于画圆及线的代码

并且在drawMap()函数里面,调用drawButton(),记得传递要绘制按钮的坐标 x,y,以及按钮标记r或者l

void drawMap()
{
    //画背景
    putimage(0, 0, &backImg);
    //画小图 第0张和第1张
    putimage(80, 130, carSmall + 0); //具体位置,用截图工具去测量,需要在哪里画 记住大致的位置 取整数即可
    putimage(80, 330, carSmall + 1); //位置计算, 加上每一张小图的大小, 160+130=290,稍微大一点到310
    //画大图
    putimage(345,100,carBig+0);
    drawButton(180, 120, 'r'); //传递坐标进来
}
int main()
{
    initgraph(932, 538); // 根据素材像素大小创建同样大小窗口
    loadResource(); //依然要记得调用刚刚的函数
    drawMap();
    getchar();
    closegraph();
    return 0;
}

如下图所示

image-20210125162430348

然后在drawMap()里面调用drawButton()函数,通过传递不同的x,y值进去,略微调整一下按钮的位置

void drawMap()
{
    //画背景
    putimage(0, 0, &backImg);
    //画小图 第0张和第1张
    putimage(80, 130, carSmall + 0); //具体位置,用截图工具去测量,需要在哪里画 记住大致的位置 取整数即可
    putimage(80, 330, carSmall + 1); //位置计算, 加上每一张小图的大小, 160+130=290,稍微大一点到310
    //画大图
    putimage(345,100,carBig+0);
    //画按钮比较复杂,需要封装函数
    // 按钮边画边试
    drawButton(200, 90, 'r'); //画右边按钮
}
image-20210125162556011

位置差不多了,我们来把drawButton()函数中的箭头功能补齐,这个箭头实际上就是三根实线:一根横线以及向上和向下的两根斜线

依然是边画边试,keep in mind,前面我们传递进来的x,y坐标确定了按钮的绝对位置,画线就是根据圆心坐标 x,y的相对位置的坐标来画线段

void drawButton(int x,int y, char postion) //按钮的坐标, 和朝向标记 <--- l   ---> r  
{
    setfillcolor(BLACK);// 设置填充颜色为黑色
    solidcircle(x, y, 20);//在x,y的位置画一个半径为20的圆
    setlinecolor(WHITE);//设置线的颜色为白色
    setlinestyle(PS_SOLID, 3, 0);//设置线的格式, 实线,3个像素宽,0为自适应

    if (postion == 'r')
    {
        circle(x, y, 15);//圆中圆
        //画线,做简单的计算,圆心坐标x,y定位,左右减加5
        line(x - 10, y, x + 10,y);//画横线
        line(x - 3,y - 5,x + 10,y);//画箭头上横线, 从一个点画到 x+10,y这个点,调试 前面2个参数到合适位置
        line(x - 3, y + 5, x + 10, y);//画箭头下横线,对称处理
    }
    else if (postion == 'l')
    {
    }
}
image-20210125163058089

按钮美化的工作,可以自己按审美完成,调整x±数值与y±数值即可

我们来补齐左边按钮,以及在drawMap()函数里面把左边按钮传递进去给绘制出来,并且在大图上方空白处显示相应的文字

void drawButton(int x,int y, char postion) //按钮的坐标, 和朝向标记 <--- l   ---> r  
{
    setfillcolor(BLACK);// 设置填充颜色为黑色
    solidcircle(x, y, 20);//在x,y的位置画一个半径为20的圆
    setlinecolor(WHITE);//设置线的颜色为白色
    setlinestyle(PS_SOLID, 3, 0);//设置线的格式, 实线,3个像素宽,0为自适应

    if (postion == 'r')
    {
        circle(x, y, 15);//圆中圆
        //画线,坐下简单的计算,圆心坐标定位, 左右减加5
        line(x - 10, y, x + 10,y);//画横线
        line(x + 3, y - 5, x + 10, y);//画箭头上横线, 从一个点画到 x+10,y这个点,调试 前面2个参数到合适位置
        line(x + 3, y + 5, x + 10, y);//画箭头下横线,对称处理
    }
    else if (postion == 'l')//画了右边箭头,现在来画左边箭头,坐标处理一下
    {
        circle(x, y, 15);
        line(x - 10, y, x + 10, y);
        line(x - 3, y - 5, x - 10, y);
        line(x - 3, y + 5, x - 10, y);
    }
}
void drawMap()
{
    //画背景
    putimage(0, 0, &backImg);
    //画小图 第0张和第1张
    putimage(80, 130, carSmall + 0); //具体位置,用截图工具去测量,需要在哪里画 记住大致的位置 取整数即可
    putimage(80, 330, carSmall + 1); //位置计算, 加上每一张小图的大小, 160+130=290,稍微大一点到310
    //画大图
    putimage(345,100,carBig+0);
    drawButton(200, 90, 'r'); //画右边按钮
    drawButton(115, 90, 'l'); //画左边按钮

    //输出文字,显示标题
    settextcolor(RED); //设置文字颜色为蓝色
    settextstyle(25, 0, "STCAIYUN");//设置字体大小25到0,和字体 字体在c盘windows下的fonts文件夹 赋值字体名字
    //setbkmode(TRANSPARENT); //有背景,去掉文字背景
    outtextxy(350, 50, "微电子-机械之心");
}

文字是有背景的,取消setbkmode的注释,然后调整坐标350,50到 520,70,调整之后的显示如下图

image-20210125165417456

按钮绘制完毕,我们接下来要做 人机交互了

3.3交互处理①(进入高亮,点击按钮事件,小图显示方框)

3.3.1 数学问题

现在我们思考一个问题,我直接画箭头不就好了,为什么要在填充圆里面画箭头?

因为判断鼠标是否在箭头上,是不是非常难处理?如果是在圆里面,可以用
x^2+y^2<=r^2
上面是圆心在坐标原点,现在我们传递进来了以画按钮参数的圆心坐标,简化一下就是
\sqrt{(x-a)^2+(y-b)^2)}<r
sqrt函数我们要#include<math.h>头文件

3.3.2逻辑问题

①鼠标进入坐标范围类,按钮高亮变色,通过绘制其他颜色的按钮,封装为一个函数drawHighlightButton()

②鼠标离开,取消高亮,重新绘制白色按钮,

③需要单独调用drawButton()函数

3.3.3鼠标事件学习

void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    while (1) //死循环,一直监听
    {
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //todo①判断鼠标是否在按钮上, 也就是鼠标左边在圆里面
            break;
        case WM_LBUTTONDOWN: //todo②鼠标左键按下,
            break;
        }
    }
}

以上就是一个鼠标消息,通过死循环的方式,不断的判断鼠标是否移动,是否移动到圆内以及是否离开和是否点下

3.3.4判断鼠标是否在圆内,放入todu①内,由于用了sqrt()函数,记得在头文件引入math.h

/*****************************************
*   处理用户交互
*   主要就是处理鼠标操作
*   userMoveMouse()
******************************************/
void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画左边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标是否在圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                //todo③

            }
            if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //第二个圆
            {
                //todo④
            }
            break;
        case WM_LBUTTONDOWN: //鼠标左键按下,todo⑤
            break;
        }
    }
}

现在鼠标是否在圆内的判断条件已经写好了,我们运行一下发现是没有效果的,是因为高亮绘制按钮的代码,点击鼠标的事件函数等功能没有做好

3.3.5现在我们来封装drawHighlightButton()函数

/*****************************************
*   鼠标停留和离开按钮处理
*   处理用户交互
*   drawHighlightButton()
******************************************/
void drawHighlightButton(int x, int y, char postion) //坐标,左边右边位置
{
    //点击一下,把按钮变色, 就是重新绘制一边, 把上面的绘制按钮的代码复用
    setfillcolor(BLACK);
    solidcircle(x, y, 20);
    setlinecolor(YELLOW);//设置线的颜色为白色
    setlinestyle(PS_SOLID, 3, 0);

    if (postion == 'r')
    {
        circle(x, y, 15);
        line(x - 10, y, x + 10, y);
        line(x + 3, y - 5, x + 10, y);
        line(x + 3, y + 5, x + 10, y);
    }
    else if (postion == 'l')
    {
        circle(x, y, 15);
        line(x - 10, y, x + 10, y);
        line(x - 3, y - 5, x - 10, y);
        line(x - 3, y + 5, x - 10, y);

    }
}

3.3.6 调用调试(main函数调用userMoveMouse(),然后userMoveMouse()调用drawHighlightButton())

现在绘制高亮圆圈的函数已经封装好了,我们在userMouseMove()函数的todo③里面调用调试一下

/*****************************************
*   处理用户交互
*   主要就是处理鼠标操作
*   userMoveMouse()
******************************************/
void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画左边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标在圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                drawHighlightButton(200,90,'r'); //重新绘制按钮在 之前的坐标,所以画按钮的坐标我们在上面就复制下来了

            }
            if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //第二个圆
            {
                drawHighlightButton(115,90,'l');

            }
            break;
        case WM_LBUTTONDOWN: //鼠标左键按下,
            break;
        }
    }
}

当然,整个鼠标事件是通过userMoveMouse()函数接入的,所以需要在main()函数里面调用,不调用会没有效果.

int main()
{
    initgraph(932, 538); // 根据素材像素大小创建同样大小窗口
    loadResource(); //依然要记得调用刚刚的函数
    drawMap();
    userMoveMouse(); //调用鼠标事件,鼠标事件调用绘制高亮圆圈
    getchar();
    closegraph();
    return 0;
}
image-20210126184054461

现在高亮完成,但是鼠标离开后还是高亮,同时我们优化一下 鼠标是否在按钮内的if else逻辑链

3.3.7 离开按钮重新绘制白色按钮

void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画右边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标在圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                drawHighlightButton(200,90,'r'); 

            }
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //第二个圆
            {
                drawHighlightButton(115,90,'l');

            }
            else //处理当鼠标不在按钮上,还圆以前的按钮,就是把drawButton()单独调用一次,注意不要调用整个drawmap了,重新绘制为白色按钮就行
            {
                drawButton(200, 90, 'r');
                drawButton(115, 90, 'l');
                
            }
            break;
        case WM_LBUTTONDOWN: //鼠标左键按下,
            break;
        }
    }
}

鼠标进入和离开的高亮,和取消高亮功能已经完成,下面我们来第四个要做的,点击按钮实现画小图的方框,以及方框的切换

3.4 点击按钮事件

逻辑是,当鼠标左键按下的时候,还是要判断是否是左边按钮和右边按钮,所以userMoveMouse()函数里面的 case WM_LBUTTONDOWN复用是否在圆内代码

        case WM_LBUTTONDOWN: //鼠标左键按下, 画一个矩形
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  
            {
                //封装一个画矩形的函数,为什么要画矩形, 因为要实现 点击箭头,矩形向下绘制的切换

            }
            //左边自己完善
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  
            {
                
            }
            break;

然后画方框我们同样需要封装一个函数,切换的逻辑是:当我们点击按钮画一个蓝色方框,再点击的时候,下面小图画蓝色方框,同时把上面小图的方框绘制为白色(偷工处理,背景图片是白色),然后再点的时候,上图绘制蓝色方框,下图绘制白色方框,如此循环,因此复用的代码确实需要封装函数

3.4.1 drawRect()函数

功能分析,需要传递一个flag进来,标记为1,2,这样就可以反复循环切换上下方框的功能

/*****************************************
*   画小图片矩形
*   drawRect()
******************************************/


void drawRect(int flag)//按等一下画上面的矩形,按第二下画下面那个矩形
{
    if (flag == 1)//标记为1,画上小图的方框
    {
        setlinecolor(GREEN);
        //rectangle();//左上角坐标到由下角坐标
        //putimage(80, 130, carSmall + 0);  //复制下上小图的绘制坐标方便方框坐标
        //putimage(80, 330, carSmall + 1); 
        //左上角是80,130,小一点点
        //rectangle(80-5,130-5,右下角的x,右下角的y);
        // loadimage(carSmall + i, fileName, 150, 160); 照片缩放的大小代码
        rectangle(80-5,130-5,80+150+5,130+160+5); //方框坐标就比图片大一点点

    }
    else if (flag == 2)//标记为2,画下小图的方框
    {
        setlinecolor(GREEN);
        rectangle(80 - 5, 330 - 5, 80 + 150 + 5, 330 + 160 + 5); //下图就是纵坐标改为330开头就行

    }

}

边写边调试,这个函数在哪里调用?

点击事件里面,所以在userMoveMouse()函数的case里面调用,加入调用代码,同时由于flag函数要传递,所以在userMoveMouse()函数里面要新增一个变量

int flag=1,userMoveMouse()代码如下

void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    int flag=1; //新增flag
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画右边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标在圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                drawHighlightButton(200,90,'r'); 

            }
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //第二个圆
            {
                drawHighlightButton(115,90,'l');

            }
            else //处理当鼠标不在按钮上,还圆以前的按钮,就是把drawButton()单独调用一次,注意不要调用整个drawmap了,重新绘制为白色按钮就行
            {
                drawButton(200, 90, 'r');
                drawButton(115, 90, 'l');
                
            }
            break;
        case WM_LBUTTONDOWN: //鼠标左键按下
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  
            {
                //封装一个画矩形的函数,为什么要画矩形, 因为要实现 点击箭头,矩形向下绘制的切换
                drawRect(flag);
                //调用画矩形函数,传递flag进去

            }
            //左边自己完善
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  
            {
                drawRect(flag);
            }
            break;
        }
    }
}
image-20210126190608069

现在点击按钮之后,第一个方框绘制成功,但是没有实现功能,我们需要完善一下drawRectange()的代码,让flag为1或者2的时候,做出不同的绘制行为

void drawRect(int flag)//按等一下画上面的矩形,按第二下画下面那个矩形
{
    if (flag == 1)//标记为1,画上小图的方框
    {
        setlinecolor(GREEN);
        //rectangle();//左上角坐标到由下角坐标
        //putimage(80, 130, carSmall + 0);  //复制下上小图的绘制坐标方便方框坐标
        //putimage(80, 330, carSmall + 1); 
        //左上角是80,130,小一点点
        //rectangle(80-5,130-5,右下角的x,右下角的y);
        // loadimage(carSmall + i, fileName, 150, 160); 照片缩放的大小代码
        rectangle(80-5,130-5,80+150+5,130+160+5); //方框坐标就比图片大一点点

        //设置下一个边框的颜色为白色
        setlinecolor(WHITE);
        //把下面边框的坐标直接复制过来绘制一遍
        rectangle(80 - 5, 330 - 5, 80 + 150 + 5, 330 + 160 + 5);

    }
    else if (flag == 2)//标记为2,画下小图的方框
    {
        setlinecolor(GREEN);
        rectangle(80 - 5, 330 - 5, 80 + 150 + 5, 330 + 160 + 5); //下图就是纵坐标改为330开头就行
        //设置上一个边框的颜色为白色
        setlinecolor(WHITE);
        //把上面边框的坐标直接复制过来绘制一遍
        rectangle(80 - 5, 130 - 5, 80 + 150 + 5, 130 + 160 + 5);

    }

}

这样编译时没有意义的,我们传入的是flag=1,只会画第一个方框,所以,flag变化的代码 我们要在userMoveMouse()的Case里面完善

每点击一下,让flag++,当flag==3的时候,flag复制为1

void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    int flag=1;
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画右边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标在右边圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                drawHighlightButton(200,90,'r'); 

            }
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //左边的处理
            {
                drawHighlightButton(115,90,'l');

            }
            else //处理当鼠标不在按钮上,还圆以前的按钮,就是把drawButton()单独调用一次,注意不要调用整个drawmap了,重新绘制为白色按钮就行
            {
                drawButton(200, 90, 'r');
                drawButton(115, 90, 'l');
                
            }
            break;
        case WM_LBUTTONDOWN: //鼠标左键按下
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  
            {
                //封装一个画矩形的函数,为什么要画矩形, 因为要实现 点击箭头,矩形向下绘制的切换
                drawRect(flag);
                //

            }
            //左边自己完善
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  
            {
                drawRect(flag);
            }
            flag++;
            if (flag == 3)
            {
                flag = 1; //每次按2下,就把标记归为1
            }
            break;
        }
    }
}

调试成功,接下来就是大图对应加框小图的切换了

3.4.2大图切换控制

大图与小图切换的逻辑,是需要对应图片的文件名,那么我们需要一个标记作为计数,计数器为i的时候,显示i.jpg就行

全局变量新增一个变量 smallNum

//开始尝试,点击切换大图片, 这里图片的切换,就需要计数器 ,在全局变量增加 新的变量
//全局变量
IMAGE backImg; //存放背景变量
IMAGE carBig[8];//存放大车
IMAGE carSmall[8];//存放小车

int smallNum = 0;//记录翻看照片的页码

切换时在点击的时候完成,所以在userMoveMouse()函数的鼠标点击事件,新增切换功能

//在鼠标点击事件里面修改代码

case WM_LBUTTONDOWN: //鼠标左键按下, 画一个矩形
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)
            {
                //封装一个画矩形的函数,为什么要画矩形, 因为要实现 点击箭头,矩形向下绘制的切换
                drawRect(flag);

                //新增功能,大图切换
                //putimage(345,100,carBig+0); //我们复制下大图的坐标位置 345,100
                putimage(345, 100, carBig + smallNum); //依靠smallNum计数器,在345,100的位置
                //时刻牢记, loadimage函数是加载资源决定图片大小,putimage函数决定放入的坐标和图片变量名
                smallNum++;// 每点击一次,计数器加一,如果加到8怎么办?
            
            }

userMoveMouse()函数代码如下

void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    int flag = 1;
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画右边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标左边在圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                drawHighlightButton(200, 90, 'r');


            }
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //第二个圆
            {
                drawHighlightButton(115, 90, 'l');
            }

            else //处理当鼠标不在按钮上,还圆以前的按钮,就是把drawButton()单独调用一次,注意不要调用整个drawmap了,重新绘制为白色按钮就行
            {
                drawButton(200, 90, 'r');
                drawButton(115, 90, 'l');

            }
            break;
        case WM_LBUTTONDOWN: //鼠标左键按下, 画一个矩形
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)
            {
                //封装一个画矩形的函数,为什么要画矩形, 因为要实现 点击箭头,矩形向下绘制的切换
                drawRect(flag);

                //新增功能,大图切换
                //putimage(345,100,carBig+0);
                putimage(345, 100, carBig + smallNum);
                smallNum++;
            


            }
            //左边自己完善
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)


            {
                drawRect(flag);

            }
            flag++;
            if (flag == 3)
            {
                flag = 1; //每次按2下,就把标记归为1
            }
            break;
        }
    }
}

调试之后,发现新的问题,图片是有上限的,不能一直切换下去,当然小图切换的功能也没有加进去

这里我们就要相信分析一下逻辑:(smallNum初始值为0)

①点击次数为3的时候,也就是smallNum==2,点击了3次,左边的小图就得切换

②当我们点击了9次,也就是smallNum==8,要做一次计数器的轮回,继续切换

void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    int flag = 1;
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画右边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标左边在圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                drawHighlightButton(200, 90, 'r');


            }
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //第二个圆
            {
                drawHighlightButton(115, 90, 'l');
            }

            else //处理当鼠标不在按钮上,还圆以前的按钮,就是把drawButton()单独调用一次,注意不要调用整个drawmap了,重新绘制为白色按钮就行
            {
                drawButton(200, 90, 'r');
                drawButton(115, 90, 'l');

            }
            break;
    case WM_LBUTTONDOWN: //鼠标左键按下, 画一个矩形
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)
            {
                //封装一个画矩形的函数,为什么要画矩形, 因为要实现 点击箭头,矩形向下绘制的切换
                drawRect(flag);
                

            
                if (smallNum == 8) //先处理最简单的情况,当图片计数器到末尾的时候,循环,并且计数器归零
                {
                    //循环完之后要重新显示第0张和第1张
                    putimage(80, 130, carSmall + 0);  //小图坐标是 80 130和 80 330
                    putimage(80, 330, carSmall + 1);
                    smallNum = 0;
                }
                if (smallNum == 2)
                {
                    putimage(80, 130, carSmall + 2);
                    putimage(80, 330, carSmall + 3);
                
                }
                if (smallNum == 4)
                {
                    putimage(80, 130, carSmall + 4);
                    putimage(80, 330, carSmall + 5);
            
                }
                if (smallNum == 6)
                {
                    putimage(80, 130, carSmall + 6);
                    putimage(80, 330, carSmall + 7);

                }
                
                //新增功能,大图切换
                //putimage(345,100,carBig+0);
                putimage(345, 100, carBig + smallNum);
                smallNum++; //计数器累加
            }
            //作业左边自己完善
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)
            {
                drawRect(flag);
                
                //点击左边的按钮待完善
            }
            flag++;
            if (flag == 3)
            {
                flag = 1; //每次按2下,就把标记归为1
            }
            break;
        }
    }
}

3.5背景音乐播放

音乐播放比较简单,只需要引用好相应的静态库就可以了

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<graphics.h>
#include<math.h>
#include<Windows.h>
#include<mmsystem.h> //播放音乐头文件
#pragma comment(lib,"WINMM.LIB")//播放音乐静态库

为了防止出错,我们把windows.h也给引用下来

音乐播放是在资源加载完成,我们通过mciSendString()函数就可以,注意观察注释

//播放音乐,加载资源的时候播放
void loadResource()
{
    mciSendString("open 1.mp3 alias music", 0, 0, NULL); //把MP3的文件名 赋值为别名music, 用默认的方式打开
    mciSendString("play music repeat", 0, 0, NULL); // 用repat的方式重复播放音乐, 注意网易云等下载的音乐有封面,这个功能要把封面裁剪到500*500以下才能播放
    loadimage(&backImg, "jiemian.jpg");
    for (int i = 0; i <= 7; i++)
    {
        char fileName[20] = "";
        // 0.jpg 1.jpg 2.jpg .....
        sprintf(fileName, "%d.jpg", i); //把文件名 *.jpg 这个作为路径名写入数组, 那么循环8次,就初始化了8次
        loadimage(carBig + i, fileName, 500, 400);
        loadimage(carSmall + i, fileName, 150, 160);
    }
}

大功告成一半,剩下的左边按钮的任务,依葫芦画瓢来进行把!

//完整代码,不要直接复制,最好自己调试
#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<graphics.h>
#include<math.h>
#include<Windows.h>
#include<mmsystem.h>
#pragma comment(lib,"WINMM.LIB")
/*****************************************
*   背景:需要一个变量
*   8张汽车照片:数组长度为8个变量
*   8张小缩放照片:数组长度为8个变量
******************************************/

//开始尝试,点击切换大图片, 这里图片的切换,就需要计数器 ,在全局变量增加 新的变量
//全局变量
IMAGE backImg; //存放背景变量
IMAGE carBig[8];//存放大车
IMAGE carSmall[8];//存放小车

int smallNum = 0;//记录翻看照片的页码

/*****************************************
*   画按钮
*   drawButton();
*   画线函数 line(int x,int y,int xx,int yy) 两点确定一条线,三条线画一个箭头
*   画圆,实心圆solidcircle(x,y,R),空心圆 circle(x,y,R)
*   实心圆填充颜色 setfillcolor(),空心圆线条颜色 setlinecolor()
******************************************/
void drawButton(int x,int y, char postion) //按钮的坐标, 和朝向标记 <--- l   ---> r  
{
    setfillcolor(BLACK);// 设置填充颜色为黑色
    solidcircle(x, y, 20);//在x,y的位置画一个半径为20的圆
    setlinecolor(WHITE);//设置线的颜色为白色
    setlinestyle(PS_SOLID, 3, 0);//设置线的格式, 实线,3个像素宽,0为自适应

    if (postion == 'r')
    {
        circle(x, y, 15);//圆中圆
        //画线,坐下简单的计算,圆心坐标定位, 左右减加5
        line(x - 10, y, x + 10,y);//画横线
        line(x + 3, y - 5, x + 10, y);//画箭头上横线, 从一个点画到 x+10,y这个点,调试 前面2个参数到合适位置
        line(x + 3, y + 5, x + 10, y);//画箭头下横线,对称处理
    }
    else if (postion == 'l')//画了右边箭头,现在来画左边箭头,坐标处理一下
    {
        circle(x, y, 15);
        line(x - 10, y, x + 10, y);
        line(x - 3, y - 5, x - 10, y);
        line(x - 3, y + 5, x - 10, y);

    }



}

/*****************************************
*   初始化资源
*   封装一个函数,初始化数据:初始化变量
*   loadResource(); 没有返回值
******************************************/

void loadResource()
{
    loadimage(&backImg, "jiemian.jpg");
    //for循环批量加载:因为文件名有规律格式 从0.jpg到7.jpg
    mciSendString("open 1.mp3 alias music", 0, 0, NULL); //把MP3的文件名 赋值为别名music, 用默认的方式打开
    mciSendString("play music repeat", 0, 0, NULL); // 用repat的方式重复播放音乐, 注意网易云等下载的音乐有封面,这个功能要把封面裁剪到500*500
    for (int i = 0; i <= 7; i++)
    {
        char fileName[20] = "";
        // 0.jpg 1.jpg 2.jpg .....
        sprintf(fileName, "%d.jpg", i); //把文件名 *.jpg 这个作为路径名写入数组, 那么循环8次,就初始化了8次
        loadimage(carBig + i, fileName, 500, 400);
        loadimage(carSmall + i, fileName, 150, 160);
    }
}
/*****************************************
*   初始化界面
*   画界面, 画背景,画按钮, 画文字
*   drawMap();
******************************************/
void drawMap()
{
    //画背景
    putimage(0, 0, &backImg);
    //画小图 第0张和第1张
    putimage(80, 130, carSmall + 0); //具体位置,用截图工具去测量,需要在哪里画 记住大致的位置 取整数即可
    putimage(80, 330, carSmall + 1); //位置计算, 加上每一张小图的大小, 160+130=290,稍微大一点到310
    //画大图
    putimage(345,100,carBig+0);
    drawButton(200, 90, 'r'); //画右边按钮
    drawButton(115, 90, 'l'); //画左边按钮

    //输出文字,显示标题
    settextcolor(RED); //设置文字颜色为蓝色
    settextstyle(25, 0, "STCAIYUN");//设置字体大小25到0,和字体 字体在c盘windows下的fonts文件夹 赋值字体名字
    setbkmode(TRANSPARENT); //有背景,去掉文字背景
    outtextxy(520, 70, "微电子-机械之心");
}
/*****************************************
*   鼠标停留和离开按钮处理
*   处理用户交互
*   drawHighlightButton()
******************************************/
void drawHighlightButton(int x, int y, char postion) //坐标,左边右边位置
{
    //点击一下,把按钮变色, 就是重新绘制一边, 把上面的绘制按钮的代码复用
    setfillcolor(BLACK);
    solidcircle(x, y, 20);
    setlinecolor(YELLOW);//设置线的颜色为白色
    setlinestyle(PS_SOLID, 3, 0);

    if (postion == 'r')
    {
        circle(x, y, 15);
        line(x - 10, y, x + 10, y);
        line(x + 3, y - 5, x + 10, y);
        line(x + 3, y + 5, x + 10, y);
    }
    else if (postion == 'l')
    {
        circle(x, y, 15);
        line(x - 10, y, x + 10, y);
        line(x - 3, y - 5, x - 10, y);
        line(x - 3, y + 5, x - 10, y);

    }
}


/*****************************************
*   画小图片矩形
*   drawRect()
******************************************/


void drawRect(int flag)//按等一下画上面的矩形,按第二下画下面那个矩形
{
    if (flag == 1)//标记为1,画上小图的方框
    {
        setlinecolor(GREEN);
        //rectangle();//左上角坐标到由下角坐标
        //putimage(80, 130, carSmall + 0);  //复制下上小图的绘制坐标方便方框坐标
        //putimage(80, 330, carSmall + 1); 
        //左上角是80,130,小一点点
        //rectangle(80-5,130-5,右下角的x,右下角的y);
        // loadimage(carSmall + i, fileName, 150, 160); 照片缩放的大小代码
        rectangle(80-5,130-5,80+150+5,130+160+5); //方框坐标就比图片大一点点

        //设置下一个边框的颜色为白色
        setlinecolor(WHITE);
        //把下面边框的坐标直接复制过来绘制一遍
        rectangle(80 - 5, 330 - 5, 80 + 150 + 5, 330 + 160 + 5);

    }
    else if (flag == 2)//标记为2,画下小图的方框
    {
        setlinecolor(GREEN);
        rectangle(80 - 5, 330 - 5, 80 + 150 + 5, 330 + 160 + 5); //下图就是纵坐标改为330开头就行
        //设置上一个边框的颜色为白色
        setlinecolor(WHITE);
        //把上面边框的坐标直接复制过来绘制一遍
        rectangle(80 - 5, 130 - 5, 80 + 150 + 5, 130 + 160 + 5);

    }

}
/*****************************************
*   处理用户交互
*   主要就是处理鼠标操作
*   userMoveMouse()
******************************************/
void userMoveMouse()
{
    //定义一个鼠标消息
    MOUSEMSG m;
    int flag = 1;
    while (1) //死循环,一直监听
    {

        //  drawButton(200, 90, 'r'); //画右边按钮
        // drawButton(115, 90, 'l'); //画右边按钮
        m = GetMouseMsg();
        switch (m.uMsg)
        {
        case WM_MOUSEMOVE: //鼠标移动
            //判断鼠标是否在按钮上, 也就是鼠标左边在圆里面
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)  //之前确定的圆半径为20
            {
                drawHighlightButton(200, 90, 'r');


            }
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)  //第二个圆
            {
                drawHighlightButton(115, 90, 'l');
            }

            else //处理当鼠标不在按钮上,还圆以前的按钮,就是把drawButton()单独调用一次,注意不要调用整个drawmap了,重新绘制为白色按钮就行
            {
                drawButton(200, 90, 'r');
                drawButton(115, 90, 'l');

            }
            break;
    case WM_LBUTTONDOWN: //鼠标左键按下, 画一个矩形
            if (sqrt((double)(m.x - 200)*(m.x - 200) + (m.y - 90)*(m.y - 90)) < 20)
            {
                //封装一个画矩形的函数,为什么要画矩形, 因为要实现 点击箭头,矩形向下绘制的切换
                drawRect(flag);
                

            
                if (smallNum == 8)
                {
                    //循环完之后要重新显示第0张和第1张
                    putimage(80, 130, carSmall + 0);  //小图坐标是 80 130和 80 330
                    putimage(80, 330, carSmall + 1);
                    smallNum = 0;
                }
                if (smallNum == 2)
                {
                    putimage(80, 130, carSmall + 2);
                    putimage(80, 330, carSmall + 3);
                
                }
                if (smallNum == 4)
                {
                    putimage(80, 130, carSmall + 4);
                    putimage(80, 330, carSmall + 5);
            
                }
                if (smallNum == 6)
                {
                    putimage(80, 130, carSmall + 6);
                    putimage(80, 330, carSmall + 7);

                }
                
                //新增功能,大图切换
                //putimage(345,100,carBig+0);
                putimage(345, 100, carBig + smallNum);
                smallNum++; 
            }
            //作业左边自己完善
            else if (sqrt((double)(m.x - 115)*(m.x - 115) + (m.y - 90)*(m.y - 90)) < 20)
            {
                drawRect(flag);
                
                //点击左边的按钮待完善
            }
            flag++;
            if (flag == 3)
            {
                flag = 1; //每次按2下,就把标记归为1
            }
            break;
        }
    }
}
//调试之后,发现新的问题,图片是有上限的,不能一直切换下去。
int main()
{
    initgraph(932, 538); // 根据素材像素大小创建同样大小窗口
    loadResource(); //依然要记得调用刚刚的函数
    drawMap();
    userMoveMouse(); //调用鼠标事件,鼠标事件调用绘制高亮圆圈
    getchar();
    closegraph();
    return 0;
}
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容

  • 用到的组件 1、通过CocoaPods安装 2、第三方类库安装 3、第三方服务 友盟社会化分享组件 友盟用户反馈 ...
    SunnyLeong阅读 14,613评论 1 180
  • 夜莺2517阅读 127,718评论 1 9
  • 版本:ios 1.2.1 亮点: 1.app角标可以实时更新天气温度或选择空气质量,建议处女座就不要选了,不然老想...
    我就是沉沉阅读 6,887评论 1 6
  • 我是一名过去式的高三狗,很可悲,在这三年里我没有恋爱,看着同龄的小伙伴们一对儿一对儿的,我的心不好受。怎么说呢,高...
    小娘纸阅读 3,387评论 4 7
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,535评论 28 53