
- •Введение
- •1. Общие принципы создания интерфейса
- •1.1. Эргономические характеристики интерфейса
- •1.2. Составные части интерфейса
- •1.3. Виды диалога
- •1.4. Процессы ввода – вывода
- •1.5. Методы разработки подпрограмм нижнего уровня
- •Int int86(int num, union regs *inregs, union regs *outregs);
- •Void pokeb(unsigned seg, unsigned off, char value);
- •Int getch();
- •2. Исчезающее меню
- •2.1. Алгоритм создания исчезающего меню
- •2.2. Сохранение и восстановление экрана
- •2.3. Вывод меню и рамки
- •2.4. Определение выбора пользователя
- •2.5. Подпрограмма исчезающего меню
- •3. Иерархическое меню
- •3.1. Фреймы меню
- •3.2. Подпрограмма активизации меню
- •3.3. Организация иерархического меню
- •3.4. Всплывающие окна
- •Void window(int num);
- •Void deactivate(int num);
- •4. Графический интерфейс
- •4.1. Организация меню в графическом режиме
- •Void outtextxy ( int X, int y, char *s);
- •4.2. Организация графического диалога
- •4.3. Особенности графического режима
- •Void putpixel (int color, int X, int y)
- •4.4. Форматы хранения графических файлов
- •5. Прикладной интерфейс для windows
- •5.1. Приложения Windows
- •5.2. Каркас приложения
- •5.3. Обработка сообщений в системе Windows
- •Int ReleaseDc(hwnd hwnd, hdc hdc);
- •Int MessageBox(hwnd hwnd, lpcstr lpText, lpcstr lpCaption, uint wMbType);
- •Int response;
- •5.4. Меню в системе Windows
- •5.5. Диалоги в системе Windows
- •Int DialogBox(hinstance hThisInst,
- •5.6. Пример программы, использующей список и окно ввода
- •6. Лабораторная 1
- •Варианты заданий
- •Пример выполнения задания
- •7 Лабораторная 2
- •Варианты заданий
- •Пример выполнения задания
6. Лабораторная 1
Задание
Написать программу, имитирующую работу пользователя в режиме редактирования. При нажатии обычных клавиш на экран выводятся соответствующие им буквы.
Если нажата одна из клавиш: «стрелка влево», «стрелка вверх», «стрелка вправо», «стрелка вниз», то курсор продвигается на одну позицию в указанном направлении. Исчезающее меню вызывается с помощью клавиши <F2>.
В зависимости от варианта исчезающее меню выводится горизонтально, либо вертикально, и состоит из четырех опций, одного из видов:
3. |
Цвет вывода |
|
Фон |
|
Эхо |
|
Выход |
2. |
Курсор |
|
Палитра |
|
Эхо |
|
Выход |
1. |
Сохранение |
|
Восстановление |
|
Эхо |
|
Выход |
Горячие клавиши для первого вида меню: ‘1’, ‘2’, ‘3’, ‘4’; для второго: ‘К’, ‘П’, ‘Э’, ‘В’; для третьего: ‘Ц’, ‘Ф’, ‘Э’, ‘В’.
После выбора опции меню исчезает, и производится одно из действий:
-
эхо – возврат в режим редактирования;
-
выход – конец работы программы;
-
сохранение – сохранение содержимого экрана в файл R.TXT;
-
восстановление – чтение файла R.TXT и вывод его на экран;
-
курсор – изменение размеров курсора;
-
палитра – смена палитры;
-
цвет вывода – изменение цвета символов, которые выводятся на экране при нажатии клавиш;
-
фон – изменение цвета фона символов.
Опишем распределение по вариантам положения и опции меню. Видам меню присвоим номера 1, 2 и 3. Горизонтальное меню обозначим буквой ‘Г’, вертикальное – буквой ‘В’. Положения меню: “слева и сверху”, “слева и внизу”, “справа и сверху”, “в центре” означают, где расположена линейка или столбик меню. Например, в левом верхнем углу или в центре экрана.
Варианты заданий
|
1Г |
1В |
2Г |
2В |
3Г |
3В |
Слева и сверху |
1 |
2 |
3 |
4 |
5 |
6 |
Слева и внизу |
7 |
8 |
9 |
10 |
11 |
12 |
Справа и внизу |
13 |
14 |
15 |
16 |
17 |
18 |
Справа и сверху |
19 |
20 |
21 |
22 |
23 |
24 |
В центре |
25 |
26 |
27 |
28 |
29 |
30 |
В клетках расположены номера вариантов. Например, в варианте 15 студент создает меню 2 (“Курсор”, “Палитра”, “Эхо”, “Выход”), выводящееся горизонтально (‘Г’) и находящееся в правой нижней области экрана.
Пример выполнения задания
Требуется написать программу, работающую в режиме “Эхо”. Подпрограмма исчезающего меню включает опции “Курсор”, “Палитра”, “Эхо”, “Выход” и поддерживает горячие клавиши “кпэв”. Меню представляет собой горизонтальную линейку и выводится слева, в средней линии экрана.
Решение. Для изменения курсора воспользуемся подпрограммой setcursortype() из пп. 1.5. Линию и нижнюю строки курсора будем устанавливать случайно. Для изменения всех регистров палитры применим подпрограмму randpalette() из пп. 1.5. Для установки позиции меню выберем x = 0, y = 10. Максимальную длину строк меню можно передавать в подпрограммы как параметр. Чтобы не было больших отличий от вывода меню вертикально, будем вычислять эту длину в каждой из подпрограмм popup(), display_menu(), get_resp(). Преобразуя эти подпрограммы, получаем следующий текст программы:
#include "stdio.h"
#include "dos.h"
#include "stdlib.h"
#include "time.h"
#include "string.h"
#include "bios.h"
#include "ctype.h"
#include "conio.h"
#define BORDER 1
#define ESC 27 // Escape
#define ENTER 13
#define BKC 8
#define F1 59 // F1
#define F2 60 // F2
#define REV_VID 0x70
#define NORM_VID 7
#define LEFT 75 // стрелка влево
#define RIGHT 77 // стрелка вправо
#define UP 72 // стрелка вверх
#define DOWN 80 // стрелка вниз
void save_video(int, int, int, int, unsigned char*);
void restore_video(int, int, int, int, unsigned char *);
void display_menu(char**,int,int,int,int,int);
void draw_border(int, int, int, int);
void write_string(int, int, char*, int);
void write_char(int,int,char,int);
void select(char**, int);
int popup(char**,char*,int,int,int,int);
int get_resp(int,int,int,char**,char*);
int is_in(char*, char);
int video_mode();
void respalette() ;
void randpalette();
void randcursortype();
char far *vid_mem;
int last_x, last_y;
int TEXT_ATTR=14, TEXT_COLOR=0, BK_COLOR=0;
char *menu[] =
{
" Курсор ",
" Палитра ",
" Эхо ",
" Выход "
};
void main(void)
{
char press;
int x,y;
clrscr(); //очистка экрана
int vmode = video_mode();
if((vmode!=2) && (vmode!=3) && (vmode!=7))
{
printf(" должен быть 80 символьный текстовый режим");
exit(1);
}
/* присвоить соответствующий адрес видеопамяти */
if(vmode==7)
vid_mem=(char far *)0xB0000000; //монохромный режим
else
vid_mem=(char far *)0xB8000000; //цветной режим
window(2,2,79,24);
gotoxy(1,1);
while(1)
{
press = getch();
if(!press) press = getch(); //расширенная клавиатура
x=wherex(), y=wherey();
switch(press)
{
case LEFT : gotoxy(x-1,y);break;
case RIGHT: gotoxy(x+1,y);break;
case UP : gotoxy(x,y-1);break;
case DOWN : gotoxy(x,y+1);break;
case F1 : write_string(1,24,"F2 - меню, ESC - выход",TEXT_ATTR);
break;
case F2 : last_x=x;last_y=y;
popup(menu,"кпэв",4,0,10,BORDER); break;
case ENTER: cprintf("\n\r"); break;
case BKC : if (x==1) gotoxy(78,y-1);
else gotoxy(x-1, y);
write_char(wherex(),wherey(),' ',TEXT_ATTR); break;
case ESC : respalette();exit(1); break;
default : write_char(x,y, press,TEXT_ATTR);
if(x==78) gotoxy(1,y+1);
else gotoxy(x+1,y); break;
}
}
}
/* вывести исчезающее меню и вернуть выбор
возвращает -2, если меню не может быть создано
возвращает -1, если пользователь нажал клавишу ESC
в остальных случаях она возвращает номер выбранного
режима, начиная с 0 */
int popup( char *menu[], /* текст меню */
char *keys, /* горячие клавиши */
int count, /* число режимов */
int x, int y, /* координаты левого верхнего угла */
int border) /* если 0, то без рамки */
{
register int i,len;
int endx, endy, choice;
unsigned char *p;
if((x>79)||(x<0)||(y>24)||(y<0))
{
printf(" выход за пределы экрана");
return -2;
}
/* вычисление размеров меню*/
len=0;
for(i=0;i<count;i++)
if(strlen(menu[i]) > len)
len = strlen(menu[i]);
endx=len*count+x+1;
endy=y+2;
if((endx>79) || (endy>24))
{
printf(" выход за пределы экрана");
return -2;
}
/* размещение памяти для видеобуфера */
p=(unsigned char *)malloc((len*count+2)*3*2);
if(!p) exit(1); /* Вы можете здесь сами обработать ошибку */
/* сохранение части экрана */
save_video(x, endx, y, endy, p);
/* рисуем рамку, если необходимо */
if(border) draw_border(x,y,endx,endy);
/* высвечивание меню на своем месте */
display_menu(menu,x+1,y+1,endx-1, endy-1, count);
/* ввести выбор пользователя */
choice=get_resp(x+1,y+1,count,menu,keys);
select(menu, choice);
/* восстановление части экрана */
restore_video(x, endx, y, endy, p);
/* освобождаем память */
free(p);
return choice;
}
/* высвечивание меню на своем месте */
void display_menu( char* menu[],
int startx,
int starty,
int endx,
int endy,
int count)
{
register int i, j;
int len;
//Закраска области меню
for(i=starty; i<=endy;i++)
for(j=startx; j<=endx; j++)
write_char(j, i , ' ', NORM_VID);
len=0;
for(i=0;i<count;i++)
if(strlen(menu[i]) > len)
len = strlen(menu[i]);
for(i=0;i<count;i++,startx+=len)
write_string(startx, starty, menu[i], NORM_VID);
}
/* рисование рамки меню*/
void draw_border(int startx, int starty, int endx, int endy)
{
register int i;
write_char(startx, starty, 218, NORM_VID);
write_char(endx, starty, 191, NORM_VID);
write_char(startx, endy, 192, NORM_VID);
write_char(endx, endy, 217, NORM_VID);
for(i=startx+1; i<endx; i++)
{
write_char(i, starty, 196, NORM_VID);
write_char(i, endy, 196, NORM_VID);
}
for(i=starty+1;i<endy;i++)
{
write_char(startx, i,179, NORM_VID);
write_char(endx, i,179, NORM_VID);
}
}
/* ввести выбор пользователя */
int get_resp(int x, int y, int count, char* menu[], char* keys)
{
union inkey
{
char ch[2];
int i;
} c;
int arrow_choice=0, key_choice;
int i, len=0;
for(i=0;i<count;i++)
if(strlen(menu[i]) > len)
len = strlen(menu[i]);
/* осветить первый выбор */
write_string(x, y, menu[0], REV_VID);
for(;;)
{
while(!bioskey(1)); // ждать нажатия
c.i=bioskey(0);
/* вернуть выбор в нормальный режим */
write_string(x+len*arrow_choice, y, menu[arrow_choice], NORM_VID);
if(c.ch[0]) // обычная клавиша
{
// горячая клавиша?
key_choice = is_in(keys,tolower(c.ch[0]));
if(key_choice) return key_choice-1;
switch(c.ch[0])
{
case '\r' : return arrow_choice;
case ' ' : arrow_choice++; break;
case ESC : return -1; // выйти
}
}
else // специальная клавиша
{
switch(c.ch[1])
{
case LEFT : arrow_choice--; // стрелка вниз
break;
case RIGHT: arrow_choice++; // стрелка вверх
break;
}
}
/* осуществить цикличность меню */
if(arrow_choice==count) arrow_choice=0;
if(arrow_choice<0) arrow_choice=count-1;
/* подсветить выбранную опцию */
write_string(x+arrow_choice*len, y, menu[arrow_choice], REV_VID);
}
}
/* вывод строки с определенным атрибутом */
void write_string(int x, int y, char* p, int attrib)
{
register int i;
char far *v; //адрес символа
v = vid_mem; //в v помещаем адрес начала видеопамяти
v += y*160+x*2; //вычисляем адрес начала строки в видеопамяти
for(i=y;*p;i++)
{
*v++ = *p++; //записываем в видеопамять символ
*v++ = attrib; //записываем в видеопамять атрибут
}
}
/* запись символа с определенным аттрибутом */
void write_char(int x, int y, char ch, int attrib)
{
char far *v; //адрес символа
v = vid_mem; //в v помещаем адрес начала видеопамяти
v += y*160+x*2; //вычисляем адрес символа в видеопамяти
*v++ = ch; //записываем в видеопамять символ
*v = attrib; //записываем в видеопамять атрибут
}
/* сохранение части экрана с использованием
прямого доступа к видеопамяти */
void save_video( int startx,
int endx,
int starty,
int endy,
unsigned char *buf_ptr)
{
register int i, j;
char far *v, far *t;
v=vid_mem;
for(i=starty;i<=endy;i++)
{
for(j=startx; j<=endx; j++)
{
t = v+i*160+j*2; // вычисляем адрес
*buf_ptr++ = *t++; // записываем в буфер символ
*buf_ptr++ = *t; // записываем в буфер атрибут
}
}
}
/* восстановление части экрана с использованием
прямого доступа к видеопамяти */
void restore_video( int startx,
int endx,
int starty,
int endy,
unsigned char *buf_ptr)
{
register int i,j;
char far *v,far *t; // временные переменные
v=vid_mem; // адрес начала видеопамяти
t=v;
for(i=starty; i<=endy; i++)
{
for(j=startx; j<=endx; j++)
{
v = t;
v += i*160+j*2; // вычисление адреса
*v++ = *buf_ptr++; // восстановление из буфера символа
*v = *buf_ptr++; // восстановление из буфера атрибута
}
}
}
/* запрос текущего видеорежима */
int video_mode()
{
union REGS r;
r.h.ah = 15; /* получить режим */
return int86(0x10,&r,&r) & 255;
}
/* проверка принадлежности символа с строке s */
int is_in(char* s, char c)
{
register int i;
for(i=0; *s; i++)
if(*s++ == c) return i+1;
return 0;
}
/* анализ выбора пункта меню */
void select(char* menu[], int pos)
{
// здесь должна быть Ваша обработка событий меню
switch(pos)
{
case 0: randcursortype();
break;
case 1: randpalette();
break;
case 2: return;
case 3: respalette(); exit(1);
}
}
void respalette()
{
union REGS r;
r.h.ah = 0;
r.h.al = video_mode();
int86(0x10,&r,&r);
}
void setcursortype(int h, int l)
{
union REGS r;
r.x.ax = 0x0100;
r.x.bx = 0;
r.h.ch = h; r.h.cl = l;
int86(0x10,&r,&r);
}
void randcursortype()
{
setcursortype(random(20),random(20));
}
void setpalette(char i, char red, char green, char blue)
{
union REGS r;
r.h.ah = 0x10;
r.h.al = 0;
r.h.bl = i;
r.h.bh = (red%2)*32 + (red/2)*4 +
(green%2)*16 + (green/2)*2 +
(blue%2)*8 + (blue/2);
int86(0x10,&r,&r);
}
void randpalette()
{
int i;
for (i=0; i<16; i++)
setpalette(i, random(3), random(4),random(4));
}