Russian Qt Forum
Ноябрь 22, 2024, 15:39 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Объект умеет сам себя рисовать?  (Прочитано 13701 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Апрель 17, 2017, 14:17 »

Добрый день

Получилось как-то совсем некрасиво (псевдокод)
Код
C++ (Qt)
void СWindow::Draw( ... )
{
for (int i = 0; i < mObjects.size(); ++i) {
  CObjectParam1 * param1 = dynamic_cast<CObjectParam1 *> (mObjects[i]);
  if (param1) {
   DrawObjectsParam1(param1);
   continue;
  }
 
// то же для  CObjectParam2  
  CObjectParam2 * param2 = dynamic_cast<CObjectParam2 *> (mObjects[i]);
  if (param2) {
   DrawObjectsParam2(param2);
   continue;
  }
 
// то же для  CObjectParam3
 ...
 и.т.д.
 
Типов CObjectParam-xxx не так уж много (< 10), можно просто перетерпеть, но как-то уж очень коряво. Напрашивается сделать как в классическом примере ООП с фигурами, объявив виртуальный Draw
Код
C++ (Qt)
void СWindow::Draw( ... )
{
for (int i = 0; i < mObjects.size(); ++i) {
  mObjects[i]->Draw(...);
}
 
Однако я быстро убедился что в данном случае это никуда не годится. Дело в том что классы CObjectParam-xxx очень маленькие, напр
Код
C++ (Qt)
// базовый
struct CObjectParam {
 СOpenGLObject * mObject;   // рисуемый объект
 QMatrix4x4 mMatrix;          
};
 
// один из наследников
struct CObjectParam1 : public  CObjectParam  {
 Color mColor;
};
 
Т.е. это просто не более чем 2-3 "опции". С др стороны класс СWindow обширный, имеет десятки методов и неск наследников. Поэтому получив упр-е в виртуальном Draw, классам CObjectParam-xxx нечего делать, весь ф-ционал рисования (работа с СOpenGLObject и.т.п.) сосредоточен в СWindow, да и большинство опций задаются там же (для окна), лишь несколько в CObjectParam

Да, ну и как же сделать правильно?

Спасибо
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #1 : Апрель 17, 2017, 20:25 »

Ну если вся отрисовка так или иначе в CWindow - как вариант, можно добавить в CObjectParam что-то типа virtual int getId() const;
Тогда каждый наследник вернет свой id, а в СWindow::Draw() вместо кучи динамик-кастов появится один свитч по этим id.

Либо вместо id возвращать набор флагов, которые бы указывали, какой параметр можно использовать для отрисовки.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #2 : Апрель 18, 2017, 10:46 »

Унифицируйте хранение параметров.
Храните их, например, в QVariant-e.
Код
C++ (Qt)
struct CObjectParam {
 СOpenGLObject * mObject;
 QVariantList params;          
};
 
Записан

Qt 5.11/4.8.7 (X11/Win)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Апрель 18, 2017, 11:54 »

Либо вместо id возвращать набор флагов, которые бы указывали, какой параметр можно использовать для отрисовки.
id или флагами не отделаться, наследники CObjectParam могут иметь хранимые данные (напр контейнер mColor). Примеры

- СObjectParam этот объект надо просто рисовать, только учитывая установки окна (напр с заливкой или без)

- СObjectParam1 - а этот надо рисовать игнорируя освещенность и используя хранимый mColor. И в одном из режимов (задаваемых для окна) нужно дорисовать wireframe поверх заливки

и.т.д.  штук 8 таких вариантов набегает

Унифицируйте хранение параметров.
Храните их, например, в QVariant-e.
Примерно так и было до того как я создал эту серию мелких классов CObjectParam_xxx (не уверен что это верное решение). Ну и был один CWindow::DrawObjectsParam на всех, капитально запутанный, все if'ы были свалены туда, вставить каждый новый случай превращалось в мучение
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #4 : Апрель 18, 2017, 13:38 »

Ну и был один CWindow::DrawObjectsParam на всех, капитально запутанный, все if'ы были свалены туда, вставить каждый новый случай превращалось в мучение
Регистрируйте обработчики (std::function) на каждый тип параметра и вызывайте уже их при отрисовке. Через те же лямбды всё можно упростить.
Записан

Qt 5.11/4.8.7 (X11/Win)
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #5 : Апрель 18, 2017, 15:19 »

id или флагами не отделаться, наследники CObjectParam могут иметь хранимые данные (напр контейнер mColor).

Ну это почти аналог QStyleOption. Там тоже хранятся данные и эти структуры имеют также int type.
Думаю, можно смело пойти этим путем)
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Апрель 18, 2017, 16:32 »

Регистрируйте обработчики (std::function) на каждый тип параметра и вызывайте уже их при отрисовке. Через те же лямбды всё можно упростить.
Я понял, ну это "синтаксический сахар", я имел ввиду может как-то принципиально, напр перепланировать классы (хотя не вижу как)

Ну это почти аналог QStyleOption. Там тоже хранятся данные и эти структуры имеют также int type.
Да, действительно, ситуация похожа, как-то не подумал об этом
Думаю, можно смело пойти этим путем)
Каким "этим"? Что я помню из исходников стилей - меня совсем не вдохновляет (суровый процедурный стиль и кастование)
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #7 : Апрель 18, 2017, 17:17 »

Я понял, ну это "синтаксический сахар", я имел ввиду может как-то принципиально, напр перепланировать классы (хотя не вижу как)
Похоже Вы меня не поняли.
Я имел в виду, что достаточно будет иметь только один CObjectParam, в котором будут заданы все параметры для отрисовки.
Плюс набор обработчиков для каждого типа параметров.
Код
C++ (Qt)
struct CObjectParam {
 COpenGLObject * mObject;
 QVariantList mParams;          
};
 
void CWindow::registerParamProcessor( int type, std::function< bool( CObjectParam* o, const QVariant& v ) > f )
{
  mParamProcessors[ type ] = f;
}
 
void CWindow::Draw( ... )
{
for (int i = 0; i < mObjects.size(); ++i) {
  auto& obj = mObjects[i];
  for( auto& v : obj->mParams ) {
     auto f = mParamProcessors[ v.userType() ];
     if( !f( obj, v ) )
         break;
  }
}
}
« Последнее редактирование: Апрель 18, 2017, 17:21 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Апрель 20, 2017, 12:12 »

Я имел в виду, что достаточно будет иметь только один CObjectParam, в котором будут заданы все параметры для отрисовки.
За это придется заплатить "дешифрированием" mParams в runtime. Может сделать указатель на метод-обработчик СWindow членом базового класса CObjectParam? напр
Код
C++ (Qt)
typedef bool CWindow::(*TDrawObject)( CObjectParam * );
struct CObjectParam {
 СOpenGLObject * mObject;
 QMatrix4x4 mMatrix;          
 TDrawObject mDrawer;
};
Но тут небольшие неудобства. Во-первых если метод рисует конкретного наследника (напр  CObjectParam1), то хотелось бы его и подавать (а не приводить от базового). Во-вторых, есть ситуация (правда всего одна) когда метод рисования имеет еще один параметр. Может тогда как-то через "туплы"?

Какой-то острой необходимости в этом нет, корявенький теперешний код вполне устраивает, просто интересно как же "по уму"  Улыбающийся
« Последнее редактирование: Апрель 20, 2017, 12:13 от Igors » Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #9 : Апрель 20, 2017, 13:25 »

Каким "этим"? Что я помню из исходников стилей - меня совсем не вдохновляет (суровый процедурный стиль и кастование)

Я имел в виду - проверять поле типа и в зависимости от него брать нужные параметры.
Ну, статик каст придется сделать, но эта операция ничего не стоит.
(Ну или, как вариант, можно параметры представить в виде QVariant - но это на любителя)
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #10 : Апрель 20, 2017, 14:49 »

Я имел в виду - проверять поле типа и в зависимости от него брать нужные параметры.
Ну, статик каст придется сделать, но эта операция ничего не стоит.
(Ну или, как вариант, можно параметры представить в виде QVariant - но это на любителя)
Для чего все эти сложности? Улыбающийся

Если рисование обеспечивается средствами CWindow, можно просто передавать ссылку на него в параметре метода draw:
Код
C++ (Qt)
struct CObjectParam
{
 СOpenGLObject * mObject;   // рисуемый объект
 QMatrix4x4 mMatrix;          
 
 virtual void draw( CWindow &surface ) const = 0;
};
 
// один из наследников
struct CObjectParam1 : public  CObjectParam
{
 Color mColor;
 
 virtual void draw( CWindow &surface ) const { surface.DrawObjectsColor( mColor ); }
};
 
struct CObjectParam2 : public  CObjectParam
{
 Texture mTex;
 
 virtual void draw( CWindow &surface ) const { surface.DrawObjectsTexture( mTex ); }
};
 

Код
C++ (Qt)
void СWindow::Draw( ... )
{
 for (int i = 0; i < mObjects.size(); ++i)
 {
   mObjects[i]->draw( *this );
 }
}
 
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #11 : Апрель 20, 2017, 15:09 »

Я имел в виду - проверять поле типа и в зависимости от него брать нужные параметры.
Ну, статик каст придется сделать, но эта операция ничего не стоит.
(Ну или, как вариант, можно параметры представить в виде QVariant - но это на любителя)
Для чего все эти сложности? Улыбающийся

Так я насколько понимаю проблему - Igors как раз хочет избежать множества виртуальных Draw.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #12 : Апрель 20, 2017, 15:23 »

Так я насколько понимаю проблему - Igors как раз хочет избежать множества виртуальных Draw.
Тогда проще не использовать C++. Улыбающийся
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #13 : Апрель 20, 2017, 20:38 »

Так я насколько понимаю проблему - Igors как раз хочет избежать множества виртуальных Draw.
Тогда проще не использовать C++. Улыбающийся

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

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #14 : Апрель 20, 2017, 21:38 »

все-таки тупой свитч и статик-каст отработают +несколько+ быстрее...
Чем вызов виртуального метода? Сильно сомневаюсь.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.265 секунд. Запросов: 23.