C 语言图形编程 | 界面 / 动画 / 字符特效

注:本文为 “C 语言图形编程” 相关文章合辑。

略作重排,如有内容异常,请看原文。


C 语言图形化界面——含图形、按钮、鼠标、进度条等部件制作(带详细代码、讲解及注释)

非线性光学元件于 2020-02-15 09:42:37 发布

0. 引言

在 CSDN 上,许多关于 C 程序图形化界面的介绍存在代码繁琐难解、不便调试修改或讲解不够详细的问题。本文提供的代码简单、易于移植且容易理解,希望对急需使用 C 语言制作图形化界面的读者有所帮助。

对于不熟悉 EasyX 的读者,只需 10 分钟即可上手,而它可能为您节省 3 个小时甚至更多的时间。

关于 EasyX 的简单应用,可参考作者之前关于 C 程序可视化的博文:C语言绘图实验-CSDN博客(附后)。

本文的讲解循序渐进,读者应重点关注每个步骤的理解以及两步之间代码的变化。

1. 素材准备

  1. EasyX 的下载链接如下(本文使用的版本是 2014 冬至版):EasyX Graphics Library for C++。使用 EasyX 需注意其兼容的编译器(下载的帮助文件中有说明),不同版本的 EasyX 兼容的编译器不同,但均与 Visual C++6 兼容(与字符编码有关)。本文以 Visual C++6 编译器为例编写代码。

  2. EasyX 的最新英文帮助文档链接(下载 2014 冬至版会自带中文帮助文档):EasyX 文档 - Basic introduction

  3. 如果成功下载了 EasyX 2014 冬至版,解压后将头文件(easyx.hgraphics.h)和 lib 文件(amd64)分别放在 VC 文件夹默认的 include 文件夹和 lib 文件夹中。右键点击 VC 程序,选择“打开文件所在位置”,然后找到 MFC 文件夹。

    以下是两个文件夹的位置截图:
    include
    lib

  4. 建议将编译的 C 文件以 .cpp 后缀保存。

2. 编程

2.1 创建界面

创建一个 480×360 的窗口,需要使用 initgraph() 函数。以下是代码示例:

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>               // 用到了定时函数 sleep()
#include <math.h>int main()
{int i;short win_width, win_height;   // 定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width, win_height);  // 初始化窗口(黑屏)for (i = 0; i < 256; i += 5){setbkcolor(RGB(i, i, i)); // 设置背景色,原来默认黑色cleardevice();            // 清屏(取决于背景色)Sleep(15);                // 延时 15ms}closegraph();                 // 关闭绘图界面return 0;
}

这段代码运行后,屏幕会逐渐变亮。这是因为背景色不断刷新为 RGB(i, i, i)。C 语言中的颜色使用十六进制表示,RGB 函数可以将 0~255 范围内的三个整数三原色转换为十六进制。cleardevice() 函数用于清屏,通常只在初始化时出现。Sleep() 是毫秒级延迟,界面变亮时间不一定是准确的 15ms×255/5=0.765s,因为其他语句也需要执行时间。closegraph() 用于关闭绘图界面。如果初始化了绘图界面但未在主函数结束前关闭它,可能会引发一些莫名其妙的错误,因此该函数必不可少。

2.2 创建按钮

在界面中创建按钮需要绘制矩形和打印文字。以下是代码示例:

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>               // 用到了定时函数 sleep()
#include <math.h>int r1[] = {30, 20, 130, 60};      // 输入按钮的矩形参数
int r2[] = {170, 20, 220, 60};     // 运行按钮的矩形参数
int r3[] = {260, 20, 310, 60};     // 退出按钮的矩形参数int main()
{int i;short win_width, win_height;   // 定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width, win_height);  // 初始化窗口(黑屏)for (i = 0; i < 256; i += 5){setbkcolor(RGB(i, i, i)); // 设置背景色,原来默认黑色cleardevice();            // 清屏(取决于背景色)Sleep(15);                // 延时 15ms}RECT R1 = {r1[0], r1[1], r1[2], r1[3]};  // 矩形指针 R1RECT R2 = {r2[0], r2[1], r2[2], r2[3]};  // 矩形指针 R2RECT R3 = {r3[0], r3[1], r3[2], r3[3]};  // 矩形指针 R3LOGFONT f;                    // 字体样式指针gettextstyle(&f);             // 获取字体样式_tcscpy(f.lfFaceName, _T("宋体"));       // 设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;       // 设置输出效果为抗锯齿settextstyle(&f);             // 设置字体样式settextcolor(BLACK);          // BLACK 在 graphic.h 头文件中被定义为黑色的颜色常量drawtext("输入参数", &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);   // 在矩形区域 R1 内输入文字,水平居中,垂直居中,单行显示drawtext("运行", &R2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);       // 在矩形区域 R2 内输入文字,水平居中,垂直居中,单行显示drawtext("退出", &R3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);       // 在矩形区域 R3 内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r1[0], r1[1], r1[2], r1[3]);rectangle(r2[0], r2[1], r2[2], r2[3]);rectangle(r3[0], r3[1], r3[2], r3[3]);system("pause");              // 暂停,为了显示closegraph();return 0;
}

按钮效果

矩形指针 RECT 使用句柄定义,不可中途再次赋值。其格式为 RECT r = {X1, Y1, X2, Y2},其中 X1 和 X2 分别是矩形的左边和右边的横坐标,Y1 和 Y2 分别是矩形的上边和下边的纵坐标。DT_CENTER | DT_VCENTER | DT_SINGLELINE 是描述填充格式的常量。drawtext 函数用于在矩形区域内书写文字,无需再计算文字的坐标和设置大小,使用起来非常方便。LOGFONT 是字体样式指针,通过 gettextstyle 函数获取当前字体类型,再通过 settextstyle 函数加以设置。这里仅修改了字体名称和显示质量,还可以修改斜体、下划线等属性,更详细的内容请参考帮助文档。

2.3 鼠标操作

2.3.1 单击特效

鼠标是输入设备,只要发生以下事件,就会暂存于鼠标消息列表中,操作系统会依次响应列表中的鼠标消息事件。常用的鼠标事件如下:

  • WM_MOUSEMOVE:鼠标移动
  • WM_MOUSEWHEEL:鼠标滚轮滚动
  • WM_LBUTTONDOWN:鼠标左键按下
  • WM_LBUTTONUP:鼠标左键弹起
  • WM_LBUTTONDBLCLK:鼠标左键双击
  • WM_RBUTTONDOWN:鼠标右键按下
  • WM_RBUTTONUP:鼠标右键弹起
  • WM_RBUTTONDBLCLK:鼠标右键双击
  • WM_MBUTTONDOWN:鼠标中键按下
  • WM_MBUTTONUP:鼠标中键弹起
  • WM_MBUTTONDBLCLK:鼠标中键双击

以下是实现鼠标左键单击特效的代码示例:

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>               // 用到了定时函数 sleep()
#include <math.h>int r1[] = {30, 20, 130, 60};      // 输入按钮的矩形参数
int r2[] = {170, 20, 220, 60};     // 运行按钮的矩形参数
int r3[] = {260, 20, 310, 60};     // 退出按钮的矩形参数int main()
{int i;short win_width, win_height;   // 定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width, win_height);  // 初始化窗口(黑屏)for (i = 0; i < 256; i += 5){setbkcolor(RGB(i, i, i)); // 设置背景色,原来默认黑色cleardevice();            // 清屏(取决于背景色)Sleep(15);                // 延时 15ms}RECT R1 = {r1[0], r1[1], r1[2], r1[3]};  // 按钮 1 的矩形区域RECT R2 = {r2[0], r2[1], r2[2], r2[3]};  // 按钮 2 的矩形区域RECT R3 = {r3[0], r3[1], r3[2], r3[3]};  // 按钮 3 的矩形区域LOGFONT f;gettextstyle(&f);             // 获取字体样式_tcscpy(f.lfFaceName, _T("宋体"));       // 设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;       // 设置输出效果为抗锯齿settextstyle(&f);             // 设置字体样式settextcolor(BLACK);          // BLACK 在 graphic.h 头文件中被定义为黑色的颜色常量drawtext("输入参数", &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);   // 在矩形区域 R1 内输入文字,水平居中,垂直居中,单行显示drawtext("运行", &R2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);       // 在矩形区域 R2 内输入文字,水平居中,垂直居中,单行显示drawtext("退出", &R3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);       // 在矩形区域 R3 内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r1[0], r1[1], r1[2], r1[3]);rectangle(r2[0], r2[1], r2[2], r2[3]);rectangle(r3[0], r3[1], r3[2], r3[3]);MOUSEMSG m;                   // 鼠标指针setrop2(R2_NOTXORPEN);        // 二元光栅——NOT(屏幕颜色 XOR 当前颜色)while (true){m = GetMouseMsg();        // 获取一条鼠标消息if (m.uMsg == WM_LBUTTONDOWN){for (i = 0; i <= 10; i++){setlinecolor(RGB(25 * i, 25 * i, 25 * i));  // 设置圆颜色circle(m.x, m.y, 2 * i);Sleep(25);          // 停顿 25mscircle(m.x, m.y, 2 * i);  // 抹去刚刚画的圆}FlushMouseMsgBuff();    // 清空鼠标消息缓存区}}system("pause");              // 暂停,为了显示closegraph();return 0;
}

鼠标单击特效

每次点击鼠标左键时,鼠标点击处会出现一个逐渐扩大并淡出的圆。当循环体内 Sleep 的时间大于 20ms 时,视觉效果会更明显。每次响应鼠标左键单击事件后,都会调用一次清空鼠标消息缓存区的函数 FlushMouseMsgBuff()。如果没有这个函数,快速连续单击鼠标左键多次时,特效会重复播放,即使停止单击,程序仍会继续播放单击特效,因为鼠标消息队列中的消息尚未处理完毕。

这里需要解释的是二元光栅设置函数 setrop2()。二元光栅是混合背景色和当前颜色的模式。我们采用的是同或(NOT XOR)的方式,若底色为白色(1),则当前颜色不变;若底色是黑色(0),则当前颜色反色。采用这种方式的原因是,我们在第二次抹去原来的圆时不能使用白色,否则如果背景色原本为黑色(比如按钮和文字),也会被抹成白色。而背景色与任意一个颜色同或两次都为其本身,即可起到还原背景色的效果。这里的背景色与 cleardevice() 前面的背景色不同,它是指执行这一条绘画指令之前屏幕上的颜色。

2.3.2 光标感应

当鼠标移到按钮上时,按钮会有所变化,移开按钮时又会恢复原样。这里采用简单的填充颜色方法,即按钮变色。需要解决的问题是按钮变色后按钮的文字不能被覆盖,因此仍需使用二元光栅。为了方便起见,将三个按钮的数组合并为一个二维数组,在鼠标事件中更容易使用和分配任务。以下是代码示例:

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>               // 用到了定时函数 sleep()
#include <math.h>int r[3][4] = {{30, 20, 130, 60}, {170, 20, 220, 60}, {260, 20, 310, 60}};  // 三个按钮的二维数组int button_judge(int x, int y)
{if (x > r[0][0] && x < r[0][2] && y > r[0][1] && y < r[0][3]) return 1;if (x > r[1][0] && x < r[1][2] && y > r[1][1] && y < r[1][3]) return 2;if (x > r[2][0] && x < r[2][2] && y > r[2][1] && y < r[2][3]) return 3;return 0;
}int main()
{int i, event = 0;short win_width, win_height;   // 定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width, win_height);  // 初始化窗口(黑屏)for (i = 0; i < 256; i += 5){setbkcolor(RGB(i, i, i)); // 设置背景色,原来默认黑色cleardevice();            // 清屏(取决于背景色)Sleep(15);                // 延时 15ms}RECT R1 = {r[0][0], r[0][1], r[0][2], r[0][3]};RECT R2 = {r[1][0], r[1][1], r[1][2], r[1][3]};RECT R3 = {r[2][0], r[2][1], r[2][2], r[2][3]};LOGFONT f;gettextstyle(&f);             // 获取字体样式_tcscpy(f.lfFaceName, _T("宋体"));       // 设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;       // 设置输出效果为抗锯齿settextstyle(&f);             // 设置字体样式settextcolor(BLACK);          // BLACK 在 graphic.h 头文件中被定义为黑色的颜色常量drawtext("输入参数", &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);   // 在矩形区域 R1 内输入文字,水平居中,垂直居中,单行显示drawtext("运行", &R2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);       // 在矩形区域 R2 内输入文字,水平居中,垂直居中,单行显示drawtext("退出", &R3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);       // 在矩形区域 R3 内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r[0][0], r[0][1], r[0][2], r[0][3]);rectangle(r[1][0], r[1][1], r[1][2], r[1][3]);rectangle(r[2][0], r[2][1], r[2][2], r[2][3]);MOUSEMSG m;                   // 鼠标指针while (true){m = GetMouseMsg();        // 获取一条鼠标消息switch (m.uMsg){case WM_MOUSEMOVE:setrop2(R2_XORPEN);setlinecolor(LIGHTCYAN);  // 线条颜色为亮青色setlinestyle(PS_SOLID, 3);  // 设置画线样式为实线,宽度为 3setfillcolor(WHITE);       // 填充颜色为白色if (button_judge(m.x, m.y) != 0){if (event != button_judge(m.x, m.y)){event = button_judge(m.x, m.y);  // 记录这一次触发的按钮fillrectangle(r[event - 1][0], r[event - 1][1], r[event - 1][2], r[event - 1][3]);  // 有框填充矩形(X1, Y1, X2, Y2)}}else{if (event != 0)  // 上次触发的按钮未被修正为原来的颜色{fillrectangle(r[event - 1][0], r[event - 1][1], r[event - 1][2], r[event - 1][3]);  // 两次同或为原来颜色event = 0;}}break;case WM_LBUTTONDOWN:setrop2(R2_NOTXORPEN);  // 二元光栅——NOT(屏幕颜色 XOR 当前颜色)for (i = 0; i <= 10; i++){setlinecolor(RGB(25 * i, 25 * i, 25 * i));  // 设置圆颜色circle(m.x, m.y, 2 * i);Sleep(30);          // 停顿 30mscircle(m.x, m.y, 2 * i);  // 抹去刚刚画的圆}break;FlushMouseMsgBuff();  // 清空鼠标消息缓存区}}system("pause");              // 暂停,为了显示return 0;
}

光标感应效果

在鼠标移动事件(case WM_MOUSEMOVE)中,使用了屏幕颜色与当前颜色异或的方式。fillrectangle 函数用于绘制一个有框填充矩形,其大小与原按钮一致。由于线条颜色为亮青色,填充颜色为白色(1),白色填充颜色与屏幕颜色异或后,取的是屏幕颜色的反色。按钮的边框是黑色(0),它与亮青色异或后,会保留原来的亮青色。与同或一样,异或两次等于没有执行操作,因此可以还原到原屏幕画布的颜色。

2.3.3 进度条

涉及进度条时,通常会结合一个简单的程序来展示进度条的变化。这里设计了一个简单的弹性球轨迹作图程序。假设球的半径为 ( R ),初始高度为 ( h_0 ),初速度为 0(自由落体),非弹性碰撞时能量损失率为 ( \alpha )。计算部分子函数如下:

int simulation()
{float dt = 0.01;  // 仿真间隔 10mslong int N = (long int)(sim_t / dt);  // 迭代次数float *h = (float *)calloc(N, sizeof(float));  // 高度float *v = (float *)calloc(N, sizeof(float));  // 速度(竖直方向)long int i;  // 迭代变量for (i = 1; i < N; i++){if (h[i - 1] > R)  // 未发生碰撞{v[i] = v[i - 1] - 9.8 * dt;  // 速度计算}else  // 发生碰撞,动能损失 \( \alpha \),速度损失 \( \sqrt{\alpha} \){v[i] = -sqrt(alpha) * v[i - 1];}}free(h);free(v);  // 释放内存return 0;
}

接下来,需要定义绘图网格的函数:

void init_figure()
{int i;setrop2(R2_COPYPEN);  // 当前颜色setlinecolor(BLACK);setlinestyle(PS_SOLID);  // 实线rectangle(30, 100, 420, 330);  // 外框线setlinestyle(PS_DOT);  // 点线for (i = 30 + 39; i < 420; i += 39){line(i, 100, i, 330);  // 竖直辅助线}for (i = 100 + 23; i < 330; i += 23){line(30, i, 420, i);  // 水平辅助线}
}

使用 rectangle 函数绘制网格外框架,使用 line 函数依次画出辅助线。目标是将高度 ( h ) 的坐标转换到网格上,绘制出球心的轨迹。以下是改进后的 simulation 函数代码:

int simulation()
{char t[3];  // 百分值的字符char *out_text;  // 带百分号的百分字符float dt = 0.01;  // 仿真间隔 10msfloat dy = 230 / h0;  // 单位纵坐标long int N = (long int)(sim_t / dt);  // 迭代次数float *h = (float *)calloc(N, sizeof(float));  // 高度float *v = (float *)calloc(N, sizeof(float));  // 速度(竖直方向)long int i;  // 迭代变量float process_duty;  // 进度RECT r = {370, 35, 400, 65};  // 百分值显示区域的矩形指针init_figure();  // 初始化图像网格setrop2(R2_COPYPEN);  // 当前颜色setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354, 19, 411, 81);  // 覆盖原进度条区域setlinestyle(PS_NULL);  // 无线条setbkmode(TRANSPARENT);  // 设置文字填充背景为透明// 计算步骤h[0] = h0;v[0] = 0;BeginBatchDraw();  // 开始缓存区for (i = 1; i < N; i++){if (h[i - 1] > R)  // 未发生碰撞{v[i] = v[i - 1] - 9.8 * dt;  // 速度计算}else  // 发生碰撞,动能损失 \( \alpha \),速度损失 \( \sqrt{\alpha} \){v[i] = -sqrt(alpha) * v[i - 1];}setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354, 19, 416, 81);  // 覆盖原进度条区域h[i] = h[i - 1] + v[i] * dt;  // 高度计算process_duty = (i + 1) / (float)(N);setlinestyle(PS_SOLID);putpixel(30 + (int)(process_duty * 390), 330 - (int)(h[i] * dy), RED);  // 画点 putpixel(X, Y, color*)setfillcolor(BLUE);setlinestyle(PS_NULL);fillpie(355, 20, 415, 80, 0, process_duty * 2 * PI);  // 绘制环形进度条setfillcolor(WHITE);fillcircle(385, 50, 20);  // 覆盖中心部分sprintf(t, "%d", (int)(process_duty * 100.0));  // 整型转换为字符串out_text = strcat(t, "%");  // 添加一个百分号drawtext(out_text, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);  // 显示进度百分比Sleep(dt * 1000);  // 延时FlushBatchDraw();  // 刷新缓存区}EndBatchDraw();  // 结束缓存区free(h);free(v);return 0;
}

这里使用了 putpixel 函数绘制球心轨迹,fillpie 函数绘制环形进度条,fillcircle 函数覆盖中心部分以形成环形效果。FlushBatchDraw 函数用于刷新缓存区,与 BeginBatchDrawEndBatchDraw 一起使用,可以批量绘图后再刷新画板。

3. 完整代码及效果

以下是完整的代码示例,包含按钮、鼠标操作、进度条和弹性球轨迹作图功能:

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>               // 用到了定时函数 sleep()
#include <math.h>
#include <string.h>
#define PI 3.1416
int r[3][4] = {{30, 20, 130, 60}, {170, 20, 220, 60}, {260, 20, 310, 60}};  // 三个按钮的二维数组
float alpha, R, h0, sim_t;  // 碰撞时的能量损失率,球的半径、初始高度、仿真时间// 按钮判断函数
int button_judge(int x, int y)
{if (x > r[0][0] && x < r[0][2] && y > r[0][1] && y < r[0][3]) return 1;if (x > r[1][0] && x < r[1][2] && y > r[1][1] && y < r[1][3]) return 2;if (x > r[2][0] && x < r[2][2] && y > r[2][1] && y < r[2][3]) return 3;return 0;
}// 初始化图像
void init_figure()
{int i;setrop2(R2_COPYPEN);  // 当前颜色setlinecolor(BLACK);setlinestyle(PS_SOLID);  // 实线rectangle(30, 100, 420, 330);  // 外框线setlinestyle(PS_DOT);  // 点线for (i = 30 + 39; i < 420; i += 39){line(i, 100, i, 330);  // 竖直辅助线}for (i = 100 + 23; i < 330; i += 23){line(30, i, 420, i);  // 水平辅助线}
}// 仿真运行
int simulation()
{char t[3];  // 百分值的字符char *out_text;float dt = 0.01;  // 仿真间隔 10msfloat dy = 230 / h0;  // 单位纵坐标long int N = (long int)(sim_t / dt);  // 迭代次数float *h = (float *)calloc(N, sizeof(float));  // 高度float *v = (float *)calloc(N, sizeof(float));  // 速度(竖直方向)long int i;  // 迭代变量float process_duty;  // 进度RECT r = {370, 35, 400, 65};  // 百分值显示区域的矩形指针init_figure();  // 初始化图像网格setrop2(R2_COPYPEN);  // 当前颜色setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354, 19, 411, 81);  // 覆盖原进度条区域setlinestyle(PS_NULL);  // 无线条setbkmode(TRANSPARENT);  // 设置文字填充背景为透明// 计算步骤h[0] = h0;v[0] = 0;BeginBatchDraw();  // 开始缓存区for (i = 1; i < N; i++){if (h[i - 1] > R)  // 未发生碰撞{v[i] = v[i - 1] - 9.8 * dt;  // 速度计算}else  // 发生碰撞,动能损失 \( \alpha \),速度损失 \( \sqrt{\alpha} \){v[i] = -sqrt(alpha) * v[i - 1];}setfillcolor(WHITE);setlinecolor(WHITE);fillrectangle(354, 19, 416, 81);  // 覆盖原进度条区域h[i] = h[i - 1] + v[i] * dt;  // 高度计算process_duty = (i + 1) / (float)(N);setlinestyle(PS_SOLID);putpixel(30 + (int)(process_duty * 390), 330 - (int)(h[i] * dy), RED);  // 画点 putpixel(X, Y, color*)setfillcolor(BLUE);setlinestyle(PS_NULL);fillpie(355, 20, 415, 80, 0, process_duty * 2 * PI);  // 绘制环形进度条setfillcolor(WHITE);fillcircle(385, 50, 20);  // 覆盖中心部分sprintf(t, "%d", (int)(process_duty * 100.0));  // 整型转换为字符串out_text = strcat(t, "%");  // 添加一个百分号drawtext(out_text, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);  // 显示进度百分比Sleep(dt * 1000);  // 延时FlushBatchDraw();  // 刷新缓存区}EndBatchDraw();  // 结束缓存区free(h);free(v);return 0;
}int main()
{int i, event = 0;char s[30];  // 输入字符串变量short win_width, win_height;  // 定义窗口的宽度和高度win_width = 480;win_height = 360;initgraph(win_width, win_height);  // 初始化窗口(黑屏)for (i = 0; i < 256; i += 5){setbkcolor(RGB(i, i, i));  // 设置背景色,原来默认黑色cleardevice();  // 清屏(取决于背景色)Sleep(30);  // 延时 30ms}RECT R1 = {r[0][0], r[0][1], r[0][2], r[0][3]};RECT R2 = {r[1][0], r[1][1], r[1][2], r[1][3]};RECT R3 = {r[2][0], r[2][1], r[2][2], r[2][3]};LOGFONT f;  // 字体样式指针gettextstyle(&f);  // 获取字体样式_tcscpy(f.lfFaceName, _T("宋体"));  // 设置字体为宋体f.lfQuality = ANTIALIASED_QUALITY;  // 设置输出效果为抗锯齿settextstyle(&f);  // 设置字体样式settextcolor(BLACK);  // BLACK 在 graphic.h 头文件中被定义为黑色的颜色常量drawtext("输入参数", &R1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);  // 在矩形区域 R1 内输入文字,水平居中,垂直居中,单行显示drawtext("运行", &R2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);  // 在矩形区域 R2 内输入文字,水平居中,垂直居中,单行显示drawtext("退出", &R3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);  // 在矩形区域 R3 内输入文字,水平居中,垂直居中,单行显示setlinecolor(BLACK);rectangle(r[0][0], r[0][1], r[0][2], r[0][3]);rectangle(r[1][0], r[1][1], r[1][2], r[1][3]);rectangle(r[2][0], r[2][1], r[2][2], r[2][3]);MOUSEMSG m;  // 鼠标指针while (true){m = GetMouseMsg();  // 获取一条鼠标消息switch (m.uMsg){case WM_MOUSEMOVE:setrop2(R2_XORPEN);setlinecolor(LIGHTCYAN);  // 线条颜色为亮青色setlinestyle(PS_SOLID, 3);  // 设置画线样式为实线,宽度为 3setfillcolor(WHITE);  // 填充颜色为白色if (button_judge(m.x, m.y) != 0){if (event != button_judge(m.x, m.y)){event = button_judge(m.x, m.y);  // 记录这一次触发的按钮fillrectangle(r[event - 1][0], r[event - 1][1], r[event - 1][2], r[event - 1][3]);  // 有框填充矩形(X1, Y1, X2, Y2)}}else{if (event != 0)  // 上次触发的按钮未被修正为原来的颜色{fillrectangle(r[event - 1][0], r[event - 1][1], r[event - 1][2], r[event - 1][3]);  // 两次同或为原来颜色event = 0;}}break;case WM_LBUTTONDOWN:setrop2(R2_NOTXORPEN);  // 二元光栅——NOT(屏幕颜色 XOR 当前颜色)for (i = 0; i <= 10; i++){setlinecolor(RGB(25 * i, 25 * i, 25 * i));  // 设置圆颜色circle(m.x, m.y, 2 * i);Sleep(20);  // 停顿 20mscircle(m.x, m.y, 2 * i);  // 抹去刚刚画的圆}// 按照按钮判断左键单击后的操作switch (button_judge(m.x, m.y)){case 1:InputBox(s, 30, "请输入碰撞时的能量损失率、球的半径、初始高度、仿真时间");sscanf(s, "%f %f %f %f", &alpha, &R, &h0, &sim_t);  // 将输入字符串依次扫描到全局变量中FlushMouseMsgBuffer();  // 单击事件后清空鼠标消息break;case 2:simulation();  // 仿真运行FlushMouseMsgBuffer();  // 单击事件后清空鼠标消息break;case 3:closegraph();  // 关闭绘图环境exit(0);  // 正常退出default:FlushMouseMsgBuffer();  // 单击事件后清空鼠标消息break;}break;}}return 0;
}

完整程序效果

进度条效果

希望本文对您有所帮助,谢谢阅读。


C 语言实现动画控制

非线性光学元件于 2018-12-22 20:47:28 发布

原材料

下载 EasyX 2014 冬至版,将 lib 文件放在编译器默认的 lib 文件夹中,h 头文件放在编译器默认的 include 文件夹中即可。下载链接:EasyX Graphics Library for C++

说明

C 语言可以使用系统内部的定时函数 sleepusleep 进行定时(需要 windows.h 头文件),但绘图窗口需要额外的图形库支持。EasyX 提供了绘图功能,可以为您的 C 编译器带来革命性的变化。

一场革命

EasyX 的压缩包中包含一个帮助文档,虽然内容丰富但不太方便查阅。希望正在使用 EasyX 的开发者能多分享一些资源。以下是一个沿着指定半径依次绘制 12 个不同颜色的圆并依次擦除的小动画程序。代码中对不太容易理解的部分加了注释,通过图形画法学习 C 语言语法,既生动又简单,可以快速跨越语法障碍。

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h>               // 用到了定时函数 sleep()
#include <math.h>
#define PI 3.14159265  // 画圆必备
int a[] = {0, 0xAA0000, 0x00AA00, 0xAAAA00, 0x0000AA, 0xAA00AA, 0x0055AA, 0xAAAAAA, 0x555555, 0xFF5555, 0x55FF55, 0xFFFF55, 0x5555FF, 0xFF55FF, 0x55FFFF, 0xFFFFFF};  // a[] 是颜色数组
// a 数组存放的颜色依次为
/*	|0:黑色		|1:蓝色		|2:绿色		|3:青色		|4:红色|5:紫色		|6:棕色		|7:浅灰		|8:深灰		|9:亮蓝|10:亮绿	|11:亮青	|12:亮红	|13:亮紫	|14:黄色	|15:白色
*/
int main()
{system("color 0B");  // 设置字体为亮蓝色,纯粹为了好看short x, y;  // 圆心坐标int R;  // 旋转半径int color[6] = {1, 2, 3, 4, 5, 6};  // 指定圆的颜色int i = 0;char t;printf("C 语言绘图实验:\n");printf("请选择画布大小(以空格分隔):\n");scanf("%d %d", &x, &y);initgraph(x, y, SHOWCONSOLE);  // 创建绘图窗口,大小为 640x480 像素printf("请输入旋转半径: ");scanf("%d", &R);printf("请选择 6 种圆的颜色:\n");printf("|0:黑色\n|1:蓝色\t|2:绿色\t|3:青色\t|4:红色\t|5:紫色\n|6:棕色\t|7:浅灰\t|8:深灰\t|9:亮蓝\t|10:亮绿\n|11:亮青\t|12:亮红\t|13:亮紫\t|14:黄色\t|15:白色\n");scanf("%d %d %d %d %d %d", &color[0], &color[1], &color[2], &color[3], &color[4], &color[5]);  // 录入 6 种不同的颜色printf("\r按任意键继续:\n");while (_getch())  // _getch() 是按下任意键即返回非零值的函数,与 getchar() 不同,不经过标准输入流的缓存区{for (i = 0; i < 12; i++){setlinecolor(RGB(0, 0, 0));  // 设置当前线条颜色setfillcolor(a[color[i % 6]]);  // 设置当前填充颜色fillcircle(x / 2 + R * cos(i * PI / 6), y / 2 + R * sin(i * PI / 6), R * (PI / 12) * 0.9);  // 绘制填充圆Sleep(300);  // 延时 300ms}for (i = 0; i < 12; i++){setlinecolor(RGB(0, 0, 0));  // 设置当前线条颜色setfillcolor(a[0]);  // 背景色(黑色)覆盖掉原来的图形fillcircle(x / 2 + R * cos(i * PI / 6), y / 2 + R * sin(i * PI / 6), R * (PI / 12) * 0.9);Sleep(300);  // 延时 300ms}}return 0;
}

以下是程序运行主界面:

程序运行主界面

以下是绘图界面:

C 语言绘图界面


C 语言写字符动画

Z.IA 已于 2024-12-01 14:26:02 修改

用 C 在控制台写了一个动画,代码没做优化,十分简单粗暴。

新版本 win 系统需使用老版本 cmd。

以管理员身份运行 exe 文件即可。

 #include <stdio.h>#include <windows.h>void color (int x){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),x);	}int main()
{int i,j,q=28,xxl=22,h=27,m=33,cc=2,xxx=1;char s[68][53];char z[140][53];char zx[148][100];for(i=0;i<35;i++){for(j=0;j<28;j++)zx[i][j]=' ';for(j=28;j<=35;j++)zx[i][j]='O';for(j=36;j<100;j++)zx[i][j]=' ';	}	for(i=35;i<134;i++){for(j=0;j<h;j++)zx[i][j]=' ';for(j=h;j<h+4;j++)zx[i][j]='O';for(j=h+4;j<=m;j++)zx[i][j]=' ';for(j=m;j<m+4;j++)zx[i][j]='O';for(j=m+4;j<100;j++)zx[i][j]=' ';if(i<57){h--;m++;}if(i>110){h++;m--;}}for(i=134;i<148;i++){for(j=0;j<28;j++)zx[i][j]=' ';for(j=28;j<=35;j++)zx[i][j]='O';for(j=36;j<100;j++)zx[i][j]=' ';	}	for(i=48;i<=51;i++)for(j=31;j<=35;j++)zx[i][j]='*';for(i=129;i<=133;i++){for(j=15;j<=17;j++)zx[i][j]='*';for(j=46;j<=48;j++)zx[i][j]='*';}for(i=0;i<40;i++)  //直行 {for(j=0;j<28;j++)z[i][j]=' ';for(j=28;j<36;j++)z[i][j]='O';for(j=36;j<53;j++)z[i][j]=' ';}for(i=40;i<61;i++)   //拐弯+回; {for(j=0;j<q;j++)z[i][j]=' ';for(j=q;j<q+8;j++)z[i][j]='O';for(j=q+8;j<60;j++)z[i][j]=' ';if(i<53)                 //右移长度控制 q-=2;               if(i>53&&i<60)             //回长度控制 q++;}for(i=61;i<101;i++)  //直行 {for(j=0;j<8;j++)z[i][j]=' ';for(j=8;j<16;j++)z[i][j]='O';for(j=16;j<53;j++)z[i][j]=' ';}for(i=101;i<124;i++)   //拐弯+回; {for(j=0;j<q;j++)z[i][j]=' ';for(j=q;j<q+8;j++)z[i][j]='O';for(j=q+8;j<60;j++)z[i][j]=' ';if(i<114)                 //右移长度控制 q+=2;               if(i>114&&i<121)             //回长度控制 q--;}for(i=124;i<140;i++){for(j=0;j<28;j++)z[i][j]=' ';for(j=28;j<=35;j++)z[i][j]='O';for(j=36;j<100;j++)z[i][j]=' ';	}	for(i=54;i<=57;i++)z[i][30]=z[i][31]=z[i][32]='*';for(i=116;i<=119;i++)z[i][14]=z[i][15]=z[i][16]='*';for(i=0;i<40;i++)  //直行 {for(j=0;j<22;j++)s[i][j]=' ';for(j=22;j<29;j++)s[i][j]='O';for(j=29;j<53;j++)s[i][j]=' ';}for(i=40;i<68;i++)   //拐弯+回; {for(j=0;j<xxl;j++)s[i][j]=' ';for(j=xxl;j<xxl+8;j++)s[i][j]='O';for(j=xxl+8;j<53;j++)s[i][j]=' ';if(i<53)                 //右移长度控制 xxl++;               if(i>53&&i<60)             //回长度控制 xxl--;}int k,c=28,begin=28,end=39;
q=39;char x[104][40];	for(i=0;i<=10;i++){for(j=0;j<q;j++)x[i][j]=' ';for(j=q;j<=39;j++)x[i][j]='O';if(q>27)q--;}for(i=90;i<=101;i++){for(j=0;j<=c;j++)x[i][j]=' ';for(j=c+1;j<=39;j++)x[i][j]='O';if(c<39)c++;}for (i=11;i<=50;i++){for (j=0;j<begin;j++)x[i][j]=' ';for (j=begin;j<=end;j++)x[i][j]='O';for (j=end+1;j<=39;j++)x[i][j]=' ';if(begin>0)begin--;if(end>0)end--;}end++;for (i=51;i<=89;i++){for (j=0;j<begin;j++)x[i][j]=' ';for (j=begin;j<=end;j++)x[i][j]='O';for (j=end+1;j<=39;j++)x[i][j]=' ';if(end>=11)begin++;if(end<39)end++;}//扭动组赋值 char kd[100][40];
for(i=0;i<100;i++)
{for(j=0;j<38;j++)kd[i][j]=' ';kd[i][39]='O';
}int p=1,g=1,xs=3;char wy[200][120];for(i=0;i<200;i++)for(j=0;j<120;j++)wy[i][j]=' ';for(i=0;i<40;i++){for(j=0;j<8;j++)wy[i][j]=' ';for(j=8;j<16;j++)wy[i][j]='O';for(j=16;j<100;j++)wy[i][j]=' ';}/*直行赋值*/ j=16;for(i=40;i<76;i++){wy[i][j]='O';	if((i-39)%4==0&&i>=43)g+=p;j+=g;if(i==55)p=-p;} j=15;p=1;g=1;for(i=42;i<78;i++){wy[i][j]='O';	if((i-41)%4==0&&i>=45)g+=p;j+=g;if(i==57)p=-p;} j=14;p=1;g=1;for(i=44;i<80;i++){wy[i][j]='O';	if((i-43)%4==0&&i>=47)g+=p;j+=g;if(i==59)p=-p;} j=13;p=1;g=1;for(i=46;i<82;i++){wy[i][j]='O';	if((i-45)%4==0&&i>=49)g+=p;j+=g;if(i==61)p=-p;} j=12;p=1;g=1;for(i=48;i<84;i++){wy[i][j]='O';	if((i-47)%4==0&&i>=51)g+=p;j+=g;if(i==63)p=-p;} // 第5组; j=11;p=1;g=1;for(i=50;i<86;i++){wy[i][j]='O';	if((i-49)%4==0&&i>=53)g+=p;j+=g;if(i==65)p=-p;} j=10;p=1;g=1;for(i=52;i<88;i++){wy[i][j]='O';	if((i-51)%4==0&&i>=55)g+=p;j+=g;if(i==67)p=-p;} j=9;p=1;g=1;for(i=54;i<90;i++){wy[i][j]='O';	if((i-53)%4==0&&i>=57)g+=p;j+=g;if(i==69)p=-p;} p=54;for(j=8;j<16;j++){for(i=40;i<p;i++)wy[i][j]='O';p-=2;}//补充 O p=75;for(j=116;j>=110;j--){for(i=89;i>p;i--)wy[i][j]='O';p+=2;}for(i=90;i<130;i++){for(j=109;j<117;j++)wy[i][j]='O';}j=108;
p=-1;
g=-1;for(i=130;i<166;i++){wy[i][j]='O';	if((i-129)%4==0&&i>=133)g+=p;j+=g;if(i==145)p=-p;} j=109;
p=-1;
g=-1;for(i=132;i<168;i++){wy[i][j]='O';	if((i-131)%4==0&&i>=135)g+=p;j+=g;if(i==147)p=-p;} j=110;
p=-1;
g=-1;for(i=134;i<170;i++){wy[i][j]='O';	if((i-133)%4==0&&i>=137)g+=p;j+=g;if(i==149)p=-p;} j=111;
p=-1;
g=-1;for(i=136;i<172;i++){wy[i][j]='O';	if((i-135)%4==0&&i>=139)g+=p;j+=g;if(i==151)p=-p;} j=112;
p=-1;
g=-1;for(i=138;i<174;i++){wy[i][j]='O';	if((i-137)%4==0&&i>=141)g+=p;j+=g;if(i==153)p=-p;} j=113;p=-1;g=-1;for(i=140;i<176;i++){wy[i][j]='O';	if((i-139)%4==0&&i>=143)g+=p;j+=g;if(i==155)p=-p;} j=114;p=-1;g=-1;for(i=142;i<178;i++){wy[i][j]='O';	if((i-141)%4==0&&i>=145)g+=p;j+=g;if(i==157)p=-p;} j=115;p=-1;g=-1;for(i=144;i<180;i++){wy[i][j]='O';	if((i-143)%4==0&&i>=147)g+=p;j+=g;if(i==159)p=-p;} p=165;for(j=8;j<16;j++){for(i=179;i>p;i--)wy[i][j]='O';p+=2;}p=144;for(j=116;j>=110;j--){for(i=130;i<p;i++)wy[i][j]='O';p-=2;}for(i=180;i<200;i++){for(j=0;j<8;j++)wy[i][j]=' ';for(j=8;j<16;j++)wy[i][j]='O';for(j=16;j<100;j++)wy[i][j]=' ';}//菱形部分 char a[50][54];k=15;begin=24;end=27;for(i=0;i<=49;i++)for(j=24;j<=27;j++)a[i][j]='O';for(i=0;i<=24;i++){for(j=0;j<begin;j++)a[i][j]=' ';for(j=begin;j<24;j++)a[i][j]='i';for(j=28;j<=end;j++)a[i][j]='i';for(j=end+1;j<=51;j++)a[i][j]=' ';begin-=1;end+=1;}begin+=1;end-=1;for(i=25;i<=49;i++){for(j=0;j<begin;j++)a[i][j]=' ';for(j=begin;j<24;j++)a[i][j]='i';for(j=28;j<=end;j++)a[i][j]='i';for(j=end+1;j<=51;j++)a[i][j]=' ';begin+=1;end-=1;}system("color f3");for(i=0;i<100;i++){for(j=0;j<40;j++)printf("%c",kd[i][j]);printf("\n\n");Sleep(2);}  int yans=2;system("color f3");while(yans--)
{for(i=0;i<=100;i++){for (j=0;j<=39;j++)printf("%c",x[i][j]);if(i<=100)printf("\n\n");Sleep(1);} 
}k=3;while (k--){for(i=0;i<=49;i++){for(j=0;j<24;j++){color(3);printf("%c",a[i][j]);}for(j=24;j<=27;j++){color(7);printf("%c",a[i][j]);}for(j=28;j<=51;j++){color(3);printf("%c",a[i][j]);}printf("\n\n");Sleep(1);}}color(7);for(i=47;i<=50;i++)s[i][8]=s[i][9]=s[i][10]='*';for(i=0;i<47;i++){ for(j=0;j<53;j++)printf("%c",s[i][j]);printf("\n\n");Sleep(1);
}for(i=47;i<=50;i++){for(j=0;j<=10;j++){color(4);printf("%c",s[i][j]);}for(j=11;j<53;j++){color(7);printf("%c",s[i][j]);}printf("\n\n");}for(i=51;i<68;i++){for(j=0;j<53;j++)printf("%c",s[i][j]);printf("\n\n");Sleep(1);
}while(cc--)
{for(i=0;i<54;i++)
{ for(j=0;j<53;j++)printf("%c",z[i][j]);printf("\n\n");Sleep(1);
}for(i=54;i<=57;i++){for(j=0;j<=29;j++){color(7);printf("%c",z[i][j]);}for(j=30;j<33;j++){color(4);printf("%c",z[i][j]);}printf("\n\n"); Sleep(1);}color(7); for(i=58;i<116;i++){  for(j=0;j<53;j++)printf("%c",z[i][j]);printf("\n\n");Sleep(1);}for(i=116;i<=119;i++){for(j=0;j<=16;j++){color(4);printf("%c",z[i][j]);}for(j=17;j<53;j++){color(7);printf("%c",z[i][j]);}printf("\n\n"); Sleep(1);}for(i=120;i<140;i++){for(j=0;j<53;j++)printf("%c",z[i][j]);printf("\n\n");Sleep(1);}
}while(xxx--)
{for(i=0;i<48;i++){for(j=0;j<100;j++)printf("%c",zx[i][j]);printf("\n\n");Sleep(1);}for(i=48;i<52;i++){for(j=0;j<31;j++)printf("%c",zx[i][j]);color(4);for(j=31;j<=35;j++)printf("%c",zx[i][j]);color(7);for(j=36;j<100;j++)printf("%c",zx[i][j]);printf("\n\n");Sleep(1);}for(i=52;i<129;i++){for(j=0;j<100;j++)printf("%c",zx[i][j]);printf("\n\n");Sleep(1);}for(i=129;i<134;i++){color(4);for(j=0;j<=17;j++)printf("%c",zx[i][j]);color(7);for(j=18;j<46;j++)printf("%c",zx[i][j]);color(4);for(j=46;j<100;j++)printf("%c",zx[i][j]);printf("\n\n");Sleep(1);}color(7);for(i=134;i<148;i++){for(j=0;j<100;j++)printf("%c",zx[i][j]);printf("\n\n");Sleep(1);}}for(i=0;i<54;i++)
{ for(j=0;j<53;j++)printf("%c",z[i][j]);printf("\n\n");Sleep(1);
}for(i=54;i<=57;i++){for(j=0;j<=29;j++){color(7);printf("%c",z[i][j]);}for(j=30;j<33;j++){color(4);printf("%c",z[i][j]);}printf("\n\n"); Sleep(1);}color(7); for(i=58;i<102;i++){  for(j=0;j<53;j++)printf("%c",z[i][j]);printf("\n\n");Sleep(1);}while(xs--)
{for(i=0;i<200;i++){for(j=0;j<120;j++){color(xs+2);printf("%c",wy[i][j]);}printf("\n\n");Sleep(2);}
}
}

via:

  • C语言图形化界面——含图形、按钮、鼠标、进度条等部件制作(带详细代码、讲解及注释)-CSDN博客
    https://blog.csdn.net/weixin_44044411/article/details/104276757

  • C 语言绘图实验-CSDN博客
    https://blog.csdn.net/weixin_44044411/article/details/85217818

  • C 语言写字符动画_c语言字符动画-CSDN博客
    https://blog.csdn.net/qq_60682749/article/details/124206299

  • 关于C语言实现easyX一帧一帧播放动态图(超详细)_如何用easyx实现简单的动画-CSDN博客
    https://blog.csdn.net/loneth/article/details/126788379

  • C语言图形编程(easyX简明教程) - C语言网
    https://www.dotcpp.com/course/easyx/

  • 动画原理 浅析 - Jenaral - 博客园
    https://www.cnblogs.com/Jenaral/p/5681815.html

  • 控制台动态绘制字符艺术-CSDN博客
    https://blog.csdn.net/dandelionLYY/article/details/86744041

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/80295.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发狂飙VS稳定刹车:Utility Tree如何让架构决策“快而不失控”

大家好&#xff0c;我是沛哥儿。 在软件技术架构的世界里&#xff0c;架构师们常常面临灵魂拷问&#xff1a;高并发和低成本哪个优先级更高&#xff1f; 功能迭代速度和系统稳定性该如何平衡&#xff1f; 当多个质量属性相互冲突时&#xff0c;该如何做出科学决策&#xff1f; …

SCI论文图数据提取软件——GetData Graph Digitizer

在写综述或者毕业论文的时候一般会引用前人的文献数据图&#xff0c;但是直接截图获取来的数据图通常质量都不太高。因此我们需要从新画一张图&#xff0c;可以通过origin绘图来实现&#xff0c;今天介绍一个新的软件GetData Graph Digitizer 感谢下面博主分享的破解安装教程 …

深入探索 Apache Spark:从初识到集群运行原理

深入探索 Apache Spark&#xff1a;从初识到集群运行原理 在当今大数据时代&#xff0c;数据如同奔涌的河流&#xff0c;蕴藏着巨大的价值。如何高效地处理和分析这些海量数据&#xff0c;成为各行各业关注的焦点。Apache Spark 正是为此而生的强大引擎&#xff0c;它以其卓越…

场景可视化与数据编辑器:构建数据应用情境​

场景可视化是将数据与特定的应用场景相结合&#xff0c;借助数据编辑器对数据进行灵活处理和调整&#xff0c;通过模拟和展示真实场景&#xff0c;使企业能够更直观地理解数据在实际业务中的应用和影响&#xff0c;为企业的决策和运营提供有力支持。它能够将抽象的数据转化为具…

攻防世界-php伪协议和文件包含

fileinclude 可以看到正常回显里面显示lan参数有cookie值表示为language 然后进行一个判断&#xff0c;如果参数不是等于英语&#xff0c;就加上.php&#xff0c;那我们就可以在前面进行注入一个参数&#xff0c;即flag&#xff0c; payload&#xff1a;COOKIE:languageflag …

手撕LFU

博主介绍&#xff1a;程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章&#xff0c;首发gzh&#xff0c;见文末&#x1f447;&#x1f…

火影bug,未保证短时间数据一致性,拿这个例子讲一下Redis

本文只拿这个游戏的bug来举例Redis&#xff0c;如果有不妥的地方&#xff0c;联系我进行删除 描述&#xff1a;今天在高速上打火影&#xff08;有隧道&#xff0c;有时候会卡&#xff09;&#xff0c;发现了个bug&#xff0c;我点了两次-1000的忍玉&#xff08;大概用了1千七百…

KRaft (Kafka 4.0) 集群配置指南(超简单,脱离 ZooKeeper 集群)还包含了简化测试指令的脚本!!!

docker-compose方式部署kafka集群 Kafka 4.0 引入了 KRaft 模式&#xff08;Kafka Raft Metadata Mode&#xff09;&#xff0c;它使 Kafka 集群不再依赖 ZooKeeper 进行元数据管理。KRaft 模式简化了 Kafka 部署和管理&#xff0c;不需要额外配置 ZooKeeper 服务&#xff0c;…

Admyral - 可扩展的GRC工程自动化平台

文章目录 一、关于 Admyral相关链接资源关键特性 二、安装系统要求 三、快速开始1、启动服务 四、核心功能1、自动化即代码2、AI增强工作流3、双向同步编辑器4、工作流监控5、企业级基础设施 五、示例应用六、其他信息许可证遥测说明 一、关于 Admyral Admyral 是一个基于 Pyt…

DDR在PCB布局布线时的注意事项及设计要点

一、布局注意事项 控制器与DDR颗粒的布局 靠近原则&#xff1a;控制器与DDR颗粒应尽量靠近&#xff0c;缩短时钟&#xff08;CLK&#xff09;、地址/控制线&#xff08;CA&#xff09;、数据线&#xff08;DQ/DQS&#xff09;的走线长度&#xff0c;减少信号延迟差异。 分组隔…

计算机网络-LDP工作过程详解

前面我们已经学习了LDP的基础概念&#xff0c;了解了LDP会话的建立、LDP的标签控制等知识&#xff0c;今天来整体过一遍LDP的一个工作过程&#xff0c;后面我们再通过实验深入学习。 一、LDP标签分发 标签分发需要基于基础的路由协议建立LDP会话&#xff0c;激活MPLS和LDP。以…

解构与重构:自动化测试框架的进阶认知之旅

目录 一、自动化测试的介绍 &#xff08;一&#xff09;自动化测试的起源与发展 &#xff08;二&#xff09;自动化测试的定义与目标 &#xff08;三&#xff09;自动化测试的适用场景 二、什么是自动化测试框架 &#xff08;一&#xff09;自动化测试框架的定义 &#x…

跑不出的循环 | LoveySelf 系列定位

最近开始陷入一轮一轮的循环状态&#xff0c;无奈&#xff0c;只能自我整理一下。23年暑假&#xff0c;在计算机系折腾了一年后&#xff0c;重新打开博客&#xff0c;回想在数学系摸索博客写作的日子&#xff0c;思绪涌上心头&#xff0c;我们决定拾起这份力量。当时觉得 hexo …

Redis最新入门教程

文章目录 Redis最新入门教程1.安装Redis2.连接Redis3.Redis环境变量配置4.入门Redis4.1 Redis的数据结构4.2 Redis的Key4.3 Redis-String4.4 Redis-Hash4.5 Redis-List4.6 Redis-Set4.7 Redis-Zset 5.在Java中使用Redis6.缓存雪崩、击穿、穿透6.1 缓存雪崩6.2 缓冲击穿6.3 缓冲…

一文读懂Python之requests模块(36)

一、requests模块简介 requests模块是python中原生的一款基于网络请求的模块&#xff0c;功能强大&#xff0c;简单便捷且高效 &#xff0c;该模块可以模拟浏览器发送请求&#xff0c;主要包括指定url、发起请求、获取响应数据和持久化存储&#xff0c;包括 GET、POST、PUT、…

WPF之布局流程

文章目录 1. 概述2. 布局元素的边界框3. 布局系统原理3.1 布局流程时序图 4. 测量阶段(Measure Phase)4.1 测量过程4.2 MeasureOverride方法 5. 排列阶段(Arrange Phase)5.1 排列过程5.2 ArrangeOverride方法 6. 渲染阶段(Render Phase)7. 布局事件7.1 主要布局事件7.2 布局事件…

uniapp|获取当前用户定位、与系统设定位置计算相隔米数、实现打卡签到(可自定义设定位置、位置有效范围米数)

基于UniApp阐述移动应用开发中定位功能的实现全流程,涵盖实时定位获取、动态距离计算与自定义位置、有效范围设定等功能。文章提供完整的代码示例与适配方案,适用于社交签到、课堂教室打卡等场景。 目录 引言定位功能在移动应用中的价值(社交、导航、O2O等场景)UniApp跨平台…

Yii2.0 模型规则(rules)详解

一、基本语法结构 public function rules() {return [// 规则1[[attribute1, attribute2], validator, options > value, ...],// 规则2[attribute, validator, options > value, ...],// 规则3...]; }二、规则类型分类 1、核心验证器&#xff08;内置验证器&#xff0…

数据结构(三)——栈和队列

一、栈和队列的定义和特点 栈&#xff1a;受约束的线性表&#xff0c;只允许栈顶元素入栈和出栈 对栈来说&#xff0c;表尾端称为栈顶&#xff0c;表头端称为栈底&#xff0c;不含元素的空表称为空栈 先进后出&#xff0c;后进先出 队列&#xff1a;受约束的线性表&#xff0…

SQL Server 存储过程开发三层结构规范

以下是《SQL Server 存储过程开发三层结构规范》的正式文档结构&#xff0c;适用于企业级数据库应用开发场景&#xff0c;有助于团队协作、代码审查与自动化运维&#xff1a; &#x1f4d8; SQL Server 存储过程开发三层结构规范 一、架构设计总览 三层结构简介 层级命名约定…