数码相册——电子书轮询方式支持多输入

  • 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
  • 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
  • 参考资料:《嵌入式Linux应用开发手册》、《嵌入式Linux应用开发手册第2版》、《gcc中文手册》
  • 开发环境:Linux 3.4.2内核、arm-linux-gcc 4.3.2工具链
  • 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3

目录

  • 数码相册——电子书轮询方式支持多输入
    • 一、前言
    • 二、框架图
      • 1、软件框架图
      • 2、Makefile框架图
    • 三、input输入部分
      • 1、管理者头文件`input_manager.h`
      • 2、管理者实现文件`input_manager.c`
      • 3、input设备——stdin
      • 4、input设备——touchscreen
    • 四、修改
      • 1、main.c文件修改
        • 1.1 显示支持信息部分
        • 1.2 循环部分
      • 2、draw.c文件修改
        • 2.1 初始化部分修改
      • 3、Makefile修改
        • 3.1 /input目录下Makefile
        • 3.2 顶层目录Makefile
    • 五、编译与运行
      • 1、编译
      • 2、运行

一、前言

在【1.7 数码相册—电子书(1)—实现】和【1.7 数码相册—电子书(2)—编写通用的Makefile】这两篇博文中,我们实现了在开发板中显示电子书,但是仍然存在一些缺点,这节课针对这些缺点来进行改进。

  • 实现:
    1、电子书支持多种输入方式如标准串口输入实现翻页退出操作,触摸LCD实现翻页操作;
    2、在main.c中采用轮询的方式支持多种输入方式。

二、框架图

1、软件框架图


对于上述完成主要功能的5个部分:encoding编码部分、fonts获取字体点阵部分、display显示部分、input输入部分、draw协调部分

  1. encoding编码部分去文件中获得编码信息,对于每个文件,保存的时候,系统对自动或手动的根据编码规范,对文件的信息进行编码:如保存为ASCII、GBK、UTF-8、UTF16LE、UTF16BE
  2. fonts获取字体点阵部分根据获得的编码信息得到字体数据(LCD上表示为点阵)
  3. display显示部分把字体数据(点阵)显示在LCD上
  4. input输入部分管理不同的输入方式,定制不同的输入方式所实现的控制,满足多种控制场合;
  5. draw协调部分组织各个模块部分进行合作,实现电子书的显示、翻页功能等。

2、Makefile框架图


由于整个分为如下3部分:顶层目录的Makefile顶层目录的Makefile.build各级子目录的Makefile

所以对于新添加的input输入部分需要进行如下修改:其目录下也需要添加该目录下的Makefile,对于顶层目录的Makeifle也需要添加obj-y += /input,具体的在编译的时候会介绍。

而对于顶层的Makefile.build不需要进行修改,因为它是一个比较通用的文件根据顶层目录的Makefile信息进入到各个子目录下进行预处理、编译、汇编,最后每个子目录与顶层得到的built-in.o进行链接,最后得到可执行文件show_file.

下面就来介绍添加的input输入部分

三、input输入部分

1、管理者头文件input_manager.h

在这个文件:

  • 定义一个结构体变量拓展文件可以根据自己的情况:分配结构体、设置结构体、注册结构体
  • 定义一些函数,供外部文件调用

#ifndef _INPUT_MANAGER_H
#define _INPUT_MANAGER_H
#include <sys/time.h>#define INPUT_TYPE_STDIN            0
#define INPUT_TYPE_TOUCHSCREEN      1#define INPUT_VALUE_UP              0
#define INPUT_VALUE_DOWN            1
#define INPUT_VALUE_EXIT            2
#define INPUT_VALUE_UNKONW         -1/* 输入事件信息结构体 */
typedef struct InputEvent {struct timeval time;int type;int val;
}T_InputEvent, *PT_InputEvent;/* 输入事件结构体 */
typedef struct InputOpr {char *name;int (*DeviceInit)(void);int (*DeviceExit)(void);int (*GetInputEvent)(PT_InputEvent ptInputEvent);struct InputOpr *ptNext;
}T_InputOpr, *PT_InputOpr;int RegisterInputOpr(PT_InputOpr ptFontOpr);
int InputInit(void);
void ShowInputOpr(void);
int GetInputEvent(PT_InputEvent ptInputEvent);
int AllInputDeviceInit(void);
int StdinInit(void);
int TouchScreenInit(void);#endif/* _INPUT_MANAGER_H */

2、管理者实现文件input_manager.c

  • 注册函数
    每个输入方式的结构体,可以调用这个函数把结构体注册到链表中
/* 函数名:  注册函数* 函数功能:构建一个链表:把多个拓展文件的结构体“串”起来* 函数实现:根据传入的结点,首先判断该链表头是否为空*              空则,头结点指向传入的节点,且把节点的ptNext域指向NULL*             不空则,尾插法插入链表*/
int RegisterInputOpr(PT_InputOpr ptInputOpr)
{PT_InputOpr ptTmp;if (!s_ptInputOprHead) {s_ptInputOprHead   = ptInputOpr;ptInputOpr->ptNext = NULL;} else {ptTmp = s_ptInputOprHead;while (ptTmp->ptNext){ptTmp = ptTmp->ptNext;}ptTmp->ptNext    = ptInputOpr;ptInputOpr->ptNext = NULL;}return 0;
}
  • 显示函数
    通过这个函数,可以把链表中所有input方式的名字打印出来,供用户查看所支持的input方式。
/* 显示支持拓展文件的名字 */
void ShowInputOpr(void)
{int i = 0;PT_InputOpr ptTmp = s_ptInputOprHead;while (ptTmp) {printf("%02d %s\n", i++, ptTmp->name);ptTmp = ptTmp->ptNext;}
}
  • 初始化函数
    调用此函数,可以把对应的input方式结构体放入链表中。
/* 初始化函数 */
int InputInit(void)
{int error;error = StdinInit();error |= TouchScreenInit();return error;
}
  • 调用input设备事件函数
/* 调用所有的Input设备的事件发生函数,即轮询的方式获取LCD或标准输入的数据 */
int GetInputEvent(PT_InputEvent ptInputEvent)
{/* 把链表中的InputOpr的GetInputEvent都调用一次,一旦有数据立即返回 */PT_InputOpr ptTmp;ptTmp = s_ptInputOprHead;while (ptTmp) {if (ptTmp->GetInputEvent(ptInputEvent) == 0)return 0;ptTmp = ptTmp->ptNext;}return -1;
}
  • 设备初始化函数
    初始化每个设备的函数(设置input设备、调整模式等)
/* 初始化所有支持的Input设备 */
int AllInputDeviceInit()
{int error;PT_InputOpr ptTmp;error = -1;ptTmp = s_ptInputOprHead;while (ptTmp) {if (ptTmp->DeviceInit() == 0)error = 0;ptTmp = ptTmp->ptNext;}return 0;
}
  • 完整文件

#include <config.h>
#include <string.h>
#include <stdlib.h>#include "input_manager.h"static PT_InputOpr s_ptInputOprHead; //链表头/* 函数名:  注册函数* 函数功能:构建一个链表:把多个拓展文件的结构体“串”起来* 函数实现:根据传入的结点,首先判断该链表头是否为空*              空则,头结点指向传入的节点,且把节点的ptNext域指向NULL*             不空则,尾插法插入链表*/
int RegisterInputOpr(PT_InputOpr ptInputOpr)
{PT_InputOpr ptTmp;if (!s_ptInputOprHead) {s_ptInputOprHead   = ptInputOpr;ptInputOpr->ptNext = NULL;} else {ptTmp = s_ptInputOprHead;while (ptTmp->ptNext){ptTmp = ptTmp->ptNext;}ptTmp->ptNext    = ptInputOpr;ptInputOpr->ptNext = NULL;}return 0;
}/* 显示支持拓展文件的名字 */
void ShowInputOpr(void)
{int i = 0;PT_InputOpr ptTmp = s_ptInputOprHead;while (ptTmp) {printf("%02d %s\n", i++, ptTmp->name);ptTmp = ptTmp->ptNext;}
}/* 初始化函数 */
int InputInit(void)
{int error;error = StdinInit();error |= TouchScreenInit();return error;
}/* 调用所有的Input设备的事件发生函数,即轮询的方式获取LCD或标准输入的数据 */
int GetInputEvent(PT_InputEvent ptInputEvent)
{/* 把链表中的InputOpr的GetInputEvent都调用一次,一旦有数据立即返回 */PT_InputOpr ptTmp;ptTmp = s_ptInputOprHead;while (ptTmp) {if (ptTmp->GetInputEvent(ptInputEvent) == 0)return 0;ptTmp = ptTmp->ptNext;}return -1;
}/* 初始化所有支持的Input设备 */
int AllInputDeviceInit()
{int error;PT_InputOpr ptTmp;error = -1;ptTmp = s_ptInputOprHead;while (ptTmp) {if (ptTmp->DeviceInit() == 0)error = 0;ptTmp = ptTmp->ptNext;}return 0;
}

3、input设备——stdin

在这个函数中,为stdin设备进行:分配结构体、设置结构体、注册结构体

/*** @file  stdin.c* @brief 标准输入input设备的处初始化,处理过程与取消* @version 1.0 (版本声明)* @author Dk* @date  July 1,2020*/
#include <termios.h>
#include <unistd.h>
#include <stdio.h>#include "input_manager.h"/*** @Description: 获取标准串口输入的初始化,设置模式使其可以采用非阻塞的方式获取输入* @return 成功:0*/
static int StdinDevInit(void)
{struct termios ttystate;/* 获得终端的状态 */tcgetattr(STDIN_FILENO, &ttystate);/* 关闭标准模式,并设置位为  1,表示接受最小用户数输入为1 */ttystate.c_lflag &= ~ICANON; ttystate.c_cc[VMIN] = 1;      /* 设置术语状态 */tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);return 0;
}/*** @Description: 获取标准串口输入的退出,恢复原本的模式* @return 成功:0*/
static int StdinDevExit(void)
{struct termios ttystate;/* 获得终端的状态 */tcgetattr(STDIN_FILENO, &ttystate);/* 打开标准模式 */ttystate.c_lflag |= ICANON;/* 设置术语状态 */tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);return 0;
}/*** @Description: 根据标准输入的结果进行相应处理,采用非阻塞的方式获取输入* @param ptInputEvent - 表示input设备的结构体.* @return 描述符fd在描述符集fds中:0 不在:-1*/
static int StdinGetInputEvent(PT_InputEvent ptInputEvent)
{struct timeval tv;fd_set fds;char c;/* 输入(stdin)执行无阻塞检查,而不会将超时0 */tv.tv_sec = 0;tv.tv_usec = 0;/* 指定的文件描述符集清空 */FD_ZERO(&fds);/* 在文件描述符集合中增加一个新的fds */FD_SET(STDIN_FILENO, &fds);/* 测试指定的fds可读 */select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);/* 测试指定的fds是否在该集合中 */if (FD_ISSET(STDIN_FILENO, &fds)) {/* 存在,处理数据 */ptInputEvent->type = INPUT_TYPE_STDIN;c = fgetc(stdin);if (c == 'u') {ptInputEvent->val = INPUT_VALUE_UP;gettimeofday(&ptInputEvent->time, NULL);} else if (c == 'n') {ptInputEvent->val = INPUT_VALUE_DOWN;      gettimeofday(&ptInputEvent->time, NULL);} else if (c == 'q') {ptInputEvent->val = INPUT_VALUE_EXIT;gettimeofday(&ptInputEvent->time, NULL);} else {ptInputEvent->val = INPUT_VALUE_UNKONW;gettimeofday(&ptInputEvent->time, NULL);}return 0;}elsereturn -1;
}static T_InputOpr s_tStdinOpr = {.name             = "stdin",.DeviceInit   = StdinDevInit,.DeviceExit    = StdinDevExit,.GetInputEvent  = StdinGetInputEvent,
};/*** @Description: 标准输入初始化函数,供上层调用注册设备* @return 成功:0*/
int StdinInit(void)
{return RegisterInputOpr(&s_tStdinOpr);
}

4、input设备——touchscreen

在这个函数中,为touchscreen设备进行:分配结构体、设置结构体、注册结构体

/*** @file  touchscreen.c* @brief touchscreen input设备的处初始化,处理过程与取消,参考tslib中的ts_print.c* @version 1.0 (版本声明)* @author Dk* @date  July 1,2020*/
#include <stdlib.h>
#include <tslib.h>#include "input_manager.h"
#include "config.h"
#include "draw.h"static struct tsdev *s_pTSDev;   //touchscreen设备
static int s_Xres; //LCD x方向的分辨率
static int s_Xres; //LCD y方向的分辨率/*** @Description: 获取touchscreen输入的初始化,设置模式使其可以采用非阻塞的方式获取输入* @return 成功:0 失败: -1* @note 由于需要获取到LCD的分辨率,所以这个函数被调用之前,SelectAndInitDisplay必须被调用,才可以获取到数据*/
static int TouchScreenDevInit(void)
{char *pTSName = NULL; /* 根据环境变量获得设备名,并以非阻塞的方式打开 */if((pTSName = getenv("TSLIB_TSDEVICE")) != NULL) s_pTSDev = ts_open(pTSName, 1);elses_pTSDev = ts_open("/dev/event0", 1);if (!s_pTSDev) {DBG_PRINTF("ts_open error!\n");return -1;}if (ts_config(s_pTSDev)) {DBG_PRINTF("ts_config error!\n");return -1;}/* 获取LCD分辨率 */if (GetDispResolution(&s_Xres, &s_Xres))return -1;return 0;
}/*** @Description: touchscreen输入的退出,恢复原本的模式* @return 成功:0*/
static int TouchScreenDevExit(void)
{return 0;
}/*** @Description: 判断上一次事件与此次事件相隔的时间是否超过500ms* @param ppreTime - 存储上一次事件时间的结构体指针,pcurTime - 此次存储事件时间的结构体指针 * @return 两次事件时间间隔超过500ms:0 无超过:1*/
static int isOutOf500ms(struct timeval *ppreTime, struct timeval *pcurTime)
{int prems;int curms;/* tv_sec - 秒, tv_usec - 微秒 */prems = ppreTime->tv_sec * 1000 + ppreTime->tv_usec / 1000;curms = pcurTime->tv_sec * 1000 + pcurTime->tv_usec / 1000;return (curms > (prems + 500));
}/*** @Description: 采用查询的方式获读取touchscreen数据* @param ptInputEvent - 表示input设备的结构体.* @return 有数据:0 无数据:-1*/
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)
{int ret;struct ts_sample samp;static struct timeval preTime;ret = ts_read(s_pTSDev, &samp, 1);/* 无数据返回 */if (ret < 0) {DBG_PRINTF("ts_read no data!\n");return -1;}/* 有数据处理 */if ((isOutOf500ms(&preTime, &samp.tv))) {/* 两次事件时间间隔超过500ms */ptInputEvent->type = INPUT_TYPE_TOUCHSCREEN;preTime = samp.tv;ptInputEvent->time = samp.tv;/* 根据读取到的LCD y坐标值,进行对应操作* y < y分辨率的1/3,则为上翻* y > y分辨率的2/3,则为下翻* 其他情况,则为未定义操作*/if (samp.y < (s_Xres / 3))ptInputEvent->val = INPUT_VALUE_UP;else if (samp.y > (2 * s_Xres / 3))ptInputEvent->val = INPUT_VALUE_DOWN;elseptInputEvent->val = INPUT_VALUE_UNKONW;return 0;} elsereturn -1;return 0;
}static T_InputOpr s_tTouchScreenOpr = {.name           = "touchscreen",.DeviceInit     = TouchScreenDevInit,.DeviceExit  = TouchScreenDevExit,.GetInputEvent  = TouchScreenGetInputEvent,
};/*** @Description: touchscreen input设备初始化函数,供上层调用注册设备* @return 成功:0*/
int TouchScreenInit(void)
{return RegisterInputOpr(&s_tTouchScreenOpr);
}

四、修改

1、main.c文件修改

1.1 显示支持信息部分

  • 修改前:

```c/* 显示当前支持信息 */if (List){printf("supported display:\n");ShowDispOpr();printf("supported font:\n");ShowFontOpr();printf("supported encoding:\n");ShowEncodingOpr();return 0;}
  • 修改后:
    /* 显示当前支持信息 */if (List){printf("supported display:\n");ShowDispOpr();printf("supported font:\n");ShowFontOpr();printf("supported encoding:\n");ShowEncodingOpr();printf("supported input:\n");ShowInputOpr();return 0;}

1.2 循环部分

  • 修改前:只支持串口标准输入控制
/* 循环根据输入信息进行对应操作* n:  显示下一页信息* u:  显示上一页信息* q:  退出程序*/while (1){printf("Enter 'n' to show next page, 'u' to show previous page, 'q' to exit: ");do {Opr = getchar();            } while ((Opr != 'n') && (Opr != 'u') && (Opr != 'q'));if (Opr == 'n')ShowNextPage();else if (Opr == 'u')ShowPrePage();           else return 0;       }
  • 修改后:通过轮询的方式,调用GetInputEvent(&InputEvent)不断的判断串口和LCD是否有输入根据输入的标志位来进行相关操作
    /* 循环根据输入信息进行对应操作* n:  显示下一页信息* u:  显示上一页信息* q:  退出程序*/printf("Enter 'n' to show next page, 'u' to show previous page, 'q' to exit\n\r");printf("Touch the upper third of the touch screen to show previous page\n\r");printf("Touch the bottom third of the touch screen to show next page\n\r");while (1){if (GetInputEvent(&InputEvent) == 0) {if (InputEvent.val == INPUT_VALUE_DOWN)ShowNextPage();else if (InputEvent.val == INPUT_VALUE_UP)ShowPrePage();         else if (InputEvent.val == INPUT_VALUE_EXIT) {printf("\n\r");return 0;}}}

2、draw.c文件修改

2.1 初始化部分修改

  • 修改前:
int DrawInit(void)
{int error;/* 初始化 */error = DisplayInit();if (error) {printf("DisplayInit error!\n");return -1;}error = FontsInit();if (error) {printf("FontsInit error!\n");return -1;}error = EncodingInit();if (error) {printf("EncodingInit error!\n");return -1;}return 0;
}
  • 修改后:添加了input部分的初始化
int DrawInit(void)
{int error;/* 初始化 */error = DisplayInit();if (error) {printf("DisplayInit error!\n");return -1;}error = FontsInit();if (error) {printf("FontsInit error!\n");return -1;}error = EncodingInit();if (error) {printf("EncodingInit error!\n");return -1;}error = InputInit();if (error) {printf("InputInit error!\n");return -1;}return 0;
}

3、Makefile修改

3.1 /input目录下Makefile

# 子目录Makefileobj-y += input_manager.o
obj-y += stdin.o
obj-y += touchscreen.o

3.2 顶层目录Makefile

  • 添加库:
LDFLAGS := -lm -lfreetype -lts
  • 添加input目录:
obj-y += input/
  • 完整文件:
# 顶层目录Makefile
#
# 目的:
#   1、每个子目录都会建立一个Makefile,包含当前目录下.c文件.h文件
#   2、顶层目录下# 交叉编译工具链
CROSS_COMPILE = arm-linux-# 定义一些变量 $(CROSS_COMPILE):取出该变量的值 $(CROSS_COMPILE)gcc->arm-linux-gcc
AS      = $(CROSS_COMPILE)as
LD      = $(CROSS_COMPILE)ld
CC      = $(CROSS_COMPILE)gcc
CPP     = $(CC) -E
AR      = $(CROSS_COMPILE)ar
NM      = $(CROSS_COMPILE)nmSTRIP     = $(CROSS_COMPILE)strip
OBJCOPY     = $(CROSS_COMPILE)objcopy
OBJDUMP     = $(CROSS_COMPILE)objdump# 取出变量的值
export  AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP# :=         简单扩展型变量的值是一次扫描永远使用
# CFLAGS 方便您利用隐含规则指定编译C语言源程序的旗标
# -Wall     帮助列出所有警告信息
# -02     多优化一些,除了涉及空间和速度交换的优化选项,执行几乎所有的优化工作
# -g        可以认为它是缺省推荐的选项
CFLAGS := -Wall -O2 -g# 把当前目录下的include目录下指定为系统目录
# +=        为已经定以过的变量的值追加更多的文本
# -I        指定搜寻包含makefile文件的路径
# $(shell pwd)  执行shell命令的pwd命令,获取执行命令的结果
CFLAGS += -I $(shell pwd)/include# LDFLAGS 用于调用linker(‘ld’)的编译器的额外标志
# -l        连接库的搜寻目录 -lm调用math库 -lfreetype调用freetype库
LDFLAGS := -lm -lfreetype -lts# 取出变量的值
export  CFLAGS LDFLAGSTOPDIR := $(shell pwd)
export TOPDIR# TARGET    目标变量
# :=         简单扩展型变量的值是一次扫描永远使使用
TARGET := show_fileobj-y += main.o
obj-y += display/
obj-y += draw/
obj-y += encoding/
obj-y += fonts/
obj-y += input/# 规则     arm-linux-gcc -lm -lfreetype -o show_file built-in.o
all : make -C ./ -f $(TOPDIR)/Makefile.build$(CC) $(LDFLAGS) -o $(TARGET) built-in.o# clean  删除所有make正常创建的文件
# 规则        找到所有make创建出来.o文件进行删除
#           删除show_file
clean :rm -f $(shell find -name "*.o")rm -f $(TARGET)# distclean 删除所有正常创建的文件
#           配置文件或为编译正常创建的准备文件,甚至makefile文件自身不能创建的文件
# 规则        找到所有mkae创建出来的.o文件进行删除
#           删除show_file
distclean:rm -f $(shell find -name "*.o")rm -f $(shell find -name "*.d")rm -f $(TARGET)

五、编译与运行

1、编译

执行make,得到可执行文件show_file

2、运行

由于使用到触摸屏,需要调用tslib库来进行校准

  • 执行./show_file -l,显示出当前支持的设备
  • 执行./shoe_file -s 16 -h HZK16 -f ./MSYH.TTF hz.txt
    通过串口输入,可以立刻根据输入的值进行操作,不需要回车键后才进行操作;
    通过触摸屏输入点击屏幕的上1/3部分进行上页显示点击屏幕的下1/3部分进行下页显示

第三阶段应用层——1.7 数码相册—电子书(3)—轮询方式支持多输入相关推荐

  1. 第三阶段应用层——2.6 视频监控—CMOS摄像头的硬件原理

    视频监控-CMOS摄像头的硬件原理 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.0 ...

  2. 第三阶段应用层——2.7 视频监控—从零写CMOS摄像头驱动

    视频监控-从零写CMOS摄像头驱动 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3),OV7740摄像头 软件平台:运行于VMware Workstation 12 Player下Ubu ...

  3. 第三阶段应用层——2.4 视频监控—从0写USB摄像头驱动(1)-描述符的分析与打印

    视频监控-从0写USB摄像头驱动(1)-描述符的分析与打印 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下U ...

  4. Linux运维 第三阶段 (一) 网络配置及openssl加密

    Linux运维 第三阶段 (一) 网络配置及openssl加密 主机接入网络:IP,netmask,gateway,hostname,DNS1,DNS2,DNS3,route,dhcp(dynamic ...

  5. mysql三阶段提交实现_基于两阶段提交的分布式事务实现(UP-2PC)

    引言:分布式事务是分布式数据库的基础性功能,在2017年上海MySQL嘉年华(IMG)和中国数据库大会(DTCC2018)中作者都对银联UPSQL Proxy的分布式事务做了简要介绍,受限于交流形式难 ...

  6. 中国石油大学(北京)-《计算机网络应用基础》第三阶段在线作业

    第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) 以下关于VPN说法正确的是 A.VPN指的是用户自己租用线路,和公共网络物理上完全隔离的.安全的线路 B.VPN指的是用户通过公用网络 ...

  7. 中国石油大学《计算机应用基础#》第三阶段在线作业

    第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) PowerPoint演示文稿的作者必须非常注意幻灯片集的两个要素是(). A.内容和设计 B.内容和模板 C.内容和视觉效果 D.问题 ...

  8. java 高并发第三阶段实战_JAVA多线程编程实战视频-第三阶段(共80节)

    高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解 高并发编程第三阶段02讲 AtomicInteger API详解,以及CAS算法详细介绍 高并发编程第三阶段03讲 利用CAS构造 ...

  9. 自学it18大数据笔记-第三阶段Spark-day04——会持续更新……

    笔记为自学时随手记录,如有错误,欢迎指正,不胜感激!现已广州转移至上海,欢迎小伙伴们加qq或微博沟通交流(QQ,微博和博客同名) 笔记分享:自学it18大数据笔记-第三阶段Spark-day04--会 ...

  10. 5G全球声量升级:Verizon宣布固定+移动齐步走,中国第三阶段试验倒计时

    就在CES2018国际消费类电子产品展和2018世界移动大会即将召开的时候,5G的信号在全球范围也来了一次集体释放. 1月2日,工业和信息化部召开评审会,为有效指导5G第三阶段试验做准备.同一天,韩国 ...

最新文章

  1. 通过sessionid获取session php,php如何返回sessionID和如何通过sessionID获取相关的session...
  2. 一个演示A星相关的寻路的网站
  3. 近几年,关于基于Imagenet数据集图像分类的模型总结
  4. VTK:IO之GenericDataObjectReader
  5. yum 升级curl_CentOS 6/7 更新curl
  6. 《从缺陷中学习C/C++》——6.3 数组传参时的sizeof
  7. MySQL 四种事务隔离级的说明
  8. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_22-CMS前端页面查询开发-Api调用-跨域解决...
  9. nginx 多php项目配置文件,nginx,_nginx配置多目录访问,nginx - phpStudy
  10. 2021Eclipse最新下载与安装教程
  11. android 距离感应器控制屏幕熄灭_华为nova3e、小米6X、OPPOA7x对比,选IPS屏幕还是TFT屏幕,自选...
  12. UWB超宽带 DW1000 通道和带宽
  13. 我的游戏学习日志10——数字游戏策划(5)游戏策划的概念与分工
  14. 思维导图超级学习力提升宝典
  15. BUUCTF·[WUSTCTF2020]大数计算·WP
  16. noip模拟题11.5
  17. java 24字母_java 时间格式化中的模式字母
  18. 【原创达人】ZUK HD-1 双发声单元圈铁耳机
  19. 流氓软件卸载了又偷偷冒出来,dllhost.exe暗藏安装玄机
  20. project 2003

热门文章

  1. javaScript学习笔记【尚硅谷】
  2. APM编译example
  3. 给定一个无重复元素的数组 candidates 和一个目标数 target .
  4. Playwright-python 教程
  5. 用计算机画图教案评价,电脑画图教案
  6. 漫谈Anchor-based和Anchor-Free
  7. AXI协议(5):AXI协议的burst机制
  8. 女版乔布斯的覆灭,这是今年我听过最唏嘘的真人故事
  9. 天才小毒妃 第945章 龙非夜心情很不好
  10. Python:实现monte carlo蒙特卡罗算法(附完整源码)