程序猿的酷炫屏保
    2015-12-13 05:54:36 +08:00
  juxiuyu123
#include "stdafx.h"  
#include <windows.h>  
#define ID_TIMER    1   
#define STRMAXLEN  25                 //一个显示列的最大长度   
#define STRMINLEN  8                  //一个显示列的最小长度  
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;   
//////////////////////////////////////////////////////////////////   
//////////////////////////////////////////////////////////////////   
typedef struct tagCharChain           //整个当作屏幕的一个显示列,这是个双向列表   
{   
    struct tagCharChain *prev;        //链表的前个元素   
    TCHAR  ch;                        //一个显示列中的一个字符   
    struct tagCharChain *next;        //链表的后个元素   
}CharChain, *pCharChain;  
 
typedef struct tagCharColumn   
{   
    CharChain *head, *current, *point;   
    int x, y, iStrLen;               //显示列的开始显示的 x,y 坐标,iStrLen 是这个列的长度   
    int iStopTimes, iMustStopTimes;  //已经停滞的次数和必须停滞的次数,必须停滞的次数是随机的   
}CharColumn, *pCharColumn;  
  
int main(HINSTANCE hInstance, HINSTANCE hPrevInstance,   
   PSTR szCmdLine, int iCmdShow)   
{   
    static TCHAR szAppName[] = TEXT ("matrix") ;   
   HWND            hwnd ;   
    MSG            msg ;   
    WNDCLASS    wndclass ;  
  
    wndclass.style                = CS_HREDRAW | CS_VREDRAW ;   
   wndclass.lpfnWndProc        = WndProc ;   
    wndclass.cbClsExtra        = 0 ;   
   wndclass.cbWndExtra        = 0 ;   
    wndclass.hInstance        = hInstance ;  
  
   wndclass.hIcon                = LoadIcon (NULL, IDI_APPLICATION) ;   
    wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW) ;   
    wndclass.hbrBackground        = (HBRUSH) GetStockObject (BLACK_BRUSH) ;   
    wndclass.lpszMenuName        = NULL ;   
    wndclass.lpszClassName        = szAppName ;  
  
   if(!RegisterClass (&wndclass))   
    {   
        MessageBox (NULL, TEXT ("此程序必须运行在 NT 下!"), szAppName, MB_ICONERROR) ;   
        return 0;   
    }  
  
    hwnd = CreateWindow (szAppName, NULL,   
        WS_DLGFRAME | WS_THICKFRAME | WS_POPUP,   
       0, 0,   
       GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),   
       NULL, NULL, hInstance,   
        NULL) ;  
  
    ShowWindow (hwnd, SW_SHOWMAXIMIZED) ; //最大化显示   
    UpdateWindow (hwnd) ;   
    ShowCursor(FALSE);                    //隐藏鼠标光标   
 
    srand ((int) GetCurrentTime ()) ;     //初始化随机数发生器   
    while (GetMessage (&msg, NULL, 0, 0))   
    {   
        TranslateMessage (&msg) ;   
        DispatchMessage (&msg) ;   
    }   
    ShowCursor(TRUE);                   //显示鼠标光标   
    return msg.wParam ;   
}  
  
TCHAR randomChar()                      //随机字符产生函数   
{   
    return (TCHAR)(rand()%(126-33)+33); //33 到 126 之间   
}  
  
int init(CharColumn *cc, int cyScreen, int x) //初始化   
{   
    int j;   
    cc->iStrLen = rand()%(STRMAXLEN-STRMINLEN) + STRMINLEN; //显示列的长度   
    cc->x = x+3 ;                      //显示列的开始显示的 x 坐标   
    cc->y =rand()%3?rand()%cyScreen:0; //显示列的开始显示的 y 坐标   
    cc->iMustStopTimes = rand()%6 ;   
    cc->iStopTimes    = 0 ;   
    cc->head = cc->current =   
        (pCharChain)calloc(cc->iStrLen, sizeof(CharChain)); //生成显示列   
    for(j=0; j<cc->iStrLen-1; j++)   
    {   
        cc->current->prev = cc->point;      //cc->point 一个显示列的前个元素   
        cc->current->ch  = '\0';   
        cc->current->next = cc->current+1;  //cc->current+1 一个显示列的后个元素   
        cc->point          = cc->current++; //cc->point = cc->current; cc->current++;   
    }   
    cc->current->prev = cc->point;          //最后一个节点   
    cc->current->ch  = '\0';   
    cc->current->next = cc->head;   
    cc->head->prev    = cc->current;        //头节点的前一个为此链的最后一个元素  
  
    cc->current = cc->point = cc->head;     //free 掉申请的内存要用 current 当参数   
    cc->head->ch = randomChar();            // 对链表头的 元素填充   
    return 0;   
}  
  
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)   
{   
    HDC          hdc ;   
    //ctn 用来确定一个显示链是否 向下前进,如果等待次数超过必须等待的次数,ctn 就代表要向下前进   
    int i, j, temp, ctn;                   //j 为一个显示链中除链表头外的在屏幕上显示的 y 坐标,temp 绿色过度到黑色之用   
    static  HDC hdcMem;   
    HFONT    hFont;   
    static  HBITMAP hBitmap;   
    static  int cxScreen, cyScreen;       //屏幕的宽度 高度.   
    static  int iFontWidth=10, iFontHeight=15, iColumnCount; //字体的宽度 高度, 列数   
    static  CharColumn *ccChain;  
  
    switch (message)   
    {   
    case WM_CREATE:   
        cxScreen = GetSystemMetrics(SM_CXSCREEN) ; //屏幕宽度   
        cyScreen = GetSystemMetrics(SM_CYSCREEN) ;   
        SetTimer (hwnd, ID_TIMER, 10, NULL) ;  
  
        hdc = GetDC(hwnd);   
        hdcMem = CreateCompatibleDC(hdc);   
        hBitmap = CreateCompatibleBitmap(hdc, cxScreen, cyScreen);   
        SelectObject(hdcMem, hBitmap);   
        ReleaseDC(hwnd, hdc);   
        //创建字体   
        hFont = CreateFont(iFontHeight, iFontWidth-5, 0, 0, FW_BOLD, 0, 0, 0,   
            DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,   
            DRAFT_QUALITY, FIXED_PITCH | FF_SWISS, TEXT("Fixedsys"));   
        SelectObject(hdcMem, hFont);   
        DeleteObject (hFont) ;   
        SetBkMode(hdcMem, TRANSPARENT);           //设置背景模式为 透明   
        iColumnCount = cxScreen/(iFontWidth*3/2); //屏幕所显示字母雨的列数  
  
        ccChain = (pCharColumn)calloc(iColumnCount, sizeof(CharColumn));   
        for(i=0; i<iColumnCount; i++)   
        {   
            init(ccChain+i, cyScreen, (iFontWidth*3/2)*i);   
        }   
        return 0 ;  
  
    case WM_TIMER:   
        hdc = GetDC(hwnd);   
        PatBlt (hdcMem, 0, 0, cxScreen, cyScreen, BLACKNESS) ; //将内存设备映像刷成黑色   
        for(i=0; i<iColumnCount; i++)   
        {   
            ctn = (ccChain+i)->iStopTimes++ > (ccChain+i)->iMustStopTimes;   
            //   
            (ccChain+i)->point = (ccChain+i)->head; //point 用于遍历整个显示列   
  
            //第一个字符显示为 白色   
            SetTextColor(hdcMem, RGB(255, 255, 255));   
            TextOut(hdcMem, (ccChain+i)->x, (ccChain+i)->y, &((ccChain+i)->point->ch), 1);   
           j = (ccChain+i)->y;    
            (ccChain+i)->point = (ccChain+i)->point->next;   
            //遍历整个显示列,将这个显示列里的字符从下往上显示   
            temp = 0 ; //temp 绿色过度到黑色之用   
            while((ccChain+i)->point != (ccChain+i)->head && (ccChain+i)->point->ch)   
            {   
                SetTextColor(hdcMem, RGB(0, 255-(255*(temp++)/(ccChain+i)->iStrLen), 0));   
                TextOut(hdcMem, (ccChain+i)->x, j-=iFontHeight, &((ccChain+i)->point->ch), 1);   
                (ccChain+i)->point = (ccChain+i)->point->next;   
            }   
            if(ctn)   
                (ccChain+i)->iStopTimes = 0 ;   
            else continue;   
            (ccChain+i)->y += iFontHeight; //下次开始显示的 y 坐标 为当前的 y 坐标加上 一个字符的高度   
            //如果开始显示的 y 坐标减去 整个显示列的长度超过了屏幕的高度   
            if( (ccChain+i)->y-(ccChain+i)->iStrLen*iFontHeight > cyScreen)   
            {   
                free( (ccChain+i)->current );   
                init(ccChain+i, cyScreen, (iFontWidth*3/2)*i);   
            }   
            //链表的头 为此链表的前个元素,因为下次开始显示的时候 就相当与在整个显示列的开头添加个元素,然后在开始往上显示   
            (ccChain+i)->head = (ccChain+i)->head->prev;   
            (ccChain+i)->head->ch = randomChar();   
        }   
  
        BitBlt(hdc, 0, 0, cxScreen, cyScreen, hdcMem, 0, 0, SRCCOPY);   
        ReleaseDC(hwnd, hdc);   
        return 0;  
  
    case WM_RBUTTONDOWN:   
        KillTimer (hwnd, ID_TIMER) ;   
        return 0;  
  
    case WM_RBUTTONUP:   
        SetTimer (hwnd, ID_TIMER, 10, NULL) ;   
       return 0;  
  
        //处理善后工作   
    case WM_KEYDOWN:         // 按下键盘任意键
    case WM_LBUTTONDOWN:     //鼠标双击
    case WM_DESTROY:   
        KillTimer (hwnd, ID_TIMER) ;   
        DeleteObject(hBitmap);   
        DeleteDC(hdcMem);   
        for(i=0; i<iColumnCount; i++)   
        {   
            free( (ccChain+i)->current );   
        }   
        free(ccChain);   
        PostQuitMessage (0) ;   
        return 0 ;   
    }   
    return DefWindowProc (hwnd, message, wParam, lParam) ;   
}
    
    
    
    14 条回复
    
    
    
      
      vibbow
2015-12-13 06:34:06 +08:00
没看代码
但是看标题,猜测不会是黑客帝国那种效果把...
 
    
    
      
      hqs123
2015-12-13 08:08:14 +08:00
楼主是编程高手啊...
 
    
    
      
      greatghoul
2015-12-13 09:47:43 +08:00
楼主不如直接给个 gist 链接 ,你这排版一点也不炫。
 
    
    
      
      wyntau
2015-12-13 10:54:20 +08:00
请使用 cmatrix
 
    
    
      
      Ouyangan
2015-12-13 10:55:10 +08:00
编码风格,我头痛~
 
    
    
      
      Karblue
2015-12-13 11:34:37 +08:00
不用看了。字母雨效果
 
    
    
      
      harry890829
2015-12-13 12:03:00 +08:00
windows 的……
 
    
    
      
      loading
2015-12-13 12:22:25 +08:00
楼主你知道这样贴是没人看的吗?
 
    
    
      
      tangbao
2015-12-13 17:39:31 +08:00
LZ , stdafx.h 这个头文件是不是只有 vc++才有的啊?
 
    
    
      
      Barnet
2015-12-13 20:27:42 +08:00
没看评论,我估也是黑客帝国那种效果
 
    
    
      
      haogefeifei
2015-12-13 21:50:40 +08:00
看见 windows.h 。我默默的不说话了。。。
 
    
    
      
      icedx
2015-12-13 23:44:30 +08:00
Windows 还是 MFC 啧啧
 
    
    
      
      exoticknight
2015-12-13 23:51:11 +08:00
除了黑客帝国还能怎么酷炫?
 
    
    
      
      matthewz
2015-12-14 00:13:35 +08:00
誰還看 mfc
 
    
    
    这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
     https://www.v2ex.com/t/243146
      V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
      V2EX is a community of developers, designers and creative people.