简介

前面绘制的鼠标在移动时会擦除已有的图像,实现图像的重叠效果需要对图像分层。 图像叠加处理的原理很简单,就是给图像分层,从低下往上面画,便可以实现叠加的效果。 计算机桌面上有三个窗口程序,A、B、C。B位于A之上,C位于B之上。要实现这种效果,只需要先画A(盖住了桌面一部分)、再画B(盖住了A和桌面一部分)、再画C(盖住了B和桌面一部分)。

目标

新建图层窗口管理器:
win_sheet.h:

#ifndef WIN_SHEET_H
#define WIN_SHEET_H#include "memman.h"//图层的数据结构
typedef struct _SHEET {unsigned char *buf;int width, height, x, y, col_inv, weight, flags;
}SHEET;
/*
buf用来记录图层上所描画内容的地址。图层的整体大小:width、height。图层在画面上位置的坐标:x、y。col_inv为透明色色号。weight 为图层显示层级权重flags用于存放有关图层的各种设定信息。(使用状况)
*/#define MAX_SHEETS  256
typedef struct _SHTCTL {unsigned char *vram;int xsize, ysize, top;SHEET *sheets[MAX_SHEETS];SHEET sheets0[MAX_SHEETS];
}SHTCTL;#define SIZE_OF_SHEET  32
#define SIZE_OF_SHTCTL 9232SHTCTL *shtctl_init(MEMMAN *memman, unsigned char *vram,int xsize, int ysize);SHEET *sheet_alloc(SHTCTL *ctl);void sheet_free(SHTCTL *ctl,SHEET *sht);void sheet_setRect(int x,int y,int width,int height,int col_inv,SHEET *sht, unsigned char *buf);void sheet_setWeight(SHTCTL *ctl,SHEET *sht, int weight);int sheet_refresh(SHTCTL *ctl);void sheet_slide(SHTCTL *ctl,SHEET *sht, int vx0, int vy0);#endif

win_sheet.c:

#include "win_sheet.h"#define SHEET_FREE 0
#define SHEET_USE  1SHTCTL *shtctl_init(MEMMAN *memman, unsigned char *vram,int xsize, int ysize){SHTCTL *ctl = (SHTCTL *)mem_alloc(memman, SIZE_OF_SHTCTL);if (ctl == 0) {return 0;}ctl->vram = vram;ctl->xsize = xsize;ctl->ysize = ysize;ctl->top = -1;for (int i = 0; i < MAX_SHEETS; i++) {ctl->sheets0[i].flags = SHEET_FREE;}return ctl;
}SHEET *sheet_alloc(SHTCTL *ctl){SHEET *sht;for (int i = 0; i < MAX_SHEETS; i++) {if (ctl->sheets0[i].flags == 0) {sht = &ctl->sheets0[i];ctl->sheets[i] = sht;sht->flags = SHEET_USE;//标记为正在使用sht->weight = -1;     //隐藏return sht;}}return 0;
}void sheet_free(SHTCTL *ctl,SHEET *sht){sheet_setWeight(ctl,sht,-1);   sht->weight = -1;sht->flags = SHEET_FREE;
}void sheet_setRect(int x,int y,int width,int height,int col_inv,SHEET *sht, unsigned char *buf){sht->x = x;sht->y = y;sht->width = width;sht->height = height;sht->buf = buf;sht->col_inv = col_inv;
}void sheet_setWeight(SHTCTL *ctl,SHEET *sht, int weight){//存储设置前的窗口权重信息int old = sht->weight;//进行修正if (weight > ctl->top + 1) {weight = ctl->top + 1;}if (weight < -1) {weight = -1;}sht->weight = weight;int h;if (old > weight) {//窗口往管理器数组前面移动if (weight >= 0) {//还需要显示,只是显示在相对底层for (h = old; h > weight; h--) {//weight之后old之间的数据往数组后面搬移ctl->sheets[h] = ctl->sheets[h-1];ctl->sheets[h]->weight = h;}ctl->sheets[weight] = sht;} else {//不需要显示了if (ctl->top > old) {for (h = old; h < ctl->top; h++) {//old 位置被old后面的数据覆盖ctl->sheets[h] = ctl->sheets[h+1];ctl->sheets[h]->weight = h;}}ctl->top--;}} else if (old < weight) {//窗口向管理器数组后面移动if (old >= 0) {//该窗口原来也是显示的for (h = old; h < weight; h++) {ctl->sheets[h] = ctl->sheets[h + 1];ctl->sheets[h]->weight = h;}ctl->sheets[weight] = sht;} else {//需要新增一个显示窗口if(ctl->top>=0){//窗口管理器中有数据for (h = ctl->top; h >= weight; h--) {//weight索引位置后的数据往后移动ctl->sheets[h + 1] = ctl->sheets[h];ctl->sheets[h + 1]->weight = h + 1;}}ctl->sheets[weight] = sht;ctl->top++;}}sheet_refresh(ctl);
}int sheet_refresh(SHTCTL *ctl){unsigned char *vram = ctl->vram;for (int h = 0; h <= ctl->top; h++) {SHEET *sht = ctl->sheets[h];unsigned char *buf = sht->buf;for (int by = 0; by < sht->height; by++) {int vy = sht->y + by;for (int bx = 0; bx < sht->width; bx++) {int vx = sht->x + bx;unsigned char c = buf[by * sht->width + bx];if (c != sht->col_inv) {vram[vy * ctl->xsize + vx] = c;}}}}return 0;
}void sheet_slide(SHTCTL *ctl,SHEET *sht, int vx0, int vy0){sht->x = vx0;sht->y = vy0;if (sht->weight >= 0) {sheet_refresh(ctl);}
}

2.整理内存管理模块,主要在上节的基础上修改函数名以更能体现对内存的操作。
memman.h:

//内存管理模块#ifndef MEMMAN_H
#define MEMMAN_H#define  MEMMAN_FREES  4096typedef struct _FREEINFO {unsigned int *addr, size;
}FREEINFO;//该结构体空间大小大致为32K
typedef struct _MEMMAN {//frees 表示空闲内存块的数量//lostsize 表示丢弃的内存大小//losts 表示丢弃的内存次数int frees, maxfrees, lostsize, losts;FREEINFO free[MEMMAN_FREES];
}MEMMAN;//初始化内存管理器
//man   内存管理器
//addr  内存管理器管理的内存块基址
//size  内存管理器管理的内存块长度字节
void memman_init(MEMMAN *man,void *addr,int size);//获取可用总内存大小
int mem_total(MEMMAN *man);//内存分配,为了减小内存碎片分配的大小为4k的倍数
void* mem_alloc(MEMMAN *man,int size);//内存释放
void mem_free(MEMMAN *man,void *addr,int size);//给制定内存设置值
//mem   内存基址
//val   设置的值
//size  设置的长度(字节)
void mem_set(char *mem,char val,int size);#endif

memman.c:

#include"memman.h"void memman_init(MEMMAN *man,void *addr,int size){man->frees = 0;man->maxfrees = 0;man->lostsize = 0;man->losts = 0;man->free[0].addr = addr;man->free[0].size = size;if(size>0){man->frees = 1;}
}int mem_total(MEMMAN *man){unsigned int t = 0;for (int i = 0; i < man->frees; i++) {t += man->free[i].size;}return t;
}void* mem_alloc(MEMMAN *man,int size){size = (size + 0xfff) & 0xfffff000;void *addr = (void *)0;for (int i = 0; i < man->frees; i++) {if (man->free[i].size >= size) {addr = man->free[i].addr;man->free[i].size -= size;man->free[i].addr = (unsigned int *)(((char *)(man->free[i].addr))+size);if (man->free[i].size == 0) {//在索引i 后的内存记录块往前搬移for(int j=i+1;j<man->frees;j++){man->free[j-1] = man->free[j]; }man->frees--;}return addr;}}return (unsigned int*)0;
}void mem_free(MEMMAN *man,void *addr,int size){unsigned int *offAddr = (unsigned int*)((char *)addr+size);for(int i=0;i<man->frees;i++){if((char *)(man->free[i].addr)+man->free[i].size == (char *)addr){//作为高地址合并man->free[i].size += size;return;}else if(man->free[i].addr == offAddr){//作为低地址合并man->free[i].addr = addr;man->free[i].size += size;return;}}//作为新增块man->free[man->frees].addr = addr;man->free[man->frees].size = size;man->frees++;}void mem_set(char *mem,char val,int size){for(int i=0;i<size;i++){mem[i] = val;}
}

3.调整os.c 文件,最大的变化就是图形显示部分,以前直接向显存中写入信息,但是使用图形分层实现图像叠加效果,需要先把信息写入缓存、再渲染时在将信息按显示层级依次写入显存。
申明窗口管理器和桌面背景图层

//窗口管理器
static SHTCTL *_shtctl;
//背景窗口
static SHEET *_shtback;

申明鼠标图层

//鼠标窗口
static SHEET *_shtMouse;
//鼠标光标窗口缓存
static unsigned char _shtCursorBuf[16*16];

申明字符显示图层

//字符显示窗口
static SHEET *_shtChar;
static unsigned char *_shtCharBuf;

修改 showMemInfo函数,在点击回车键后显示内存分块信息

void showMemInfo(AddrRangeDes *memDes,int page){mem_set((char *)_shtCharBuf+(320*40),COLOR_INVISIBLE,320*(200-40));//一行显示32个字符_charCount = 64;//如果换成static char *msg 时objconv 反汇编后nasm 编译时会出错,//建议使用数组的方式定义static char msg[] = "page:";char *txt = msg;int len = 0;for(int i=0;txt[i] != 0;i++){_tempArr[i] = txt[i];len++;}short temp = char2HexStr(page);_tempArr[len] = '0';_tempArr[len+1] = 'x';_tempArr[len+2] = ((char *)&temp)[0];_tempArr[len+3] = ((char *)&temp)[1];showString(_tempArr,len+4,true,_shtCharBuf);_charCount = 64+32;static char add[] = "addr:";txt = add;len = 0;for(int i=0;txt[i] != 0;i++){_tempArr[i] = txt[i];len++;}_tempArr[len] = '0';_tempArr[len+1] = 'x';len += 2;for(int i=0;i<2;i++){int data = ((int *)memDes)[1-i];for(int j=0;j<4;j++){temp = char2HexStr(((char *)&data)[3-j]);_tempArr[len] = ((char *)&temp)[0];_tempArr[len+1] = ((char *)&temp)[1];len += 2;}}showString(_tempArr,len,true,_shtCharBuf);_charCount = 64+32+32;static char lenMsg[] = "length:";txt = lenMsg;len = 0;for(int i=0;txt[i] != 0;i++){_tempArr[i] = txt[i];len++;}_tempArr[len] = '0';_tempArr[len+1] = 'x';len += 2;for(int i=0;i<2;i++){int data = ((int *)memDes)[3-i];for(int j=0;j<4;j++){temp = char2HexStr(((char *)&data)[3-j]);_tempArr[len] = ((char *)&temp)[0];_tempArr[len+1] = ((char *)&temp)[1];len += 2;}}showString(_tempArr,len,true,_shtCharBuf);_charCount = 64+32+32+32;static char typeMsg[] = "type:";txt = typeMsg;len = 0;for(int i=0;txt[i] != 0;i++){_tempArr[i] = txt[i];len++;}_tempArr[len] = '0';_tempArr[len+1] = 'x';len += 2;int data = (memDes->type);for(int j=0;j<4;j++){temp = char2HexStr(((char *)&data)[3-j]);_tempArr[len] = ((char *)&temp)[0];_tempArr[len+1] = ((char *)&temp)[1];len += 2;}showString(_tempArr,len,true,_shtCharBuf);sheet_refresh(_shtctl);
}

修改init_main函数

//操作系统C语言入口函数--可以指定为其他
void init_main() {_vram.addr = (unsigned char *)0xa0000;_vram.screenW = 320;_vram.screenH = 200;io_sti();initPallet();fifo8_init(&_keybufInfo,32,_keybuf);fifo8_init(&_mousebufInfo,128,_mousebuf);init_mouse_int();//解析最大可用内存区域AddrRangeDes *memDes = (AddrRangeDes *)mem_block_buf();int maxLen=0;char *effAddr = (char *)0;for(int i=0;i<mem_block_count();i++){int addr = memDes[i].addrLow;int len = memDes[i].lenLow;int type = memDes[i].type;if(type==1 && len>maxLen){maxLen = len;effAddr = (char *)addr;}}//初始化内存管理器_memman = (MEMMAN *)effAddr;memman_init(_memman,(void*)(effAddr+sizeof(MEMMAN)),maxLen-sizeof(MEMMAN));//背景窗口_shtctl = shtctl_init(_memman,_vram.addr,_vram.screenW,_vram.screenH);_shtback = sheet_alloc(_shtctl);_shtbackBuf = (unsigned char *)mem_alloc(_memman,_vram.screenW*_vram.screenH);drawBackground();sheet_setRect(0,0,_vram.screenW,_vram.screenH,COLOR_INVISIBLE,_shtback,_shtbackBuf);sheet_setWeight(_shtctl,_shtback,0);//鼠标窗口_shtMouse = sheet_alloc(_shtctl);_mouseDes.x = (320-16)/2;_mouseDes.y = (200-16)/2;_mouseDes.phase = 0;drawMouseCursor(_shtCursorBuf,_mouseDes.x,_mouseDes.y,COLOR_INVISIBLE,16);sheet_setRect(_mouseDes.x,_mouseDes.y,16,16,COLOR_INVISIBLE,_shtMouse,_shtCursorBuf);sheet_setWeight(_shtctl,_shtMouse,1);//字符显示窗口_shtChar = sheet_alloc(_shtctl);_shtCharBuf = (unsigned char *)mem_alloc(_memman,_vram.screenW*_vram.screenH);mem_set((char *)_shtCharBuf,COLOR_INVISIBLE,320*200);sheet_setRect(0,0,_vram.screenW,_vram.screenH,COLOR_INVISIBLE,_shtChar,_shtCharBuf);sheet_setWeight(_shtctl,_shtChar,1);_tempArr[0] = '0';_tempArr[1] = 'x';short temp = 0;for(int j=0;j<4;j++){temp = char2HexStr(((char *)&effAddr)[3-j]);_tempArr[2+2*j] = ((char *)&temp)[0];_tempArr[3+2*j] = ((char *)&temp)[1];}showString(_tempArr,10,true,_shtCharBuf);_charCount += 1;for(int j=0;j<4;j++){temp = char2HexStr(((char *)&maxLen)[3-j]);_tempArr[2+2*j] = ((char *)&temp)[0];_tempArr[3+2*j] = ((char *)&temp)[1];}showString(_tempArr,10,true,_shtCharBuf);_charCount = 32;int memCount = mem_block_count();temp = char2HexStr(memCount);_tempArr[2] = ((char *)&temp)[0];_tempArr[3] = ((char *)&temp)[1];showString(_tempArr,4,true,_shtCharBuf);int memToal = mem_total(_memman);for(int j=0;j<4;j++){temp = char2HexStr(((char *)&memToal)[3-j]);_tempArr[2+2*j] = ((char *)&temp)[0];_tempArr[3+2*j] = ((char *)&temp)[1];}_charCount += 10;showString(_tempArr,10,true,_shtCharBuf);sheet_refresh(_shtctl);int memId = -1;for(; ;){if(_keybufInfo.len>0){io_cli();int len = _keybufInfo.len;for(int t=0;t<len;t++){char data = fifo8_get(&_keybufInfo);if(data == 0x1c){memId++;if(memId==memCount){memId=0;}showMemInfo(memDes+memId,memId);}}io_sti();}else if(_mousebufInfo.len>0){io_cli();int len = _mousebufInfo.len;for(int t=0;t<len;t++){mouseCursorMoved(&_mouseDes,COLOR_INVISIBLE);}io_sti();}else{io_hlt();}}}

调整fillRect 函数向指定的内存地址写入矩形信息,winW 表示y+1 与 y 之间相差的像素字节宽度。

void fillRect(int x,int y,int width,int height,char col,unsigned char *buf,int winW){for(int i=y;i<=y+height;i++){for(int j=x;j<=x+width;j++){buf[i*winW+j] = col;}}
}

调整drawBackground 函数

void drawBackground(){fillRect(0,0,_vram.screenW-1,_vram.screenH-29, COL8_008484,_shtbackBuf,_vram.screenW);fillRect(0,_vram.screenH-28,_vram.screenW-1,28, COL8_848484,_shtbackBuf,_vram.screenW);fillRect(0,_vram.screenH-27,_vram.screenW,1, COL8_848484,_shtbackBuf,_vram.screenW);fillRect(0,_vram.screenH-26,_vram.screenW,25, COL8_C6C6C6,_shtbackBuf,_vram.screenW);fillRect(3,_vram.screenH-24,56,1, COL8_FFFFFF,_shtbackBuf,_vram.screenW);fillRect(2,_vram.screenH-24,1,20, COL8_FFFFFF,_shtbackBuf,_vram.screenW);fillRect(3,_vram.screenH-4,56,1, COL8_848484,_shtbackBuf,_vram.screenW);fillRect(59,_vram.screenH-23,1,19, COL8_848484,_shtbackBuf,_vram.screenW);fillRect(2,_vram.screenH-3,57,0, COL8_000000,_shtbackBuf,_vram.screenW);fillRect(60,_vram.screenH-24,0,19, COL8_000000,_shtbackBuf,_vram.screenW);fillRect(_vram.screenW-47,_vram.screenH-24,43,1, COL8_848484,_shtbackBuf,_vram.screenW);fillRect(_vram.screenW-47,_vram.screenH-23,0,19, COL8_848484,_shtbackBuf,_vram.screenW);fillRect(_vram.screenW-47,_vram.screenH-3,43,0, COL8_FFFFFF,_shtbackBuf,_vram.screenW);fillRect(_vram.screenW-3,_vram.screenH-24,0,21, COL8_FFFFFF,_shtbackBuf,_vram.screenW); }

修改drawMouseCursor函数绘制鼠标图形信息到缓存区

void drawMouseCursor(unsigned char *vram,int x,int y,char bc,int winW){//16*16 Mouse //鼠标指针点阵static char cursor[16][16] = {"*...............","**..............","*O*.............","*OO*............","*OOO*...........","*OOOO*..........","*OOOOO*.........","*OOOOOO*........","*OOOOOOO*.......","*OOOO*****......","*OO*O*..........","*O*.*O*.........","**..*O*.........","*....*O*........",".....*O*........","......*........."};for (int i = 0; i < 16; i++) {for (int j = 0; j < 16; j++) {int off = i*winW+j;if (cursor[i][j] == '*') {vram[off] = COL8_000000;}if (cursor[i][j] == 'O') {vram[off] = COL8_FFFFFF;}if (cursor[i][j] == '.') {vram[off] = bc;}}}}

修改鼠标移动处理函数

//鼠标移动处理
void mouseCursorMoved(MouseDes *mdec,char bc){unsigned char val = fifo8_get(&_mousebufInfo);//表示处理到第3步,需要绘制鼠标光标if(mouse_decode(mdec,val) == 1) {mdec->x += mdec->offX;mdec->y += mdec->offY;if(mdec->x < 0){mdec->x = 0;}if(mdec->x > _vram.screenW-16/2){mdec->x = _vram.screenW-16/2;}if(mdec->y < 0 ){mdec->y = 0;}if(mdec->y > _vram.screenH - 16){mdec->y = _vram.screenH - 16;}sheet_slide(_shtctl,_shtMouse,mdec->x,mdec->y);}
}

修改字符显示函数

void showString(unsigned char *data,int len,char isAscii,unsigned char *buf){for(int i=0;i<len;i++){int ch = data[i];if(isAscii){int x = (_charCount)%32*10;int y = (_charCount)/32*20;putChar(buf,x,y,COL8_FFFFFF,_ascii+(ch-0x20)*16,_vram.screenW);_charCount++;}else{ch = char2HexStr(buf[i]);for(int j=0;j<2;j++){int x = (_charCount)%32*10;int y = (_charCount)/32*20;putChar(buf,x,y,COL8_FFFFFF,_ascii+(((unsigned char *)&ch)[j]-0x20)*16,_vram.screenW);_charCount++;}}}
}

4.编译生成floppy.img 虚拟软盘文件
以前在文件较少时直接在终端一个文件一个文件的编译生成。但是现在文件数量相对较多,输入的相关命令相对繁琐。为简化命令输入繁琐,引入Makefile文件。
新建Makefile文件

#    target : prerequests
#   [tab]   command
#   命令的前面一定要是tab键
os : os.c memman.c clang -c -m32 os.c  -o os.oclang -c -m32 memman.c -o memman.oclang -c -m32 win_sheet.c -o win_sheet.old -m elf_i386 -r os.o memman.o win_sheet.o -o os-mem.o./objconv -fnasm os-mem.o -o os.s kernel : kernel.s os.snasm kernel.s -o kernel.batfloppy : main.c floppy.cgcc main.c floppy.c -o mainclear : rm kernel.bat

target 需要实现的一个目标或标签
prerequests 实现该目标文件需要的依赖,多个依赖以空格分割
command 实现目标的命令,命令前面一定要是tab缩进
需要实现那个目标只需要在终端输入make xxx,例如得到os.s汇编文件make os,如果没有错误将会生成os.s文件。
有了os.s文件后按照以前的方式去除globall、extern、SECTION等声明,再编译得到kernel.bat文件,生成floppy.img 文件。

5.运行效果如下

第一行数字分别表示最大可用内存基址和内存字节数,第2行表示内存块的数量和内存分配后剩余可用内存字节数。

依次点击回车键后效果如下:
可见背景窗口图形并不会被鼠标光标擦除!

注意

1.我们发现和以前的内存显示不一样,以前的分块内存信息显示代码中存在bug,在本次中已经修复了。在开发系统的过程中我们会在实现一个功能时用也会用另一种方式对实现的功能进行验证,保证系统的健壮性。

2.系统在512M内存显示下,0x1fec4ff0换算成M 大约为510M可用内存。

19.分层实现窗口叠加相关推荐

  1. Qt视频播放窗口叠加透明窗口

    前言 本人在做一个视频监控项目时,遇到了透明窗口无法透明的问题,特记录下解决过程. 更新:经测试,本文提到的方法用于多分屏复杂的视频播放窗口时有问题. 目录 前言 一.需求 二.关键代码 2.1.透明 ...

  2. PyQt主窗体设置停靠窗口(QDockWidget)的叠加顺序

    PyQt提供了方便的停靠窗口控件,我们可以很方便的编写一个停靠窗口,代码和效果如下: # -*- coding: utf-8 -*- from PyQt4 import QtGui, QtCore c ...

  3. 华为新系统鸿蒙效果,19款华为手机内测新系统,流畅度比肩苹果iOS,优先体验鸿蒙OS...

    原标题:19款华为手机内测新系统,流畅度比肩苹果iOS,优先体验鸿蒙OS 在前不久举办的HDC 2020大会上,华为新系统EMUI 11终于发布,10款老机型率先开启EMUI 11 Beta版内测,更 ...

  4. vps如何linux内核4.19,Linux kernel 4.19 RC1 发布,一个相当大的版本

    原标题:Linux kernel 4.19 RC1 发布,一个相当大的版本 Linus Torvalds今天发布了第一个候选版本(RC),正式启动了即将推出的Linux 4.19内核系列的开发周期. ...

  5. selenium切换窗口

    在做网页自动化测试的时候,难免会打开很多个网页,那么,如何在多个窗口之间切换呢? 获取窗口的唯一标识用句柄(handle)表示,因此只需要切换句柄,就可以灵活的在各窗口之间切换. 下面介绍几个方法 c ...

  6. Windows核心编程_将窗口嵌入到桌面图标下面不被遮挡 spy 分析过程

    近年很流行动态视频桌面,实则上早期的windows vista系统上有一个Windows DreamScene软件将桌面壁纸设置成视频,但是是收费的! 首先先来观察一下Windows桌面的组成单元: ...

  7. flink 空闲窗口-withIdleness

    flink 空闲窗口 flink多并行时,如果有窗口中没数据,那么有数据的窗口即使watermark到达了触发边界,barren没对齐,窗口也不会触发计算.这样的空窗口即空闲窗口.可通过设置空闲时间( ...

  8. framebuffer之overview/双缓冲/alpha与colorkey/窗口平移与virtual screen平移

    本文介绍了s3c6410中的framebuffer,参考代码为Linux2.6.28.网上介绍framebuffer的文章很多,内核代码中也有关于framebuffer的文档,所以本文只介绍一些其它文 ...

  9. 多线程实现多个窗口卖票问题

    写在前面: 我是「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字.我热爱技术.热爱开源.热爱编程.技术是开源的.知识是共享的. 这博客是对自己学习的一点点总结及记录,如果您对 Java.算法 感兴 ...

最新文章

  1. Python-TXT文本操作
  2. 【原创】分享一些机器学习和深度学习的学习资料
  3. Django 框架14: 缓存
  4. oracle sql判断相等,Oracle PL/SQL判断两个字段相等或不等问题
  5. java成员变量的初始化_Java成员变量初始化过程
  6. python---字符串
  7. Java笔记-WEB算术验证码
  8. 网络模型 OSI七层协议和TCP/IP四层协议
  9. AndroidManifest中android:label与第三方库冲突问题
  10. Oracle开窗函数
  11. js室内地图开发_支付宝小程序室内地图导航开发-支付宝小程序JS加载esmap地图...
  12. 怎样免费下载知网、万方数据库等文献库的文献?
  13. Dart | 使用 Flutter 制作一个像 SIRI 那样的语音机器人
  14. 华为云3年仍未超阿里云,任正非感叹:积天下英雄,为何不得天下
  15. vue中下载图片到本地
  16. 2020CCPC绵阳站 Defuse the Bombs(简单二分)
  17. html播放mov格式视频,jQuery及video标签视频播放弹窗插件支持mp4,mov等格式详解(图文)...
  18. 微软正式宣布 Win10 死刑,Win11 LTSC要来了
  19. 代码走读测试案例分享
  20. Windows远程桌面跳板机无法复制粘贴

热门文章

  1. Docker安装docker-compose插件
  2. 360 FireLine Plugin 安装与使用说明
  3. 企业微信,如何转让创建人?
  4. 计算机网络知识——初级(更新中)
  5. 全国计算机vb考试编程,计算机等级考试VB编程8个优良习惯
  6. 基于Geoda的经典空间回归模型(OLS)、空间误差模型(SEM)和空间迟滞模型(SLM)
  7. ICC II 7 顶层设计的实现(Top level implementation)
  8. mysql添加列名在第一列_mysql在表的某一位置增加一列、删除一列、修改列名
  9. 从东莞扫黄看谷歌百度的搜索提示
  10. 想自学原画应该从何处着手?