『楼 主』:
[分享]一个弹出式窗口类(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不知为什么不能登录了,重注册了一个。
|