组合按键的软件设计(c语言)

需求:
  根据用户的四个按键的(上下左右)显示对应的内容,左右键切换显示项目名称,上下键切换切换该项目的具体信息条目。另外有一个无符号整型变量上的每一位用于控制项目的显示与否,该位为1则显示对应项目,反之则不显示该项目。

  组合按键采用面向对象的思想,加上数据结构中的双向链表,这样的组合按键需求十分容易实现。

  下面是对上述需求的模型化:
  Linux终端用于显示,键盘上的w、s、a、d键和箭头符号分别表示上下左右按键。左右按键用于切换显示附近的银行名称,上下键用于切换显示该银行的具体信息,如地址、当前排队人数等。另外show_ctl变量对应的位用于控制对应的银行是否显示。

  编码如下:

#include <stdio.h>

#define KEY_UP      192
#define KEY_DOWN    193
#define KEY_LEFT    195
#define KEY_RIGHT   194

//封装显示结构体
typedef void (*SHOW_FUN)(void);
typedef struct _tag_bank
{
    struct _tag_bank* pre;
    struct _tag_bank* next;
    SHOW_FUN    showFunc[10];
    size_t      subScrMaxIndex;
    size_t      subScrIndex;
}bankItem_t;

bankItem_t *current_bankItem = NULL;

void agricultural_bank_func1() { printf("------------ 中国农业银行 ------------ \n");}
void agricultural_bank_func2(){ printf("1. 地址: xx街道xxx号\n");}
void agricultural_bank_func3(){ printf("2. 当前排队人数: 5人\n"); }
void agricultural_bank_func4() { printf("3. 上班时间: 9:30 ~ 17:30\n"); } 

void icbc_bank_func1() { printf("-------------- 工商银行 --------------\n"); }
void icbc_bank_func2() { printf("1. 地址: yy街道yyy号\n"); }
void icbc_bank_func3() { printf("2. 当前排队人数: 6人\n"); }
void icbc_bank_func4() { printf("3. 上班时间: 10:00 ~ 17:30\n"); }

void china_bank_func1() { printf("-------------- 中国银行 --------------\n"); }
void china_bank_func2() { printf("1. 地址: cc街道cc号\n"); }
void china_bank_func3() { printf("2. 当前排队人数: 8人\n"); }
void china_bank_func4() { printf("3. 上班时间: 10:00 ~ 17:00\n"); }

void construction_bank_func1() { printf("-------------- 建设银行 --------------\n"); }
void construction_bank_func2() { printf("1. 地址: zz街道zzz号\n"); }
void construction_bank_func3() { printf("2. 当前排队人数: 4人\n"); }
void construction_bank_func4() { printf("3. 上班时间: 9:00 ~ 17:00\n"); }

bankItem_t bank1 = {0, 0, {agricultural_bank_func1, agricultural_bank_func2, agricultural_bank_func3, agricultural_bank_func4}, 3, 0};
bankItem_t bank2 = {0, 0, {icbc_bank_func1, icbc_bank_func2, icbc_bank_func3, agricultural_bank_func4}, 3, 0};
bankItem_t bank3 = {0, 0, {china_bank_func1, china_bank_func2, china_bank_func3, china_bank_func4}, 3, 0};
bankItem_t bank4 = {0, 0, {construction_bank_func1, construction_bank_func2, construction_bank_func3, construction_bank_func4}, 3, 0};

//用于控制哪个银行是否显示 bit[0]-农业,bit[1]-工商,bit[2]-中国,bit[3]-建设
unsigned char show_ctl = 0x02;  

static bankItem_t* _show_ctl_arr[] = {&bank1, &bank2, &bank3, &bank4};
static char _check_show(unsigned char num)
{
    if ((show_ctl >> num) & 0x01)
        return 1;
    return 0;
}

//初始化显示条目的顺序
int struct_init()
{
    char i = 0, ret, cnt = 0;
    bankItem_t* tail = NULL;

    for (i = 0; i < 4; i++)
    {
        ret = _check_show(i);
        if (ret)
        {
            //以下是双向链表的插入操作
            if (current_bankItem == NULL)
            {
                _show_ctl_arr[i]->pre = _show_ctl_arr[i];
                _show_ctl_arr[i]->next = _show_ctl_arr[i];
                current_bankItem = _show_ctl_arr[i];
            }
            else
            {
                _show_ctl_arr[i]->next = current_bankItem;
                _show_ctl_arr[i]->pre = tail;
                tail->next = _show_ctl_arr[i];
                current_bankItem->pre = _show_ctl_arr[i];
            }
            tail = _show_ctl_arr[i];
            cnt++;
        }
    }
    return cnt;
}

//获取键盘数据
int static _get_input(void)
{
    char buf[8];
    int ret;

    ret = read(0, buf, 8);  //0是标准输入的fd
    if (ret == 1)           //用于输入的是w/s/a/d
        return buf[0];
    else if (ret == 3 && buf[0] == 27 && buf[1] == 91)  //用于输入的是箭头符号
        return 127 + buf[2];                            //小于127的数都和键盘上按键有对应关系 
}


int main(void)
{
    int c;
    int ret;

    system("clear");

    if (!(ret = struct_init())) //struct_init()根据select_ctl变量初始化显示条目的顺序
    {
        printf("\t[附近没有银行(%#x)]\n\n", show_ctl);
        return 0;
    }
    printf("\t[附近有%d家银行(%#x)]\n\n", ret, show_ctl);

    //关闭终端的输入回显
    system("stty -echo -icanon");    

    printf("当前位于:\n");
    current_bankItem->showFunc[current_bankItem->subScrIndex]();
    printf("[请按左右键显示附近银行,上下键显示当前银行信息] \n");
    while (1)
    {
        c = _get_input();

        if (c == 'a' || c == KEY_LEFT)
        {
            current_bankItem = current_bankItem->pre;
            current_bankItem->subScrIndex = 0;
        }
        else if (c == 'd' || c == KEY_RIGHT)
        {
            current_bankItem = current_bankItem->next;
            current_bankItem->subScrIndex = 0;
        }
        else if (c == 'w' || c == KEY_UP)
        {
            if (current_bankItem->subScrIndex < current_bankItem->subScrMaxIndex)
                current_bankItem->subScrIndex++;
        }
        else if (c == 's' || c == KEY_DOWN)
        {
            if (current_bankItem->subScrIndex > 1)
                current_bankItem->subScrIndex--;
            else
                current_bankItem->subScrIndex = 1;
        }
        else
        {
            printf("输入有误,请重新输入\n");
            continue;
        }
        current_bankItem->showFunc[current_bankItem->subScrIndex]();

    }

    //打开终端的输入回显
    system("stty echo icanon");        

    return 0;
}

  运行结果:
这里写图片描述

  比起用面向过程的方法实现,用面向对象思想和函数指针来设计按键应用程序,最大的好处在于其可扩展性,思路也清晰得多。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值