翁恺老师的大作业二
做一个行编辑器
1.开始想用矩形框覆盖,后来想到用双向链表,鲁棒性超强。
2.用了两个registerevent,开始啥也不懂,查看类看了许久才找到mouseevent和charevent,使用方法类似。event是按下为0,抬起为1,charevent返回一个char,似乎不能返回上下左右,于是同时用了一个keyevent可以返回上下左右bakespace箭头。
3.用mousex,mousey表示鼠标位置,nx,ny表示当前字符的位置,利用它们的关系对链表进行插入删除添加等操作
4.自我感觉妙的是打印链表,为了实现换行后接着打印,设置了一个obs数组(obstacle),还有一个行数deep,obs[deep]记录当前行的位置,打印的时候根据obs来换行。
5.按回车以后打印链表,再按任意键退出程序。
6.当bug弄掉的时候,真的很开心
7.最后还是留下了bug 多个函数相乘是有错误的。。。
写了十几个小时,效率极低。。。
代码:
//大作业二 行编辑器
//2019.4.18 16:00--2019.4.19 1:30
//2019.4.19 9:30--11:00
//2019.4.19 18:00--20:00
//2019.4.20 16:00--17:00
//"↓"用作回车
//增加delete功能,删除光标后面的字
#include"acllib.h"
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
typedef struct node* ptr;
struct node
{
char c;
ptr next;
ptr prev;
};//双向链表
void keyEvent(int key, int event);/*用来对键盘事件进行处理,可以处理回车、上下左右、空格的输入*/
void charEvent(char c,int event);/*用来对输入的字符进行处理,可以处理大小写字母、数字、各种符号*/
void paintcaret(int x,int y);
void print();
//以上是函数声明
int nx=0,ny=0,deep=0;
const int dx=14,dy=25;
int N;
int obs[1000];
int mousex=0,mousey=0;
ptr L,p,q;
//以上是全局变量
int Setup()
{
int j;
L=(ptr)malloc(sizeof(struct node));
L->next=NULL;
L->prev=NULL;
p=L;
q=L;
setBrushColor(WHITE);
setPenColor(EMPTY);
setTextColor(BLUE);
setTextBkColor(EMPTY);
ptr ans=L;
initConsole();
initWindow("Line Editor",-1,-1,1200,400);
N=getWidth()*14/16/dx;
for(j=0;j<sizeof(obs)/sizeof(int);j++)obs[j]=N*dx;//初始化为最大长度
paintcaret(mousex,mousey);
registerKeyboardEvent(keyEvent);
registerCharEvent(charEvent);
}
void charEvent(char c,int event)
{
// printf("%d %d %d %d\n",mousex,nx,mousey,ny);
if(mousex<0)mousex=0;
if(nx>=getWidth()*14/16)
{
deep++;
nx=0;
mousex=0;
ny+=dy;
mousey+=dy;
}/*当前字符位置超过宽度,行数deep+1,回到0,当前纵坐标和鼠标纵坐标都增加dy*/
if(nx<0)
{
nx=0;
}/*防止在最开始按"←" */
if(!event)
{
if(c!=13&&c!=8)
{
mousex+=dx;
nx+=dx;
if(mousex==nx)
{
ptr tmp=malloc(sizeof(struct node));
tmp->c=c;
tmp->next=NULL;
tmp->prev=NULL;
p->next=tmp;
p=p->next;
p->prev=q;
q=q->next;
}/*鼠标位置和当前字符位置相同时 双向链表增加结点*/
else
{
ptr tmp=malloc(sizeof(struct node));
tmp->c=c;
tmp->next=p->next;
tmp->prev=p;
p->next=tmp;
p=p->next;
if(p->next)p->next->prev=tmp;
}/*鼠标位置在字符中间时 双向链表插入*/
}
}
paintL();/*打印链表*/
paintcaret(mousex,mousey);/*显示光标*/
}
void keyEvent(int key, int event)
{
if(key==13)
{
print(L);
system("pause");
exit(0);
}/*按下回车,打印链表,再按一下退出程序*/
if(!event)
{
if(key==8)/*按下backspace*/
{
if(mousex==0&&deep>0)
{
obs[deep]=N*dx;//归位
mousex=obs[--deep];
obs[deep]=N*dx;//再次归位 要这一层接着写
mousey-=dy;
}/*如果鼠标在非首行的最开头,按下backspace, 鼠标返回上一行,打印用到的obs归位*/
else if(mousex==0&&deep==0);/*在首行最开头,不做操作*/
else if(mousex>nx)mousex-=dx;
else if(p)
{
p->prev->next=p->next;
if(p->next)p->next->prev=p->prev;
ptr tmp=malloc(sizeof(struct node));
tmp=p;
p=p->prev;
free(tmp);
mousex-=dx;
nx-=dx;
}/*不是在最开头的位置,鼠标位置减一个字符dx,当前字符位置减dx,删除掉当前字符,全局变量的链表指针p左移*/
}
else if(key==46)
{
if(p)
{
if(p->next==NULL);
else
{
ptr tmp=malloc(sizeof(struct node));
tmp=p->next;
p->next=tmp->next;
if(p->next)p->next->prev=p;
free(tmp);
}
paintL();
}
}
else if(key==16);
else if(key==38);/*按“↑”,不做反应*/
else if(key==40)
{
if(mousey>=getHeight());
else mousey+=dy;
if(mousey>ny)obs[deep]=mousex;
mousex=0;
deep++;
}/*按“↓”,如果下一行没有字符,就用obs记录行数为deep时需要换行的位置,打印时遇到obs换行*/
else if(key==37)
{
mousex-=dx;
if(mousex<0)mousex=0;
if(mousex>0&&p)p=p->prev;
if(mousex==0);
}/*按“←”,光标左移,p向左指一位,以后可能会在此插入*/
else if(key==39)
{
mousex+=dx;
if(p->next)
{
p=p->next;
}
else{
ptr tmp=malloc(sizeof(struct node));
tmp->c=' ';
tmp->next=NULL;
tmp->prev=NULL;
p->next=tmp;
tmp->prev=p;
p=p->next;
}
nx+=dx;
}/*按“→”,光标位置和字符位置都加dx,如果在当前字符的尾部,填充一个空格,如果在中间,p往右移动一位,方便以后插入*/
}
paintcaret(mousex,mousey);//按上下左右
}
void paintcaret(int x,int y)
{
setCaretSize(3,25);
setCaretPos(x,y);
showCaret();
}
void print()
{
ptr pp=L->next;
while(pp)
{
printf("%c ",pp->c);
pp=pp->next;
}
printf("\n");
}
void paintL()
{
int k=0,flag=0,tag;
if(L==NULL)return;
ptr pp=L->next;
char a[10]={'\0'};
setTextSize(25);
beginPaint();
clearDevice();//放到begin和end里!
while(pp)
{
while(k*dx>=obs[flag])/*while解决跳行问题,即连按好多下“↓”,显示仍然正常*/
{
k=0;
flag++;
}
a[0]=pp->c;
paintText(k*dx,dy*flag,a);
pp=pp->next;
k++;
}
endPaint();
}