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.pswp.cn/bicheng/80295.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80295.shtml
英文地址,請注明出處:http://en.pswp.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 存儲過程開發三層結構規范 一、架構設計總覽 三層結構簡介 層級命名約定…