中国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
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

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


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



论坛跳转: