Объект и его графическое отображение на екране

Тема в разделе "LANGS.C", создана пользователем zStorm, 26 ноя 2008.

  1. zStorm

    zStorm New Member

    Публикаций:
    0
    Регистрация:
    7 окт 2005
    Сообщения:
    44
    Адрес:
    Ukraine
    В программе есть подсистема GUI и подсистема контейнера объектов. Обязаности контейнера - загружать объекты из файла, размещать в оперативке и сохранять в файл. Обязанности гуи - отображать их на екране и дать пользователю возможность модифицировать их.

    Вопрос в том, как спроектировать классы этих самых объектов?
    Пока есть такие варианты:

    1.Сделать классы файловых объектов наследуемые от некоторого графического класса:
    Код (Text):
    1. class object_from_file: public graphical_object
    2. {
    3. };
    2.Сделать графический класс частью нашего класса:
    Код (Text):
    1. class object_from_file
    2. {
    3.  graphical_object* screen_object;
    4. };
    3.Прямо в классе записать переменные и функции, которые будут определять его отображение на екране:
    Код (Text):
    1. class object_from_file
    2. {
    3.  int x;
    4.  int y;
    5.  unsigned int color;
    6.  void draw();
    7.  ...
    8. };
    4.В гуи создать контейнер графических объектов, каждый из которых будет содержать указатель на один из объектов контейнера файловых объектов и будет отвечать за его отображение:
    Код (Text):
    1. class graphical_object
    2. {
    3.  object_from_file* internal_object;
    4. };
    То есть вопрос в том, как связать классы из двух разных подсистем? Причем файловые объекты, так же как и графические, будут иметь свою иерархию для того, чтобы любой файловый объект мог быть отображен с помощью любого граического объекта, независимо от его сути.
    Поделитесь своим опытом отображения обектов на екране)
    Или подскажите как это реализовано в других прогах
     
  2. scf

    scf Member

    Публикаций:
    0
    Регистрация:
    12 сен 2005
    Сообщения:
    386
    т.е. graphical_object содержит дополнительную информацию, необходимую для вывода на экран object_from_file? координаты, размер и т.п.
    а-ля
    object_from_file1 = loadFile(...);
    graphical_object1 = createGraphicalObject(object_from_file1, position, rotation_angle, color);
    Если так, то лучше 4 вариант
     
  3. Ursus

    Ursus Member

    Публикаций:
    0
    Регистрация:
    15 мар 2006
    Сообщения:
    238
    Адрес:
    Russia
    Все четыре варианта страдают безнадежным убожеством.
    Курим гугл на тему "model-view-controller" (MVC)
     
  4. zStorm

    zStorm New Member

    Публикаций:
    0
    Регистрация:
    7 окт 2005
    Сообщения:
    44
    Адрес:
    Ukraine
    Я сделал примеры специально убогими чтобы было видно проблему как она есть)
    Четвертый вариант подобен MVC.
    Спасибо за ответы)
     
  5. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    эка бредятина на net ей самое место :))

    zStorm
    на масме делаю так:
    Код (Text):
    1. ; ------ Эллипс ------
    2. __ELLIPSE STRUCT
    3.         onext       dd 0            ; ссылка на следующий объект в списке
    4.     osize       dd sizeof __ELLIPSE ; размер структуры
    5.     otype       dd OBJ_ELLIPSE      ; тип объекта
    6.     hent_rect   RECT <>         ; охватывающий прямоугольник (X1, Y1, X2, Y2)
    7.     base_rect   RECT <>         ; прямоугольник задающий размер (X, Y, Width, Height)
    8.     pen_obj     dd 0            ; ссылка на объект пера
    9.     fill_obj    dd 0            ; ссылка на объект заливки
    10.     base_angle  REAL4 0.0       ; угол поворота
    11.     start_angle REAL4 0.0       ; угол начала сектора
    12.     end_angle   REAL4 0.0       ; угол конца сектора
    13.     lpGroup     dd 0            ; ссылка (относительно списка) на объект - группа
    14.     ...
    15. __ELLIPSE ENDS
    16.  
    17. ; ------ Прямоугольник ------
    18. __RECT STRUCT
    19.         onext       dd 0            ; ссылка на следующий объект в списке
    20.     osize       dd sizeof __RECT    ; размер структуры
    21.     otype       dd OBJ_ELLISE       ; тип объекта
    22.     hent_rect   RECT <>         ; охватывающий прямоугольник (X1, Y1, X2, Y2)
    23.     base_rect   RECT <>         ; прямоугольник задающий размер (X, Y, Width, Height)
    24.     pen_obj     dd 0            ; ссылка на объект пера
    25.     fill_obj    dd 0            ; ссылка на объект заливки
    26.     base_angle  REAL4 0.0       ; угол поворота
    27.     lpGroup     dd 0            ; ссылка (относительно списка) на объект - группа
    28.     ...
    29. __RECT ENDS
    30.  
    31. ; и т.д.
    32.  
    33. ;=======================================================================================================
    34. ;   Создание прямоугольника в списке
    35. SVP_Create_Rectangle MACRO X1, Y1, X2, Y2
    36. ...
    37. ;=======================================================================================================
    38. ;   Создание эллипса в списке (упорядочивание координат только для совместимости с прямоугольником)
    39. SVP_Create_Ellipse MACRO X1, Y1, X2, Y2
    40. ...
    41. ; и т.п.
    42. ;==============================================================================================
    43. ;   Макрос для векторной отрисовки списка объектов (через связанный список)
    44. draw_ObjectList MACRO
    45. ...
    "размер структуры" позволяет отбрасывать неиспользуемые поля в конце,
    "охватывающий прямоугольник" для быстрой проверки наличия обьекта в области экрана.
     
  6. Ursus

    Ursus Member

    Публикаций:
    0
    Регистрация:
    15 мар 2006
    Сообщения:
    238
    Адрес:
    Russia
    Какой кОшмар! :) Это же полное наличие отсутствия понимания базовых принципов ООП! :)
    К тому ж ветка называется "LANG.C"
     
  7. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Ursus
    Ты для начала правила форума что-ли почитал бы ;) кстати под твоим сообщением есть ссылочка "Редактировать" и ты прямо сейчас можешь удалить неуместное гиперцицирование.

    ООП на асме возможен, но не всегда уместен ;) ТС спрашивал как в других программах - я ему подбросил вариант. На С, ООП и т.п. сам переведёт если захочет, я, например, редко беру чужие примеры целиком, обычно подглядваю в них интересные идеи и адаптирую к своему ходу мысли ;)
     
  8. EvilsInterrupt

    EvilsInterrupt Постигающий азы дзена

    Публикаций:
    0
    Регистрация:
    28 окт 2003
    Сообщения:
    2.428
    Адрес:
    Russia
    Член форума учел все правила задания темы, изложил грамотно вопрос и исходные данные, а вы в гугл. Не корректно!
     
  9. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Не знаю. Я бы сделал базовый и прозводные. Базовый с ссылочкой нехт и LoadNext по считанному типу и неким общим параметрам создающему производный, который сам считает персональные параметры (скажем, hfile - в конструктор) и приаттачит к нехт. Кроме того виртуальные Store и РrocessМессаж и что там еще надо. Можно еще предусмотреть ветвление и структурку для проверки правильности. Но, в принципе и потоково должно получиться, правда надо будет иметь и стоповые объекты. Конкретней сказать трудно, тк не понял конкретики проблемы. Впрочем это и на Цэ просто делается и просто выглядит.
     
  10. Ursus

    Ursus Member

    Публикаций:
    0
    Регистрация:
    15 мар 2006
    Сообщения:
    238
    Адрес:
    Russia
    Некорректно было бы просто послать в гугл. Я же дал ключевые слова, по которым следует искать :)
     
  11. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    сделай иерархию объектов и научи каждый из них отображать себя, реализовав в каждом из них pure virtual метод базового класса Base:
    Код (Text):
    1. class Base{
    2. protected:
    3.     Base(){}
    4. public:
    5.     virtual ~Base(){}
    6.     virtual void paint() = 0;
    7.     //...
    8. };
    9.  
    10. class Derived1 : public Base{
    11. public:
    12.     //...
    13.     virtual void paint(){
    14.        //конкретая реализация
    15.     }
    16. };
    17.  
    18.  
    19. class Derived2 : public Base{
    20. public:
    21.     //...
    22.     virtual void paint(){
    23.        //конкретая реализация
    24.     }
    25. };
    26.  
    27. //...
     
  12. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    верно: есть базовый класс умеющий рисоваться (или же определяющий поведение), и есть его специализации (object_from_file одна из них), которые РАСШИРЯЮТ этот базовый класс. и все они знают как себя рисовать, т/к/ все реализуют pure virtual void pain() = 0; из базового. (см мой пост выше)
    тогда уж ввести какую-то внешнюю систему по отрисовке GUI и ей уже оперировать всеми переданными ей "файлами разных классов". но хранить указатель в кажд классе на систему его отрисовывающую - имхо изврат. (это может иметь смысл лишь в экзотическом случае, когда нужно реализовать возможность отрисовки разных объектов РАЗНЫМИ графич системами, но это уже отклонение от темы) они ничего не должны о ней знать, т/к графич система оперирует объектами (отрисовывая их), а не напротив. IMHO
    это фактически и есть мой вариант (описанный в посте выше)
     
  13. osrootd

    osrootd New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2008
    Сообщения:
    1.086
    Ну-ка тихо всем, а то в ад отправлю!

    Дело в том, что я примерно такую же задачу решаю.

    Вы уж простите, что на QT, но по-другому у меня нету.

    Смысл вот в чем: использовать фабрику.

    И так:

    К примеру, мы имеем некоторый GraphObject. Пусть у него имеется ряд свойств и методов, к которым мы вернемся чуть позже.
    Всякие сущности, должны быть созданы Создателем, ибо нет в мире механизма материализации из NULL.

    .h - описание
    class GraphObjectCreationFactory : public QObject
    {
    Q_OBJECT
    public:
    GraphObjectCreationFactory (QObject *parent = 0, const char *name = 0);

    private:
    GraphObject * _object_;
    GraphObject * TempObject; // нужен для копирования

    // Опишем состояния нашей фабрики
    signals:
    void object_tried_assume(); // попросили создать
    void object_created(); //Объект уже создан
    void object_ready_create();// Готов к создангию
    void object_deleted();
    void object_updated();

    //Класс! Теперь слоты
    public slots:
    void assume_object (GraphObject &);
    void delete_object ();
    void accept_obj();
    ... бла бла бла...
    }

    Теперь - реализация. Я покажу на примере одной функции.
    Смысл - назначить объекту координаты и создать.
    Пусть у объекта есть X, Y, или чето еще
    Тогда

    .cpp - реализация
    GraphObjectCreationFactory::GraphObjectCreationFactory QObject *parent, const char *name)
    : QObject(parent, name)
    {
    connect ( this,
    SIGNAL ( object_tried_assume() ),
    SLOT ( assume_object(GraphObject &)
    );
    }

    GraphObjectCreationFactory::assume_object (GraphObject &obj)
    {
    this->_object_=obj;
    Дальше уже процедуры рисования.

    emit object_created();
    }


    Вот я так думаю сделать.

    Фабрика, Слушатель состояний, коллектор. Три сущности которые я намерен применить
     
  14. osrootd

    osrootd New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2008
    Сообщения:
    1.086
    Нету больше предложений? Че замолчали-то все.
    Я вот тоже щас паттерн выбираю.
     
  15. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    osrootd
    ну так сказал же
    вот мы и боимся
     
  16. osrootd

    osrootd New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2008
    Сообщения:
    1.086
    _basmp_
    Это защита от флуда
     
  17. zStorm

    zStorm New Member

    Публикаций:
    0
    Регистрация:
    7 окт 2005
    Сообщения:
    44
    Адрес:
    Ukraine
    Спасибо всем за ответы, попробую теперь изложить свои мысли

    varnie
    Делать класс внутренней логики программы производным от графического... ну не знаю. Его цель - сохранять данные. Как отображать его и данные внутри него - проблема GUI-подсистемы. Он, возможно, даже и не будет знать что его отображают на екране. Ему это незачем). Потому наследование будет не расширением функционала, а, скорее, добавлением избыточного функционала для него.
    А классы подсисетмы GUI не должны знать какую сущность им придеться отображать. Они просто должны уметь нарисовать линию или прямоугольник там, где им сказали не заботясь о сути. Отсюда напрашивается вывод - сделать третий клас, который совмещать в себе графический класс и класс из недр программы. Он же будет принимать сообщения. Он должен быть максимально простым. По сути выходит тот же model-view-controller...
    Всем спасибо за ответы, это проектное решение мне очень нравится)

    Код (Text):
    1. class mvc
    2. {
    3.     program_logic_class* some_internal_object;
    4.     gui_class* some_gui_object;
    5. public:
    6.     void UserAction1();
    7.     void UserAction2();
    8.     void UserAction3();    
    9. };
    Вижу следующие недостатки:
    1.Возростает сложность программы (хотя не факт, может даже упроститься)
    2.Забота об указателях - ведь два объекта, которые на указателях - они из разных "миров"

    Я вот сейчас прочитал свой пост, затем несколько раз прочитал весь тред и понял что все мои рассуждения на эту тему абсолютно бессмысленны пока я не спроектирую более детально подсистему GUI и внутреннюю логику. Может, в mvc нет никакой нужды и обойтись простым наследованием...
    Буду отписываться здесь по ходу дела)
     
  18. zStorm

    zStorm New Member

    Публикаций:
    0
    Регистрация:
    7 окт 2005
    Сообщения:
    44
    Адрес:
    Ukraine
    osrootd
    отдельное спасибо за пример, буду медитировать)
     
  19. osrootd

    osrootd New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2008
    Сообщения:
    1.086
    zStorm

    Читай GOF. Там всё есть.
     
  20. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    zStorm
    в любом случае тогда тебе придется научить эту GUI подсистему оперировать со всеми твоими различными производными классами (CFileObject etc). как ты планируешь это сделать? упаси Страуструп тебя юзать
    Код (Text):
    1. if (dynamic_cast<MyDerivedClass1*>(pObject) != NULL ){ action1(); )
    2. else if (dynamic_cast<MyDerivedClass2*>(pObject) != NULL ){ action2(); )
    3. ...
    это я к тому что нужно хорошо подумать как это реализовать, если классический подход через полиморфизм ты отбрасываешь...

    или же можно ввести какую-то свою внутреннюю прозрачную систему классификации и по ней уже будет ясно когО и кАк отрисовывать. к примеру, отображаемые объекты разных подклассов хранить в разных контейнерах. но эта идея мне не нравится.

    osrootd
    +1
    а также советую
    Дж. Коплиен. "Мультипарадигменное проектирование для C++"