Помощь - Поиск - Пользователи - Календарь
Полная версия: ООП и графический редактор
Форум «Всё о Паскале» > Pascal, Object Pascal > Теоретические вопросы
demon9999
Уважаемые господа!
Проблема такая - мне было задано за семестр изучить объектно ориентированное программирование и с его помощью написать какой-нибудь графический редактор.
Что такое ООП я, в принципе, изучил (спасибо литературе на этом сайте и на borlpasc.narod.ru) и написал программу, демонстрирующую его особенности (текст прилагается). Но с редактором у меня возникли ряд вопросов, которыя я не могу решить самостоятельно.
1. Для рисования чего бы то ни было мне нужно получать координаты х,у с положения курсора. Теоретически я понимаю что это делается функцией GetX, GetY, но практически так и не въехал, как ее применять. Разъясните, пожалуйста, поподробнее. Если можно, то на примере приложенной программы.
2. Сохранение и откат. Опять таки, теоретически я предполагаю, что сохранение ведется в список (видимо односвязанный), но как?
3. Может быть кто-нибудь что то похожее делал? Если остались исходники каких-нибудь модулей (интерфейс, рисование фигур и вообще все что подходит по теме) скиньте, пожалуйста, мне на почтовый ящик. Только сложностей не надо - я еще не волшебник, я только учусь smile.gif
Вообще редактор, по моему разумению должен получиться простой, без мыши, на hot key's. Типа "ручки-ножки-огуречик".
Заранее благодарен.
Код
Program OPP1;
Uses Crt, Graph;
Var gd,gm:integer;
 Ch: Char;
 S: Boolean;
Const
 Instr = 'УПРАВЛЕНИЕ ДВИЖЕНИЕМ - СТРЕЛКИ, ПЕРЕХОД - END, ВЫХОД - ESC';

Type
 Tp=Object   {объект - точка}
   X,y,c : integer;
   Constructor Init(ax,ay:integer;ac:word);
   Procedure Show; Virtual;
   Procedure Hide; Virtual;
   Procedure Moveto(dx: integer);
 End;

Constructor Tp.Init;
Begin
 X:=ax; y:=ay; c:=ac;
End;

Procedure Tp.Show;
Begin
 Putpixel(x,y,c);
End;

Procedure Tp.Hide;
Begin
 Putpixel(x,y,Getbkcolor)
End;

Procedure Tp.Moveto;
Begin
 repeat
   s:=true;
   Ch := ReadKey;
   Case Ch of
     #27: begin CloseGraph; Halt end;  { выход по клавише ESC }
     #75: begin Hide; X := X-dx end; {изменение координат x, y нажатием стрелок}
     #77: begin Hide; X := X+dx end; {"влево", "вправо", "вверх", "вниз"       }
     #72: begin Hide; Y := Y-dx end;
     #80: begin Hide; Y := Y+dx end;
     #79: S := false; {переход кнопкой END}
   end;
   Show;
 until s = false;
 Hide;
End;

Type
 Tc=Object(Tp)    {объект - круг (наследник)}
   r : integer;
   Constructor Init(ax,ay,ar:integer;ac:word);
   Procedure Show; Virtual;
   Procedure Hide; Virtual;
 End;

Constructor Tc.Init;
Begin
 Inherited Init(ax,ay,ac);  {наследование инициализации}
 R:=ar
End;

Procedure Tc.Show;        {рисование круга}
 Begin
   Setcolor( c );
   Circle(x,y,r);
   SetFillStyle(solidfill, red);
   FloodFill(x,y, red);
 End;

Procedure Tc.Hide;
Begin
 Setcolor(GetBkColor);
 Circle(x,y,r);
 SetFillStyle(solidfill, GetBkColor);
 FloodFill(x,y, GetBkColor);
End;

Var
 T: Tp;
 C: Tc;

Begin
 gd:=detect;
 initgraph(gd,gm,'c:tpbgi');
 SetBkColor(White);
 SetColor(blue);
 Rectangle(50, 425, 600, 460);            {рисование рамки}
 OutTextXY(90, 440, Instr);
 T.Init(125,125,Magenta);      {инициализация 1 объекта}
 T.Show;                       {прорисовка объекта}
 T.MoveTo(15);                 {движение объекта}
 C.Init(125,125,15,red); {инициализация объекта 2}
 C.Show;                  {прорисовка объекта 2}
 While True do begin
   C.Moveto(15);           {движение объекта 2 }
 end;
end.
___ALex___
чё-то я себе не больно представляю рисование без мыши?
как это?
или он должен работать так неудобно типа:
выбрал режим - линия, указываешь две точки - нажимаешь ещё что-нить он тебе рисует линию через две точки, выбрал режим круг - указал центр - нажал "нажимаешь ещё что-нить" - нарисовался круг
такой примитив тебе нужен?
а с ООП тебе ещё надо разбираться и разбираться...
demon9999
Alex'у
Во-первых, мне действительно нужен примитив, т.к. я не в состоянии быстро разобраться с мышом и программами под мыша в Паскале. А для студента-заочника, по непрофильному курсу, хватит и примитива.
Во-вторых, мне еще многов чем разбираться, я и не хвастаю мастерством.
И, в-третьих, а по существу вопроса ты что-нибудь можешь сказать?
___ALex___
давай всё по порядку:
  1. Как должна работать программа?
    Потому что без мыши она будет работать по механизму как я описал в предыдущем посте или по пиксельно выводить, то есть юзер "ведёт" курсор по экран и в этих местах выводятся пиксели
  2. Насчёт отката
    Должна ли твоя программа сохранять нарисованное изображение в файл? Число откатов ограниченно? Можно либо сохранять изображения после каждого его изменения в файл, либо в память, либо сохранять информацию о том "как заново нарисовать изображение" (что будет тормозней - этого лучше не делать)
  3. Ну рисовать будешь в цикле, там же будешь реагировать на нажатия клавиш пользователем, смещая курсор вывода
  4. Насчёт ООП
    Объект - есть "сущность" и она НЕ должна зависить от чего-либо. Это самостоятельная единица и писать методы типа MoveTo, который к тому же использует ещё и глобальную переменную S не следует, пиши отдельно методы MoveLeft, MoveRight, MoveUp, MoveDown, а обработка нажатий клавиш будет вестись с основной проге (см. пункт 3)
Ещё хотел сказать на счёт основной части твоего примера: раз ты определяешь
графдрайвер, а вместе с ним и графрежим автоматически (Detect), то использовать
в программе абсолютные координаты не нужно, так как режим может "выставиться" какой угодно и твоя программа будет выводить графику неправильно. Используй GetMaxX, GetMaxY либо выбирай конкретный режим.
demon9999
Alex'у по порядку:
  1. Программа должна работать, по моему разумению, так:
    При загрузке появляется собственно лист для рисования и сбоку краткое описание - рисовать круг-клавиша, рисовать прямоугольник-клавиша, рисовать линию-клавиша, заливка-клавиша, сохранить-клавиша, выйти-ESC.

    При нажатии на одну из горячих клавиш появляется курсор в центре экрана (или где-нибудь еще) и внизу поясниловка. например, для круга - "выберите центр окружности, нажмите " ", определите диаметр "+" больше, "-" меньше, Enter - оставить так, Esc-убрать". (шаг увеличения/уменьшения равен шагу курсора, забит в переменных и не меняется), начало линии задается клавишей и дальше она рисуется за курсором (LineTo?) и т.д.

    Все фигуры (контуры) рисуются одним цветом, чтобы было проще с заливкой.
  2. Откат, в принципе, не нужен (было задано сделать, если смогу), но итоговое изображение должно сохраняться в файл (и, соответственно, загружаться из файла, при желании).

    Сохранение должно быть векторным. Кстати, а что это такое?
  3. Рисовать само-собой в цикле. Видимо на каждую фигуру свой объект. При этом кто кого будет наследовать, я еще не понял :'(
  4. Насчет отдельных методов - не понял. Я просто содрал программу из исходников, дополнил ее объектами из примеров к лекции по ООП, подкорректировал, как сумел и оно работает. Правда сделать так, чтобы кружочек появлялся там, где пропадает точка у меня не получилось sad.gif (см. выше)
___ALex___
лучше б ты на Delphi писал проблем бы заметно поубавилось
кстати щас вроде вся учёба закончилась?(
у меня винт недавно полетел, так что щас Турбо Паскаля нет
пришли мне его по почте(только всё самое необходимое)там "покумекаем"
в архиве зашли
вот мыло ___ALex___@inbox.ru
Noname
скачать можно тут
                                       http://pascal.dax.ru/?go&id=9
AlaRic
Интересная тема! Пишите, а мы подкорректируем, если конечно сможем  ;)
___ALex___
ну чё Паскаль я добыл(
AlaRic
подключайся?  :D
AlaRic
Я сейчас правда сайтом занят, но постараюсь помочь!  
trminator
В работе. Делаю наподобие PostScript (основано на стеке) - следовательно, векторное и простой откат любой глубины
___ALex___
автор сабжа пропал давно
AlaRic
Цитата
автор сабжа пропал давно

Не сказал бы. Кажется у него некоторые трудности: http://pascal.dax.ru/?gb
demon9999
Я не пропал, я просто терпеливо жду, когда в обсуждении появится какой-нибудь ответ на какой-либо из моих вопросов.
Мы просто приходим на форум в разное время из за разницы в часовых поясах (весьма большой, кстати) smile.gif
demon9999
Да. И не надо все усложнять. Если подключить мышь, проработать интерфейс, сделать все очень красиво и векторно, то получится что-то вроде http://pascal.hop.ru/Arhives/Edit.zip
Только я не в состоянии понять, как это работает :'(
А я не могу (и не хочу) сдавать то, что я несмогу объяснить.
Стар я уже стал краснеть перед преподавателем, который лет на 10 меня моложе ;)
___ALex___
ты по малу спрашивай что нужно!( smile.gif
а то каждый раз на форум заходить...
___ALex___
а если хочешь хороший интерфейс, то надо писать на Delphi или в какой-нибудь другой визуальной среде с ООП языком
demon9999
В своем первом сообщении (см.выше) я поставил, по-моему, вполне конкретные вопросы.
Я ведь не прошу написать за меня программу, я постараюсь сделать это сам. Просто в процессе работы столкнулся с трудностями, которые не могу сам разрешить, поэтому обратился на форум.
Я не слишком уж туп, как мне кажется  ;) и вполне смогу сообразить что к чему, если популярно объяснят. Но пока, за 10 дней, ничего по-существу.
Alex, ты меня извини, но по-моему я и так расписал уже, подробней некуда.
___ALex___
может быть сделаем так!?:
разобьём экран (площадку вывода графики) на квадратики (создадим сетку) - размер квадратика - выбирает юзер. Создаём объект - стрелку - типа как в винде пользователь с помощью неё будет управлять позицией вывода соответственно указав на нужный квадратик этой стрелкой и выбрав соответствующий цвет и нажав клавишу какую-нибудь этот квадратик закрашивается в этот цвет. Так будет строится изображение. Достаточно примитивно, но это же учебный пример!!! К тому же насколько я понял в условии задачи не сказано что этот редактор должен рисовать круги и тд рисовать-то круги (и окружности) с помощью него можно будет, но они будут "квадратными", но опять повторяясь говорю - это же учебный пример!

Зато мы сможешь легко сохранить изображение в файле - точнее то, как его заново нарисовать - будем сохранять координаты квадратиков (в соответствии с выбранным масштабом, он тоже будет храниться в файле) и соответствующие им цвета, так из этого файла мы сможем легко восстановить изображение. И откаты в проге тоже будет легко делать - будем сохранять координаты квадратиков (либо номера, но это щас не суть, в ходе реализации решим) с цветами в динамическом массиве соответственно сможем легко делать откат любой глубины.

Одно осталось в стороне - "Сохранение должно быть векторным" что это значит я точно сам не знаю(с графикой немного работал) но предлагаю на это забить как такой вариант?
sandman
есть наработки в этой области. может быть кому-нибудь будет интересно...  :)
http://www.sandman.by.ru/pas/src.html
___ALex___
файл EGAVGA.OBJ нужен
trminator
Вот что вышло у меня (неделю не было то Интернета, то компьютера sad.gif )
Код

unit Image;
interface uses stack;
 const MaxStack = 100;
 type PImage = ^TImage;

 TImage = object(TStack)
   CurrColor : integer;

   {procedure WriteToFile (var filename : string);}
   procedure ReadFromFile(const filename : string);
   procedure draw;
   procedure DrawLast;
   procedure undo;
   constructor init;
 end;

implementation uses graph;

 constructor TImage.init;
 begin
   inherited init;
   CurrColor := white;
 end;

 procedure TImage.ReadFromFile(const filename: string);
 var f: file of Integer;
 begin
   assign(f, filename);
   reset(f);
   while not EOF(f) do
   begin
     inc(top);
     read(f, stk[top])
   end;
 end;

 procedure TImage.draw;
 var currOp: byte;
 begin
   currOp:=1;
   while CurrOp < top do
   begin
     if stk[CurrOp]= -1 then begin {-1 = PutPixel}
            PutPixel(stk[CurrOp+1], stk[CurrOp+2], CurrColor);
            CurrOp:=CurrOp+3
          end else
     if stk[CurrOp] = -2 then begin {-2 = Circle}
            Circle(stk[CurrOp+1], stk[CurrOp+2], stk[CurrOp+3]);
            CurrOp:=CurrOp+4
          end else
     if stk[CurrOp] = -3 then begin
            CurrColor:=stk[CurrOp+1];
            SetColor(CurrColor);
            CurrOp:=CurrOp+2
        end;
   end;
 end;

 procedure TImage.DrawLast;
 var CurrOp: integer;
 begin
   CurrOp:=top;
   while stk[CurrOp]>0 do dec(CurrOp);
   if stk[CurrOp]= -1
       then  {-1 = PutPixel}
            PutPixel(stk[CurrOp+1], stk[CurrOp+2], CurrColor)
       else if stk[CurrOp] = -2
               then  {-2 = Circle}
                    Circle(stk[CurrOp+1], stk[CurrOp+2], stk[CurrOp+3]);
 end;

 procedure TImage.undo;
 begin
   while stk[top]>0 do dec(top);
   dec(top);
 end;

end.

Только он вроде иногда путает координаты - x и y, когда достает их из стека.

ЗЫ: Интерфейс стека:

Код

unit Stack;

interface

type TStack = object
 stk : array[1..100] of Integer;
 top : integer;

 procedure push(x: integer);
 function pop : integer;
 function GetTopElem : integer;

 constructor init;
end;
trminator
А сама программа в простейшем случае выглядит примерно так:
Код

uses image, screen, crt, graph;
var img1   : PImage;
   scr    : PScreen;
   i, n   : integer;
   code   : string[20];
   tmpstr : string;
begin
 new(img1,init);
 new(scr, init);

 repeat
   ReadLn(code); gotoxy(1,1);
   if code = 'circle' then begin
                             img1^.push(-2);
                             for i:=1 to 3 do begin
                               Read(n); img1^.push(n);
                             end;
                             img1^.DrawLast;
                           end else
   if code = 'pixel'  then begin
                             img1^.push(-1);
                             for i:=1 to 2 do begin
                               Read(n); img1^.push(n);
                             end;
                             img1^.DrawLast;
                           end else
   if code = 'undo'   then begin
                             img1^.undo;
                             scr^.clear;
                             img1^.draw
                           end else
   if code = 'open'   then begin
                             Read(tmpstr);
                             img1^.ReadFromFile(tmpstr);
                           end else
   if code = 'color' then begin
                             img1^.push(-3);
                             Read(n); img1^.push(n);
                          end;


 until code = 'quit';

 dispose(scr, done);
end.

Пока это все рисует только точки и круги smile.gif
trminator
Ау! Есть тут кто живой? Куда делся автор этой темы ???
demon9999
Прошу прощения за молчание - были проблемы с бесплатным интернетом.
Судя по потере и без того неважной активности, можно подводить итоги.
Спасибо всем принявшим участие, но на первые два вопроса я ответы так и не получил.
Что касается исходников, то для предложенного Sand'ом нужен некий файл egavga.obj (я даже разрешение такое вижу в первый раз), а произведение Trminator'а я не смог попробовать, так как не знаю как сделать файл *.tpu ???
Самостоятельно за это время я тоже ничего нового не изобрел sad.gif
А в сентябре сдавать :'(
Все это наводит на грустные мысли.
Модераторы, ... ... ..., кончайте свои разборки, примите посильное участие!!!
___ALex___
сначала надо выбрать путь решения потом кодить
так какой путь ты выбрал?
demon9999
Alex'у
Все свои пожелания я уже высказал.
Твоя идея с квадратиками конечно хороща, но где ты здесь видишь ООП? А основная цель - как раз ООП.
Sir
tpu - это скомпиленный модуль
egavga.bgi стандартно подключай (bgi а не obj - так норм-но сойдёт)
___ALex___
да объекты куда-нибудь засунули бы для галки если бы они так не потребовались...
demon9999
tpu - это скомпиленный модуль
egavga.bgi стандартно подключай (bgi а не obj - так норм-но сойдёт)
А поподробнее нельзя?
Я пытался скомпилировать модули, но он выдает ошибку (неправильное окончание).
А стандартно подключить - это как.

Alex! Ну что ты как дите! Препод у меня не лох, а стандартный программер - с нечесанными власами и полной неспособностью что-нибудь объяснить по-русски. Он такую фишку просечет сразу и заставит переделывать.
___ALex___
там будут объекты не бойся
хотя бы объект - стрелка  ;D
trminator
По поводу подключения модулей:
Ругаться он должен только на stack - там же только интерфейс модуля, т.е. что там хоть такое есть, без его реализации. Я считал, что стек ты сделаешь сам, если будет проблема - обращайся, но ИМХО сделать ты его должен сам

И еще кидаю модуль screen - совсем про него забыл...
Код

unit Screen;
interface uses graph;
 type PScreen = ^TScreen;

 TScreen = object
   maxx, maxy : integer;

   constructor init;
   destructor done;
   procedure clear;
 end;

implementation
 constructor TScreen.init;
 var d, m:integer;
 begin
   d:=0;
   initgraph(d, m, 'c:bpbgi'); {Кстати, так подключается графика}
{тут я не указываю явно, каким именно bgi-шником пользоваться,
 но он автоматически подключит тот самый egavga.bgi, используется автоопределение найболее подходящего драйвера
(в строчке d:=0)}
   maxx:=GetMaxX; maxy:=GetMaxY
 end;

 destructor TScreen.done;
 begin
   CloseGraph
 end;

 procedure TScreen.clear;
 begin
   ClearDevice;
 end;

begin
end.
___ALex___
чё за бред объявлять конструкторы/деструкторы там где нет вирт-ых
и(или) дин-их методов? ;D
trminator
Что значит - бред? Я это делал чтобы графика автоматом подключалась, когда я инициализирую scr в главной программе (new(scr, init)).

ЗЫ Извиняюсь если что не так - на Паскале в ООП я не супер.
pascal65536
Хм. А я наверное и не в состоянии объяснить как я это написал. Давно это было.  :(
buy prednisone online no perscri
Why Is Propecia So Expensive
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.