博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SDL2 自己画按钮
阅读量:6692 次
发布时间:2019-06-25

本文共 10915 字,大约阅读时间需要 36 分钟。

hot3.png

SDL2 没有自带控件,今天尝试自己画个按钮。

用图片按钮是最简单的:找几幅图片,代表不同的按钮状态,根据需要显示即可。

这里实现一个windows标准风格、文字的,可以通用,不用带着不同的图片跑了——图片到底大,而且不通用。

首先把那个五子棋程序里的取得纹理的几个函数独立成一个库,方便调用

// GetTexture.h// SDL2 公共函数 - 取得 RGB、文字、图片的纹理#include 
#include 
#include 
#ifndef SDL2_GET_TEXTURE_H#define SDL2_GET_TEXTURE_H// 取得颜色板纹理// 参数:pRenderer = 渲染器;color = 颜色;width, height = 颜色板宽、高// 返回值:纹理指针extern SDL_Texture *GetRGBTexture(SDL_Renderer *pRenderer, int color, int width, int height);// 取得图片文件纹理// 参数:pRenderer = 渲染器;FileName = 图片文件名;bTransparent = 是否透明处理;color = 背景色// 返回值:纹理指针extern SDL_Texture *GetImageTexture(SDL_Renderer *pRenderer, char *FileName, _Bool bTransparent, int color);// 取得字符串纹理// 参数:pRenderer = 渲染器;szString = 字符串内容;pFont = 字体;color = 文字颜色// 返回值:纹理指针extern SDL_Texture *GetTextTexture(SDL_Renderer *pRenderer, char *text, TTF_Font *pFont, int color);#endif

// GetTexture.c// SDL2 公共函数 - 取得 RGB、文字、图片的纹理#include "GetTexture.h"// 取得颜色板纹理// 参数:pRenderer = 渲染器;color = 颜色;width, height = 颜色板宽、高// 返回值:纹理指针SDL_Texture *GetRGBTexture(SDL_Renderer *pRenderer, int color, int width, int height){    SDL_Texture *pTexture;    SDL_Surface *pSurface;    if((pSurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0)) == NULL)        return NULL;    SDL_FillRect(pSurface, NULL, color);    pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);    SDL_FreeSurface(pSurface);    return pTexture;}// 取得图片文件纹理// 参数:pRenderer = 渲染器;FileName = 图片文件名;bTransparent = 是否透明处理;color = 背景色// 返回值:纹理指针SDL_Texture *GetImageTexture(SDL_Renderer *pRenderer, char *FileName, _Bool bTransparent, int color){    SDL_Texture *pTexture;    SDL_Surface *pSurface;    if((pSurface = IMG_Load(FileName)) == NULL)        return NULL;    if(bTransparent)        SDL_SetColorKey(pSurface, 1, SDL_MapRGB(pSurface->format, color>>16, (color>>8)&0xFF, color&0xFF));    pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);    SDL_FreeSurface(pSurface);    return pTexture;}// 取得字符串纹理// 参数:pRenderer = 渲染器;szString = 字符串内容;pFont = 字体;color = 文字颜色// 返回值:纹理指针SDL_Texture *GetTextTexture(SDL_Renderer *pRenderer, char *text, TTF_Font *pFont, int color){    SDL_Texture *pTexture;    SDL_Surface *pSurface;    SDL_Color c = {color>>16, (color>>8)&0xFF, color&0xFF};    if((pSurface = TTF_RenderUTF8_Blended(pFont, text, c)) == NULL)        return NULL;    pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);    SDL_FreeSurface(pSurface);    return pTexture;}

在这个基础上画按钮

// button.h// SDL2 自定义部件 - 按钮#include 
#include 
#ifndef SDL_WIDGET_BUTTON_H#define SDL_WIDGET_BUTTON_H// 按钮状态typedef enum en_SDL_Button_State{    BTN_STATE_NORMAL,     // 正常    BTN_STATE_DOWN,       // 按下    BTN_STATE_UP          // 弹起} SDL_Button_State;// 按钮结构typedef struct st_SDL_Button{    int id;    int x, y, w, h;             // 窗口(渲染器)定位    char *text;                 // 文字    _Bool enable;               // 是否可用    SDL_Button_State state;     // 状态} SDL_Button;// 画按钮// 参数:pRenderer = 渲染器;pFont = 字体;pbtn = 按钮数组;btnNum = 按钮数量extern void SDL_DrawButton(SDL_Renderer *pRenderer, TTF_Font *pFont, SDL_Button *pbtn, int btnNum);// 坐标是否在有效按钮上// 参数:x,y = 坐标;pbtn = 按钮数组;btnNum = 按钮数量// 返回值:按钮ID,或者 -1(不在有效按钮上)extern int SDL_isOnButton(int x, int y, SDL_Button *pbtn, int btnNum);#endif

// button.c// SDL2 自定义部件 - 按钮#include "button.h"#include "GetTexture.h"// 坐标是否在有效按钮上// 参数:x,y = 坐标;pbtn = 按钮数组;btnNum = 按钮数量// 返回值:按钮ID,或者 -1(不在有效按钮上)int SDL_isOnButton(int x, int y, SDL_Button *pbtn, int btnNum){    for(int i=0; i
= pbtn[i].x && x <= pbtn[i].x + pbtn[i].w && y >= pbtn[i].y && y <= pbtn[i].y + pbtn[i].h)            return pbtn[i].id;    return -1;}// 画按钮// 参数:pRenderer = 渲染器;pFont = 字体;pbtn = 按钮数组;btnNum = 按钮数量void SDL_DrawButton(SDL_Renderer *pRenderer, TTF_Font *pFont, SDL_Button *pbtn, int btnNum){    int BackGroundColor, TextColor;    Uint8 UpLineColor, DownLineColor;    SDL_Texture *pBackGroundTexture;    SDL_Texture *pTextTexture;    SDL_Rect rt;    for(int i=0; i

然后在消息循环里处理鼠标按键消息、移动消息

// Five.c// SDL2 五子棋//#define _DEBUG_#include 
#include 
#include 
#include 
#include 
#include 
#include "FiveData.h"#include "GetTexture.h"#include "button.h"// 资源文件char *ImageFileName[] ={    "Resource/BackGround.jpg",  // 棋盘背景图文件    "Resource/BlackPiece.jpg",  // 黑棋子图文件    "Resource/WhitePiece.jpg"   // 白棋子图文件};int BackColor        = 0xFFFFFF;// 棋子图片的背景色char FontFileName[]  = "C:/Windows/Fonts/msyh.ttf";  // 字体文件char SoundFileName[] = "Resource/Stone.mp3";         // 落子音效文件// 字符串常量char szWindowTitle[] = "SDL2 五子棋";char *szWho[]  ={    "黑方",    "白方"};char *szGameTips[] ={    "第 %d 手,轮到 %s 落子",    "共 %d 手,%s 取得本局胜利"};_Bool OnKeyUp(int x, int y, int nSpacing);void DrawBoard(SDL_Renderer *pRenderer, int nSpacing, int color);void DrawPieces(SDL_Renderer *pRenderer, int nSpacing, SDL_Texture **pImageTexture);void PrintString(SDL_Renderer *pRenderer, int nSpacing, char *text, TTF_Font *pFont, int color);void UpdateWindow(SDL_Window *pWindow, SDL_Renderer *pRenderer, int nSpacing, TTF_Font *pFont,                  SDL_Texture **pImageTexture, SDL_Button *pBtn, int n);#undef mainint main(int argc, char **argv){    int nWindowWidth  = 640;        // 屏幕尺寸    int nWindowHeight = 480;    int nSpacing;                   // 棋盘线距    SDL_Window   *pWindow;          // 主窗口    SDL_Renderer *pRenderer;        // 主窗口渲染器    SDL_Texture  *pImageTexture[3]; // 棋盘背景、黑白棋子图纹理    TTF_Font     *pFont;    // 提示文字字体    Mix_Music    *pMusic;   // 音效    SDL_Event    event;     // 事件    _Bool        bRun;      // 持续等待事件控制循环标识    // 按钮    int id;    int btnNum = 2;    SDL_Button btn[2] =    {        {0, 0,0,0,0, "新局", 0, BTN_STATE_NORMAL},        {1, 0,0,0,0, "悔棋", 0, BTN_STATE_NORMAL}    };    // 初始化:SDL2、SDL_Image(jpg)、SDL_ttf、SDL_Mixer    if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096) == -1            || SDL_Init(SDL_INIT_VIDEO) == -1 || IMG_Init(IMG_INIT_JPG) == -1 || TTF_Init() == -1)    {#ifdef _DEBUG_        fprintf(stderr, "1 %s", SDL_GetError());#endif        return 1;    }    // 创建主窗口及其渲染器    if(SDL_CreateWindowAndRenderer(640, 480, SDL_WINDOW_RESIZABLE, &pWindow, &pRenderer) == -1)    {#ifdef _DEBUG_        fprintf(stderr, "2 %s", SDL_GetError());#endif        goto label_error;    }    SDL_SetWindowTitle(pWindow, szWindowTitle);    // 加载图片文件    if(NULL == (pImageTexture[0] = GetImageTexture(pRenderer, ImageFileName[0], 0, 0))            || NULL == (pImageTexture[1] = GetImageTexture(pRenderer, ImageFileName[1], 1, BackColor))            || NULL == (pImageTexture[2] = GetImageTexture(pRenderer, ImageFileName[2], 1, BackColor)))    {#ifdef _DEBUG_        fprintf(stderr, "3 %s", IMG_GetError());#endif        goto label_error;    }    // 加载字体文件    if(NULL == (pFont = TTF_OpenFont(FontFileName, 20)))    {#ifdef _DEBUG_        fprintf(stderr, "4 %s", TTF_GetError());#endif        goto label_error;    }    // 加载声音文件    if((pMusic = Mix_LoadMUS(SoundFileName)) == NULL)    {#ifdef _DEBUG_        fprintf(stderr, "5 %s", Mix_GetError());#endif        goto label_error;    }    // 重置棋局数据,等待事件    Five_ResetData();    bRun = 1;    while(bRun && SDL_WaitEvent(&event))    {        switch(event.type)        {        case SDL_MOUSEMOTION :      // 鼠标移动            // 鼠标在某个按钮上,鼠标左键压下则该按钮处于凹状态,无鼠标键压下则该按钮处于凸状态            if((id = SDL_isOnButton(event.button.x, event.button.y, btn, 2)) >= 0)            {                if(event.motion.state == SDL_BUTTON_LMASK)                    btn[id].state = BTN_STATE_DOWN;                else                    btn[id].state = BTN_STATE_UP;            }            // 鼠标不在按钮上,则所有按钮正常显示            else            {                for(int i=0; i
= 0)            {                btn[id].state = BTN_STATE_DOWN;                UpdateWindow(pWindow, pRenderer, nSpacing, pFont, pImageTexture, btn, btnNum);            }            break;        case SDL_MOUSEBUTTONUP :    // 鼠标按键弹起,在某个按钮上则响应功能,在棋盘则检测落子            id = SDL_isOnButton(event.button.x, event.button.y, btn, 2);            // 新局            if(id == 0)            {                btn[0].enable = 0;                btn[1].enable = 0;                Five_ResetData();            }            // 悔棋            else if(id == 1)            {                btn[1].state = BTN_STATE_UP;                // TODO ...            }            // 有效落子            else if(id < 0 && g_iWho != NONE && OnKeyUp(event.button.x, event.button.y, nSpacing))            {                Mix_PlayMusic(pMusic, 0);                btn[0].enable = 1;                btn[1].enable = 1;                if(Five_isFive())                    g_iWho = NONE;            }            UpdateWindow(pWindow, pRenderer, nSpacing, pFont, pImageTexture, btn, btnNum);            break;        case SDL_WINDOWEVENT :      //  有窗口消息,重新计算窗口尺寸            SDL_GetWindowSize(pWindow, &nWindowWidth, &nWindowHeight);            nSpacing = SDL_min(nWindowWidth, nWindowHeight)/(MAX_LINES+2);            UpdateWindow(pWindow, pRenderer, nSpacing, pFont, pImageTexture, btn, btnNum);            break;        case SDL_QUIT :            bRun = 0;            break;        default :            break;        }    }label_error:// 清理    if(pImageTexture[0] != NULL) SDL_DestroyTexture(pImageTexture[0]);    if(pImageTexture[1] != NULL) SDL_DestroyTexture(pImageTexture[1]);    if(pImageTexture[2] != NULL) SDL_DestroyTexture(pImageTexture[2]);    if(pFont != NULL)  TTF_CloseFont(pFont);    if(pMusic != NULL) Mix_FreeMusic(pMusic);    Mix_CloseAudio();    TTF_Quit();    IMG_Quit();    SDL_Quit();    return 0;}// 重绘窗口void UpdateWindow(SDL_Window *pWindow, SDL_Renderer *pRenderer, int nSpacing, TTF_Font *pFont,                  SDL_Texture **pImageTexture, SDL_Button *pBtn, int btnNum){    char szString[256];    SDL_RenderClear(pRenderer);    SDL_RenderCopyEx(pRenderer, pImageTexture[0], NULL, NULL, 0, NULL, SDL_FLIP_NONE);    DrawBoard(pRenderer, nSpacing, 0);    DrawPieces(pRenderer, nSpacing, pImageTexture);    sprintf(szString, szGameTips[g_iWho==NONE],            g_nHands+(g_iWho!=NONE), szWho[(g_nHands+(g_iWho==NONE))%2]);    PrintString(pRenderer, nSpacing, szString, pFont, 0);    pBtn[0].x = nSpacing * (MAX_LINES+1);    pBtn[1].x = nSpacing * (MAX_LINES+4);    pBtn[1].y = pBtn[0].y = nSpacing;    pBtn[1].w = pBtn[0].w = nSpacing * 2;    pBtn[1].h = pBtn[0].h = nSpacing;    SDL_DrawButton(pRenderer, pFont, pBtn, btnNum);    SDL_RenderPresent(pRenderer);}// 响应落子按键// 参数:(x,y) = 被点击的窗口坐标;nSpacing = 棋盘线距_Bool OnKeyUp(int x, int y, int nSpacing){    // 计算落点棋盘坐标    int m = (x - 0.5*nSpacing)/nSpacing;    int n = (y - 0.5*nSpacing)/nSpacing;    // 处理有效落点    if(m>=0 && m
=0 && n
>16, (color>>8)&0xFF, color&0xFF, SDL_ALPHA_OPAQUE);    SDL_RenderFillRect(pRenderer, &rt);}// 画棋盘// 参数:pRenderer = 渲染器;nSpacing = 棋盘线距;color = 线及星颜色void DrawBoard(SDL_Renderer *pRenderer, int nSpacing, int color){    int r, x, y, z;    // 棋盘线    SDL_SetRenderDrawColor(pRenderer, color>>16, (color>>8)&0xFF, color&0xFF, SDL_ALPHA_OPAQUE);    for(int i = 1; i <= MAX_LINES; i++)    {        SDL_RenderDrawLine(pRenderer, nSpacing, i*nSpacing, MAX_LINES*nSpacing, i*nSpacing);        SDL_RenderDrawLine(pRenderer, i*nSpacing, nSpacing, i*nSpacing, MAX_LINES*nSpacing);    }    // 星位    r = nSpacing*0.2;               // 星半径    x = nSpacing*4;                 // 第四线    y = nSpacing*(MAX_LINES+1)/2;   // 中线    z = nSpacing*(MAX_LINES-3);     // 倒数第四线    FillCircle(pRenderer, x, x, r, color);    FillCircle(pRenderer, y, x, r, color);    FillCircle(pRenderer, z, x, r, color);    FillCircle(pRenderer, x, y, r, color);    FillCircle(pRenderer, y, y, r, color);    FillCircle(pRenderer, z, y, r, color);    FillCircle(pRenderer, x, z, r, color);    FillCircle(pRenderer, y, z, r, color);    FillCircle(pRenderer, z, z, r, color);}// 画棋子// 参数:pRenderer = 渲染器;nSpacing = 棋盘线距;pImageTexture = 棋子纹理void DrawPieces(SDL_Renderer *pRenderer, int nSpacing, SDL_Texture **pImageTexture){    int r = 0.4*nSpacing;  // 棋子半径    SDL_Rect rt = {0, 0, 2*r, 2*r};    if(g_nHands <= 0)        return;    for(int i=0; i

数据处理部分没有变化。悔棋按钮没有起作用,是因为涉及修改数据处理部分,懒得弄了。

转载于:https://my.oschina.net/u/580100/blog/614830

你可能感兴趣的文章
顺序表基础操作--练习
查看>>
Spring Cloud底层原理
查看>>
SSM前言——相关设计模式
查看>>
小清丽微距花卉拍摄示范
查看>>
GetSysColor()函数可以得到系统的颜色
查看>>
项目积累demo-01
查看>>
JAVA面向对象编程深入理解图
查看>>
Android开发笔记03
查看>>
[Hadoop in China 2011] 人人网:基于Hadoop的SNS统计和聚类推荐
查看>>
[转]阳光加利福尼亚 --土老冒的硅谷、旧金山见闻
查看>>
解决Eclipse下不自动拷贝apk到模拟器问题( The connection to adb is down, and a severe error has occured)...
查看>>
Google后Hadoop时代的新“三驾马车”——Caffeine、Pregel、Dremel
查看>>
jsp与jsp之间传参数如何获取
查看>>
如何做好一名售前工程师 [理论]
查看>>
什么是语法糖?
查看>>
rabbitMQ的安装和创建用户
查看>>
每天一道LeetCode--169.Majority Elemen
查看>>
Struts2笔记——第一个实例HelloWorld
查看>>
Maven安装
查看>>
2.1列表相关知识点
查看>>