中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » [分享]一个弹出式窗口类(C++源码)
作者:
标题: [分享]一个弹出式窗口类(C++源码) 上一主题 | 下一主题
awangwjf
新手上路





积分 7
发帖 3
注册 2010-2-26
状态 离线
『楼 主』:  [分享]一个弹出式窗口类(C++源码)

这是《C++大全》上的一个DOS下弹出式窗口类C++示例,使用直接写视频VRAM方法实现窗口的显示,在DOS后期是一种成熟、使用率较高的方法。 窗口类的I/O层用纯C++代码+BIOS中断实现,没用一个标准库函数。(除了速度快以外,这种代码比较易移植) 下面是该类完整的C++源码,包含用于演示的一个简单的main,该示例思路清晰,代码实现简洁易理解,是学习C++用于面向对象设计的较好的入门级示例。 代码在BC++3.1上编译通过。
/////////////////////////////////////////////////////////////////////////////
//
//	A window class
//             PASS  BC++ 3.1
//	From CPP P633
//	Type by AW@ng
//
//             Form http://www.cn-dos.net/forum/
//             
/////////////////////////////////////////////////////////////////////////////


#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <bios.h>
#include <stdio.h>

/////////////////////////////////////////////////////////////////////////////
//
//	Globe functions and data declare
//
/////////////////////////////////////////////////////////////////////////////



/* Text colors, first 7 can also be used to specify
   background color.
*/
const enum clr {black, blue, green, cyan, red, magenta,
		brown, lightgray, darkgray, lightblue,
		lightgreen, lightcyan, lightred,
		lightmagenta, yellow, white, blink=128};


char far *vid_mem;       //pointer to screen memory when in text mode


int  video_mode();
void goto_xy(int x, int y);
void set_v_ptr();
void write_char(int x, int y, char ch, int attrib);
void write_string(int x, int y, char *p, int attrib);


/////////////////////////////////////////////////////////////////////////////
//
//	End Globe declare
//
/////////////////////////////////////////////////////////////////////////////
//
//	Start globe function define
//
/////////////////////////////////////////////////////////////////////////////


//Return the current video mode
video_mode(void)
{
	union REGS r;

	r.h.ah = 15;

	return int86(0x10, &r, &r) & 255;
}


//Set video mode video_address
void set_v_ptr()
{
	int vmode;

	vmode = video_mode();
	if((vmode != 2) && (vmode != 3) && (vmode != 7))
	{
		cout << endl
		     << "Video must be in 80 column text mode"
		     << endl;

		exit( 1 );
	}

	//set proper address of video RAM
	if(vmode == 7)
	{
		vid_mem = (char *)0xB0000000;
	}
	else
	{
		vid_mem = (char *)0xB8000000;
	}
}



//Write character with specified attribute
void write_char(int x, int y, char ch, int attrib)
{
	char far *v;

	v = vid_mem;
	v += (y *160) + (x * 2);
	*v++ = ch;
	*v = attrib;
}


//Display string with specified attrib
void write_string(int x, int y, char *p, int attrib)
{
	register int i;
	char far *v;

	v = vid_mem;
	v += (y * 160) + (x * 2);

	for(i = y; *p ; i++)
	{
		*v++ = *p++;
		*v++ = attrib;
	}
}



//Send the cursor to the specified X, Y position
void goto_xy(int x, int y)
{
	union REGS r;

	r.h.ah = 2;
	r.h.dl = x;
	r.h.dh = y;
	r.h.bh = 0;

	int86(0x10, &r, &r);
}





/////////////////////////////////////////////////////////////////////////////
//
//	Start class declare
//
/////////////////////////////////////////////////////////////////////////////

class wintype
{
	int leftx;       	    //define where window goes on the screen
	int upy;         	    //upper left coordinate
	int rightx;
	int downy;      	    //lower right coordinate

	int border;    		    //if non-zero,border displayed
	int active;      	    //non-zero if window is currently on screen
	char *title;   		    //window title

	int curx, cury;  	    //current cursor location in window

	char *buf;      	    //points to window's buffer

	char color;      	    //window text color


	//private functions
	void save_screen();         //save screen so it can be restored
	void restore_screen();      //restore the original screen
	void draw_border();         //draw a window's border
	void display_title();       //display window title

    public:
	wintype(int lx, int uy,     //upper left
		int re, int ly,     //lower right
		int b = 1,          //non-zero for border
		char *mess = "");   //title message

	~wintype()
	{
		winremove();
		delete buf;
	}


	void winput();              //display a window
	void winremove();           //remove a window
	int  winputs(char *s);      //write a string to the window
	int  winxy(int x, int y);   //go to X, Y relative to window
	void wingets(char *s);      //input a string from a window
	int  wingetche();           //input a character from a window
	void wincls();              //clears the window
	void wincleol();            //clears to end-of-line

	void setcolor(char c)   {color = c;                  }
	char getcolor()         {return color;               }
	void setbkcolor(char c) {color = (color | (c << 4)); }
	char getbkcolor()       {return (color >> 4) & 127;  }


	friend wintype &operator << (wintype &o, char *s);
	friend wintype &operator >> (wintype &o, char *s);
};

/////////////////////////////////////////////////////////////////////////////
//
//	End class declare
//
/////////////////////////////////////////////////////////////////////////////



//Construct a window.
wintype::wintype(int lx, int uy,
		 int rx, int ly,
		 int b,
		 char *mess     )
{
	if(lx < 0 ) lx = 0 ;
	if(rx > 79) rx = 79;
	if(uy < 0 ) uy = 0 ;
	if(ly > 24) ly = 24;

	leftx  = lx    ;
	upy    = uy    ;
	rightx = rx    ;
	downy  = ly    ;
	border = b     ;
	title  = mess  ;
	active = 0     ;
	curx = cury = 0;

	buf = new char[ 2 * (rightx - leftx + 1) * (downy - upy + 1) ];
	if( !buf )
	{
		cout << "\nAllocation window buffer error\n";
		exit( 1 );
	}

	color = white;
}


//Display a window
void wintype::winput()
{
	//get active window
	if( !active )		    //not currently in use
	{
		save_screen();      //save the current screen
		active = 1;         //set active flag
	}
	else
	{
		return;             //already on screen
	}

	if( border )
	{
		draw_border();
	}
	display_title();

	//position cursor in apper left corner
	goto_xy(leftx + curx + 1, upy + cury +1);
}


//Remove the window and restore prior screen contents.
void wintype::winremove()
{
	if(!active)        //con't remove a non-active window
	{
		return;
	}

	restore_screen();  //restore the original screen
	active = 0;        //restore_video
}


//Draw a border around the window
void wintype::draw_border()
{
	register int  i;
	    char far *v;
	    char far *t;

	    v = vid_mem;
	    t = v;

	    for(i = leftx + 1; i < rightx; i++)
	    {
            v += (upy * 160) + (i * 2);
            *v ++ = 196;
            *v = color;
            v = t;
            v += (downy * 160) + (i * 2);
            *v ++ = 196;
            *v = color;
            v = t;
	    }

	    for(i = upy + 1; i < downy; i++)
	    {
            v += (i * 160) + (leftx * 2);
            *v ++ = 179;
            *v = color;
            v = t;
            v += (i * 160) + (rightx * 2);
            *v ++ = 179;
            *v = color;
            v = t;
	    }

	    //draw the corners
	    write_char(leftx,  upy,   218, color);
	    write_char(leftx,  downy, 192, color);
	    write_char(rightx, upy,   191, color);
	    write_char(rightx, downy, 217, color);
}


//Display the window's title
void wintype::display_title()
{
	register int x, len;

	x = leftx;
	len = strlen(title);
	len = (rightx - x- len)/2;
	if( len < 0 ) return;

	x = x + len +1;

	write_string(x, upy, title, color);
}


//Save screen so ti can be restored after window is removed
void wintype::save_screen()
{
	register int i, j    ;
	    char far *v      ;
	    char far *t      ;
	    char *buf_ptr    ;


	    buf_ptr = buf;
	    v = vid_mem;
	    for(i = upy; i < downy+1; i++)
	    {
            for(j = leftx; j < rightx+1; j++)
            {
                t = (v + (i*160) + (j*2));
                *buf_ptr++ = *t++;
                *buf_ptr++ = *t;
                *(t - 1) = ' ';               //clear the window
            }
	    }
}


//Restore a portion of the screen
void wintype::restore_screen()
{
	register int i, j    ;
	    char far *v      ;
	    char far *t      ;
	    char *buf_ptr    ;


	    buf_ptr = buf;                      //computer pointer to video RAM
	    v = vid_mem;
	    t = v;

	    for(i = upy; i < downy+1; i++)
	    {
            for(j = leftx; j < rightx+1; j++)
            {
                v = t;
                v += (i*160) + j*2;
                *v++ = *buf_ptr++;      //write the character
                *v = *buf_ptr++;        //write the attrib
            }
	    }
}


//Write a string at the current cursor position win the specified window
int wintype::winputs(char *s)
{

	register int x, y;
	    char far *v;


	//make sure window is active
	if ( !active )	return 0;


	x = curx + leftx + 1;
	y = cury + upy + 1;

	v = vid_mem;
	v += (y * 160) + (x * 2);

	for( ; *s; s++ )
	{
		if(y >= downy)
		{
			return 1;
		}
		if(x >= rightx)
		{
			return 1;
		}

		if(*s == '\n')
		{
			y++;
			x = leftx + 1;
			v = vid_mem;
			v += (y * 160) + (x * 2);;
			cury++;
			curx = 0;
		}
		else
		{
			curx++;
			x++;
			*v++ = *s;
			*v++ = color;
		}

		winxy(curx,cury);
	}

	return 1;
}


/* Postion cursor in a window at specified location
   Return 0 if out of range; non-zero otherwise.
*/
int wintype::winxy(int x, int y)
{
	if(x < 0 || x+leftx >= rightx-1)
	{
		return 0;
	}
	if(y < 0 || y+upy >= downy-1)
	{
		return 0;
	}

	curx = x;
	cury = y;
	goto_xy(leftx + x + 1, upy + y + 1);

	return 1;
}


//read a string from a window
void wintype::wingets(char *s)
{
	char ch, *temp;

	temp = s;

	for(;;)
	{
		ch = wingetche();

		switch(ch)
		{
			case '\r' :
				{
					*s = '\0';
					return ;
				}

			case '\b' :
				if(s > temp)
				{
					s--;
					curx--;

					if(curx < 0)
					{
						curx = 0;
					}

					winxy(curx, cury);
					write_char(leftx + curx + 1, upy + cury +1, ' ', color);
				}
				break;

			default :
				{
					*s = ch;
					s++;
				}
		}
	}
}



/* Input a keystroke inside a window
   Returns full 16 bit keyboard code.
*/
wintype::wingetche()
{
	union inkey
	{
		char ch[2];
		int  i;
	} c;
	union REGS r;


	if( !active ) return 0;


	winxy(curx, cury);

	r.h.ah = 0;
	c.i = int86(0x16, &r, &r);

	if( c.ch[0] )
	{
		switch( c.ch[0] )
		{
			case '\r' :
			{
				break;
			}

			case '\b' :
			{
				break;
			}

			default:
				{
					if( curx + leftx < rightx -1 )
						{
							write_char(leftx + curx +1,
								   upy + cury +1,
								   c.ch[0],
								   color	   );
							curx++;
						}
				}
		}
	}

	if(cury < 0) cury = 0;
	if(cury + upy > downy -2)
		{
			cury--;
			winxy(curx, cury);
		}

	return c.i;
}


//Clear a window
void wintype::wincls()
{
	register int i, j;
	char far *v, far *t;

	v = vid_mem;
	t = v;

	for(i = upy +1; i < downy; i++)
		for(j = leftx + 1; j < rightx; j++)
			{
				v = t;
				v += (i * 160) + (j * 2);
				*v++ = ' ';
				*v = color;
			}

	curx = 0;
	cury = 0;
}


//Clear to end of line
void wintype::wincleol()
{
	register int i, x, y;


	x = curx;
	y = cury;
	winxy(curx, cury);

	for(i = curx; i < rightx; i++)
		{
			winputs(" ");
		}

	winxy(x, y);
}


//Output to a window
wintype &operator << (wintype &o, char *s)
{
	o.winputs(s);
	return o;
}


//Input from a window
wintype &operator >> (wintype &o, char *s)
{
	o.wingets(s);
	return o;
}



/////////////////////////////////////////////////////////////////////////////
//
//   Main program here
//
/////////////////////////////////////////////////////////////////////////////
main()
{
	char s[80];



	set_v_ptr();		//set the video memory pointer


	wintype w1(1, 10, 20, 20, 1, "My window #1");
	wintype w2(40, 1, 60, 20, 1, "My window #2");
	wintype w3(40, 5, 60, 20, 2, "My window #3");


	w1.winput();
	w2.winput();

	w1.setcolor(blue);
	w2.setcolor(green);
	w3.setcolor(red);
	getch();

	w1.winremove();
	w2.winremove();
	getch();

	w1.winput();
	w2.winput();
	w3.winput();
	getch();


	w1.winremove();
	getch();

	w3.winremove();
	getch();

	w2.winremove();
	getch();



	w1.winput();
	w2.winput();
	getch();

	w1 >> s;
	w1.winxy( 0, 0 );
	getch();

	w1.winputs("Hi there\n");
	w1.winputs("Windows is fan");
	w1 << "\n";
	w1 >> s;
	w1 << "This \nis " << "a test" << "\n";
	w2 << "this is a test";
	w2.winxy(3, 4);
	w2 << "at location 3,4";
	w1 << "This is anther test for you to see\n";
	w1 >> s;

	w3.winput();
	w3 >> s;
	w3.winremove();
	getch();


	w1.winxy(0, 0);
	w1.setcolor(red);
	w1.setbkcolor(cyan);
	w1.winputs("PROMPT:");
	w1.setcolor(white);
	w1.setbkcolor(black);
	w1 >> s;

	w2.winxy(0, 4);
	w2.setcolor(yellow);
	w2.setbkcolor(green);
	w2.winputs(s);
	w2 >> s;

	w2.wincls();
	w1.winxy(5, 0);
	w1.wincleol();
	w2 >> s;

	w1.winremove();
	w2.winremove();
	w1.winput();

	
                w1 >> s;


	return 0;
}
BC++下的代码copy到Win下有个别地方显示板式不同,没太大影响,没做调整。 这个示例是我学习C++的时候完成的,代码中的字符都是本人一个个敲进电脑的,一是为了学习BC++3.1的IDE,另外也能加深对代码的理解,书中个别印错的地方已经修正。现发上来和初学C++的朋友和爱好者共享。 那时的C++实现标准是1989年的2.1版,没现在这么复杂,模板和异常还是发展方向,名字空间,泛型听都没听说过,正因为这样,更能有助于学习C++面向对象的思维方法,而不是专注于代码的实现,这才是C++和C的本质区别。 2.1版的C++个人认为是比较纯淬的C++,能很好的用OO实现C++的初衷“使程序结构清晰、易于扩展、易于维护而不失其效率”,没有多余的东西,“增一分太肥,减一分太瘦”。 现在C++加入了各种“先进”的特性后,发展到目前的C++0X,连C++的发明人也不得不承认有些“四不象”了,真可惜了这一优美的程序设计语言。 题外: 关于BC++3的经典有了最新证据,Win7下的BC++3.1比在Windows3.1时代好用,把“环境”项里的25行显示改为50行,再得宜于Win7完善高效的内存管理,用起来真是舒服,再看看Win7的自家人VC6,“该程序有兼容性问题,请......”,我真的哭笑不得。 以前的ID不知为什么不能登录了,重注册了一个。


2010-2-27 12:50
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
stockghost
中级用户





积分 215
发帖 105
注册 2007-6-2
状态 离线
『第 2 楼』:  

都是DOS老人,同好! Win9x/2k/xp都支持DOS程序,而且也支持dos32(不管是watcom还是djgpp编译出来的),但在vista测试,上述两种程序都不支持. Win7没用过,支持DOS? 如果支持,估计也支持dos32.


2010-2-27 17:30
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
BA_WANG_MAO
初级用户




积分 147
发帖 13
注册 2005-3-25
状态 离线
『第 3 楼』:  

dos时刻最经典的"直接写屏"模式,绕开DOS的API和BIOS,直接对显存编程,提高显示速度.


2010-3-3 10:23
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: