Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Подземелье Магов
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  10:08[Войти] | [Зарегистрироваться]

Обсуждение материала
Контейнер визуальных объектов
Полный текст материала


Другие публикации автора: Юрий Спектор

Цитата или краткий комментарий:

«... Рассмотрим достаточно распространенную практическую задачу: необходимо реализовать визуальный контейнер, на котором размещаются графические объекты. Эти объекты должны быть не только нарисованы на поверхности этого контейнера, но и доступны пользователю для различных манипуляций, таких как выделение, перемещение с помощью мыши и др. Объекты могут быть разнотипными, следовательно, они будут по-разному выглядеть, характеризоваться различными параметрами. Набор операций, которые можно совершать по отношению к ним, также будет различным. ...»


Важно:
  • Страница предназначена для обсуждения материала, его содержания, полезности, соответствия действительности и так далее. Смысл не в разборке, а в приближении к истине :о) и пользе для всех.
  • Любые другие сообщения или вопросы, а так же личные эмоции в адрес авторов и полемика, не относящаяся к теме обсуждаемого материала, будут удаляться без предупреждения авторов, дабы не мешать жителям нормально общаться.
  • При голосовании учитывайте уровень, на который расчитан материал. "Интересность и полезность" имеет смысл оценивать относительно того, кому именно предназначался материал.
  • Размер одного сообщений не должен превышать 5К. Если Вам нужно сказать больше, сделайте это за два раза. Или, что в данной ситуации правильнее, напишите свою статью.
Всегда легче осудить сделанное, нежели сделать самому. Поэтому, пожалуйста, соблюдайте правила Королевства и уважайте друг друга.



Добавить свое мнение.

Результаты голосования
Оценка содержания

  Содержит полезные и(или) интересные сведения
[1]1995%
 
  Ничего особенно нового и интересного
[2]15%
 
  Написано неверно (обязательно укажите почему)
[3]00%
 
Всего проголосовали: 20

Оценка стиля изложения

  Все понятно, материал читается легко
[1]1990.5%
 
  Есть неясности в изложении
[2]29.5%
 
  Непонятно написано, трудно читается
[3]00%
 
Всего проголосовали: 21




Смотрите также материалы по темам:
[GDI, рисование на канве]

Комментарии жителей
Отслеживать это обсуждение

Всего сообщений: 82

11-04-2012 15:06
сообщение от автора материала
Кстати, у "контейнера визуальных объектов" - EasyCAD - есть свой сайт: http://easycad-lib.com Не сочтите рекламой, к автору не имею никакого отношения. А у уважаемого автора хочу поинтересоваться: как спроектировали это чудо? Может, посоветуете литературу какую? Хочу также научиться :)

Здравствуйте! Спасибо за отзыв! Проект, который начинался всего лишь с обучающей статьи, действительно разросся, последние годы моя работа так или иначе связана с "Контейнером визуальных объектов". :) Если есть к теме повышенный интерес и желание пообщаться, можете обращаться в личку, по электронной почте, или скайпу, на сайте есть мои контакты :) Что касается проектирования, литературы на этот счет полно, и хорошей, но мое мнение, что читать ее нужно уже тогда, когда и сам до всего созрел, только лишь с целью навести порядок у себя в голове, разложить все по полочкам. Так что Geo прав:

Постоянно отвечая на Круглом Столе на вопросы о том, как создать редактор схем :D

Типа того :) Не сочтите за рекламу Круглого стола. Хотя, почему же... Сочтите! :)
 Ins


11-04-2012 12:43
>>> как спроектировали это чудо?
Постоянно отвечая на Круглом Столе на вопросы о том, как создать редактор схем :D

P.S. Я тоже не автор
 Geo


11-04-2012 12:37
Кстати, у "контейнера визуальных объектов" - EasyCAD - есть свой сайт: http://easycad-lib.com Не сочтите рекламой, к автору не имею никакого отношения. А у уважаемого автора хочу поинтересоваться: как спроектировали это чудо? Может, посоветуете литературу какую? Хочу также научиться :)


11-04-2012 06:09
сообщение от автора материала
Что-то у меня исходный контейнер визуальных объектов не работает (((
Delphi 7, выдает сообщение "Error Reading Form. Class TVisualContainer not found...". и потом при попытке компиляции "Field Form1.VisualContainer1 does not have a corresponding component". Не могу понять, в чем дело - исходник на месте!


Здравствуйте! Установите пакет VisCont.dpk из исходников к статье
 Ins


07-04-2012 17:39
Что-то у меня исходный контейнер визуальных объектов не работает (((
Delphi 7, выдает сообщение "Error Reading Form. Class TVisualContainer not found...". и потом при попытке компиляции "Field Form1.VisualContainer1 does not have a corresponding component". Не могу понять, в чем дело - исходник на месте!


22-12-2010 06:10
сообщение от автора материала
Либо где-то у вас ошибка, либо возможно дело в том, что я там в коде поставил проверку, что 0-я вершина должна быть всегда выше и левее 1-й. Проверьте, не пытаетесь ли вы сделать инач, либо просто уберите эту проверку
 Ins


22-12-2010 06:06
В целом разобрался, блок рисуется но vertex[0]и vertex[1] почему то не реагирует на координату "Y" Тоесть врехняя грань блока всегда на верхней границе VisualContainer хотя 2 и 3 вершины двигаюся. Масштаб не помогает. Пока не пойму в чем дело.


22-12-2010 04:42
Спасибо большое! Буду разбираться.


22-12-2010 03:33
сообщение от автора материала
Block.Vertex[2] := Pt;

Наверное там с нуля нумерация вершин, так что на Block.Vertex[1] и Block.Vertex[0] исправьте соответственно
 Ins


22-12-2010 03:32
сообщение от автора материала
В программе

Не совсем, примерно так (пишу код прямо сюда, чуть что подправьте):

var
  Block: TBeginEndBlock;
  Pt: TFloatPoint;
begin
  Block := TBeginEndBlock.Create;
  Pt.X := 200;
  Pt.Y := 200;
  Block.Vertex[2] := Pt;
  Pt.X := 100;
  Pt.Y := 100;
  Block.Vertex[1] := Pt;
  VisualContainer.AddObject(Block);

 Ins


22-12-2010 01:34
Что то типо такого?
добавить в контейнере
procedure TVisualContainer.addobject (incomingObject: TBaseVisualObject);
begin
  Selected := FObjects.Add(incomingObject);
  Invalidate;
end;

В программе
procedure TForm1.btn1Click(Sender: TObject);
begin
  VisualContainer1.ObjectType := TVisualObjectClass((Sender as TComponent).Tag);
  VisualContainer1.Objects.Create;
  ??????настраиваем параметры и положение еще бы понять как.
  VisualContainer1.addobject;
end;

Что то голова вообще перестала соображать все забыл (((


21-12-2010 09:30
сообщение от автора материала
1. Чуть-чуть доработайте контейнер, чтобы объекты в него можно было вставлять в ран-тайм, достаточно простого метода AddObject, который принимает объект параметром, заносит его в список FObjects и вызывает перерисовку (Invalidate).
2. Создаем объект вызовом конструктора Create, настраиваем параметры, положение, и добавляем в контейнер методом AddObject
 Ins


20-12-2010 06:10
Давно искал что то подобное однако уровня моего программирования явно не хватает. Может приведет кто нибудь пример как мне нарисовать пару блоков с линией используя этот контейнер но не вручную а из программы.


29-11-2010 10:55
сообщение от автора материала
Поясню. Типов объектов много, каждый тип может выполнять свои специфические действия. Хотелось иметь возможность через интерфейс базового предка всех объектов уметь эти действия выполнить без необходимости проверять и приводить типы. Не знать конкретный тип объекта, с которым работаешь, иногда полезно, это уменьшает количество жестких связей в системе и код нашего контейнера не нужно жестко на этих типах завязывать.
Использование сообщений через Dispatch позволяет реализовать этот подход - мы любому объекту можем отправить любую команду, если он ее обрабатывает - он ее обработает, иначе - вызовет DefaultHandler, в котором можно либо ничего не делать, либо как-нибудь обработать ситуацию. Я не настаиваю что такой подход лучше чем просто объявить пару методов, нет, он лучше в том случае, если нужна универсальность, но за нее нужно платить тем, о чем Вы говорите
 Ins


26-11-2010 07:34
Для чего нужно было использовать отправку "сообщений"?
Придумывать как в 2 параметра SendMessage "запихнуть" нужную информацию для отправки.
Делать кучу структур, типа TVOCBeginDrag.

Ведь можно было бы сделать функции, типа:


Type
  TDisplayObj = class
  Public
    Procedure OnStart(X, Y: LongInt);
    Procedure OnMove(X, Y: LongInt);
    Procedure OnEnd(Align: LongInt = 0);
  End;

  // Объект рассчитан на конкретную задачу, вывода блок-схем.



 exo


18-04-2010 02:39
Спасибо за статью :)
Я в ближайшем будущем планирую заняться чем-то подобным (ради спортивного интереса), поэтому изучаю, что существует в природе. Бесплатные компоненты, которые мне уже довелось посмотреть, используют, на мой взгляд, принципиально не правильный подход (объекты наследуются от TGraphicControl, в качестве контейнера - TScrollBox или что-то вроде того) - очень непрозрачное управление объектами, жуткие тормоза прорисовки при большом кол-ве объектов.

А тут как раз всё абстрагировано, то что надо :)

Исходники я ещё не смотрел, но уже созрело такое замечание/предложение. У Вас у объектов хранятся координаты базовых вершин, при перемещении объекта надо изменять их все. А что, если положение объекта (координаты X,Y первой базовой вершины + возможно коэффициенты трансформации, угол поворота объекта и т.п.) хранить в контейнере (или в родительском объекте), а все вершины самого объекта будут хранить координаты относительно первой вершины объекта (причём саму вершину хранить не надо, у неё координаты (0,0))?
Понимаю, что в таком случае усложняется контейнер - надо хранить не только объект, но и его положение (+ возможно, его трансформации относительно контейнера - сразу на ум приходит необходимость структуры, которая будет хранить ссылку на объект, координаты 1й вершины и прочие коэффициенты трансформации и наклона). Усложнится процедура конвертирования координат, может быть что-то ещё.
Но с точки зрения объекта - как бы это выразиться... объект будет сам в себе, а для внешнего мира достаточно передать свою ширину и высоту (чтобы нарисовать прямоугольник выделения). Станет гораздо проще создавать сложные объекты (состоящие из большого числа графических примитивов).

Вобщем, мне кажется, такой подход может быть оправдан, надо будет ещё подумать над всем этим (а главное - над постановкой задачи :))...


29-01-2010 07:23
сообщение от автора материала
Понятно. Возможно в ней юнит Themes отличается от того, что в более поздних. К сожалению, нет этой версии чтобы проверить, но судя по всему оно так. Функции из этого юнита используются в редакторах свойств для рисования элементов управления в стиле XP. Замените просто их вызовы на что-нибудь более классическое, DrawFrameControl, например
 Ins


29-01-2010 05:35
Какая у вас версия Delphi?
Delphi 7


28-01-2010 04:18
сообщение от автора материала
Undeclared identifier: 'ThemeControl'

Какая у вас версия Delphi?
 Ins


26-01-2010 04:07
Здравсвуйте! При компиляции пакета выдает следующие ошибки:
  [Error] ECADPropertyEditors.pas(627): Undeclared identifier: 'ThemeControl'
  [Fatal Error] ECADObjectInspector.pas(9): Could not compile used unit '..\Sources\CommonControls\ECADPropertyEditors.pas'


15-12-2009 05:05
сообщение от автора материала
Александр Щукин, спасибо за интерес к данной теме! Насчет Вашего кода - там действительно несмотря на функциональную схожесть, решения совсем другие, общего, с первого взгляда, не так уж и много. Вы можете связаться со мной по ICQ, тогда бы мы могли с вами обсудить примененные в наших проектах подходы и приемы, обменяться мнениями на этот счет :)
 Ins


14-12-2009 14:43
Новая ссылка на исходники SimpleCAD: http://depositfiles.com/files/hiaw2f866 (проверено - вирусов нет)

Понимаю, что программа в зачаточном состоянии и сырая. Просто хочется ее показать. Буду рад любым отзывам, советам и критике


14-12-2009 13:50
>>> Не стыдно, гражданиа Щукин, глистами народ пугать?

Простите великодушно! Моего злого умысла здесь и не было. Просто мой антивирус почему-то его не видит.
А в общем, этот глист, насколько я знаю безвреден, сильный дискомфорт ощущаться не должен.

Еще раз перед всеми извиняюсь. Сылку на файл удалил. Выложу заново, как только избавлюсь от этого вируса


14-12-2009 13:19
"Гражданин Щукин" в данном случае не злоумышленник, а жертва. Это тот самый Win32.Induc, заражающий саму Delphi, который был выявлен на Королевстве.
Подробности в новостях
http://delphikingdom.com/news/index.asp?Day=12&Month=8&Year=2009

В блоге Александра Алексеева (главного охотника)
http://gunsmoker.blogspot.com/2009/08/delphi-delphi.html

to Александр Щукин:
Настоятельно рекомендую прочитать приведенные ссылки, а потом принять меры у себя. В частности, пересобрать все проекты. Иначе Вы несете угрозу для собратьев по оружию -- программистов Delphi, так как единственное, что делает данный зловред, -- заражает Delphi.
 Geo


14-12-2009 11:18
Да, Аваст тоже нашел червячка. Не стыдно, гражданиа Щукин, глистами народ пугать?


14-12-2009 09:59
На всякий случай будьте внимательней. Майкросовтовский антивирус ругнулся.
 riff


14-12-2009 06:22
Здравствуйте Ins!

Приблизительно год назад, когда Вы опубликовали эту статью я тоже заразился идеей о создании векторного редактора. С тех пор в свое свободное время также занимаюсь разработкой похожей программы (по воли случая даже название похоже - SimpleCAD).
За основу я конечно же взял Вашу идею с логической канвой. Дальше разработка программы пошле несколько инным путем. Основной упор я делал на создание редактора для машиностроительного черчения (хотя на данном этапе разработки, наверное, трудно об этом догадаться :) ).

Буду Вам очень признателен, если выскажите свое мнение о программе.

Ссылка для скачивания исходников: http://depositfiles.com/files/p15eoguqy
В этом же архиве есть общая диаграмма классов, построенная в Rational Rose 7.0.0.

PS
по образованию я не программист, по этому не судите строго :)


07-11-2009 03:51
сообщение от автора материала
Как смотрит автор на то, что исходники, приложенные к статье, будут взяты за основу коммерческого приложения?

На здоровье! :)
 Ins


07-11-2009 02:09
Как смотрит автор на то, что исходники, приложенные к статье, будут взяты за основу коммерческого приложения?


06-11-2009 14:13
сообщение от автора материала
Зависает при открытии VisCont.dpk, даже компилится запустить не могу ((
Может вышлите на мыло обновлённый вариант (ladyshack@yandex.ru).


Интересный эффект, даже не знаю чем это может быть вызвано. Попробуйте не использовать это пакет, а создайте свой и включите в него файлы из статьи. Что касается обновленного варианта, то с момента публикации данные файлы никак не редактировались, т.е. у вас последняя версия примера.
 Ins


06-11-2009 12:58
Добрый день.
Статья очень нужная и полезная, вот только проблема с исходниками. Загрузила, а открыть в Д2005 не получается. Зависает при открытии VisCont.dpk, даже компилится запустить не могу ((
Может вышлите на мыло обновлённый вариант (ladyshack@yandex.ru).
Спасибо.


31-10-2009 12:59
сообщение от автора материала
мордехай вулкан, я обновил файлы, попробуйте новые
 Ins


31-10-2009 10:12
сообщение от автора материала
мордехай вулкан, тут я вам точно ничего сказать не могу, у меня подобные ошибки не воспроизводятся, что-то возможно не так в вашей версии. Единственное что могу предложить - свяжитесь со мной по мылу, могу выслать свое.

Новая версия значительно более "задумчивая", чем первая, приложенная к статье.

Но это еще не готовый к использованию вариант, а предварительный, для тестирования
 Ins


31-10-2009 06:45
Тогда уж сразу, в догонку. Новая версия значительно более "задумчивая", чем первая, приложенная к статье.


31-10-2009 06:42
Ок, скомпилировал. Теперь сразу при запуске cкомпилированной программы выдает: Could not convert variant of type(OleStr) into type(Double)

Далее, попытка создания нового листа влечет: Access violation at adress 004DED7E in module 'DiagramDesigner.exe'. Read of address 00000278.

Создаю объект. Навожу на него мышь:  Range check error. На этом пока тестирование останавливаю.


30-10-2009 11:22
сообщение от автора материала
мордехай вулкан, странно, там действительно была такая ошибка, но вроде бы я заливал ее исправление. Что сделать, чтобы ее исправить: занесите реализацию метода внутрь этой директивы, вот так:

{$IFDEF SPACEANGLE}
procedure TECADPluginObject.RotatePoint(Point1, Point2: TECADFloatPoint);
begin
  Host.RotatePoint(Point1, Point2);
end;
{$ENDIF}



Вообще, может в Вашей версии есть еще подобные ошибки, просто проследите, чтобы метод, который объявлен в интерфейсной части юнита под этой директивой, был внутри нее и в секции implementation, и  наоборот, если в интерфейсной части метод не под этой директивой, то и в implementation он должен быть не внутри IFDEF. Я какое-то время не замечал этой ошибки, так как тестирую всегда с включенной директивой в опциях проекта, и компилятор метод находил. Вообще, смысл этой директивы в том, что когда она включена, некоторые объекты на схеме поддерживают операции поворота на произвольный угол.
 Ins


30-10-2009 05:20
Скачал по указанному адресу https://sourceforge.net/projects/easycad/ исходники, но скомпилировать не получается ни в Д7, ни в Турбо2006. Ругается так: [Pascal Error] ECADPluginsCommon.pas(428): E2003 Undeclared identifier: 'RotatePoint'
[Pascal Error] ECADPluginsCommon.pas(428): E2029 ';' expected but '(' found
[Pascal Error] ECADPluginsCommon.pas(430): E2003 Undeclared identifier: 'Host'
[Pascal Error] ECADPluginsCommon.pas(430): E2003 Undeclared identifier: 'Point1'
[Pascal Fatal Error] ECADPluginsHost.pas(9): F2063 Could not compile used unit 'ECADPluginsCommon.pas'

Есть мнение, что дело в директиве компилятора IFDEF SPACEANGLE. Найти по этой директиве в справке ничего не смог. Возможно, я ошибаюсь. Как быть?


14-10-2009 05:54
сообщение от автора материала
Подскажите, как удобней используя Ваш пример реализовать объект "связь между объектами"

Get-методы базовых точек пусть возвращают координаты не из собственного массива или полей, а запрашивают их у объектов, к которым привязаны
 Ins


14-10-2009 05:21
Подскажите, как удобней используя Ваш пример реализовать объект "связь между объектами"
По идее это должна быть ломанная линия 2 крайние базовые точки которой являются одновременно и базовыми точками прямоугольника или другой фигуры. Ну и соответственно при перетаскивании этих объектов эта "связь" должна растягиваться изменять положение...


20-09-2009 14:17
Доброго времени суток, Юрий!

Изучил статью и выложенные исходники. Поигрался  :)
Написал в аську выложенную в профиль. :)

На всякий случай решил продублировать здесь.

Не хотите поработать в этом направлении на небезвозмездной основе?

С уважением, Косов Дмитрий


18-09-2009 00:11
Спасибо!!!


17-09-2009 08:49
сообщение от автора материала
Если не готовится, то можно попросить автора поделиться - пусть и "сырыми" - наработками? Очень нужно.

Можно взять отсюда:
https://sourceforge.net/projects/easycad/
 Ins


16-09-2009 02:55
Отлично! Готовится ли вторая часть? Если не готовится, то можно попросить автора поделиться - пусть и "сырыми" - наработками? Очень нужно.


21-05-2009 03:53
сообщение от автора материала
Denis Serebraykov, напишите свой адрес, я Вам юнит вышлю, посмотрите как там реализованы интересующие Вас вещи.
 Ins


21-05-2009 02:57
сообщение от автора материала
Но вот как поступить с изменением размеров?

Хм, а что с ним? Изменение размеров родителя интересует или дочерних? Вроде как изменение размеров ни того, ни другого, на координатах никак не скажется. Ну изменился размер, а нам какое дело? Все равно отсчитываем от вершины родителя. Точно так же ведь и компоненты на форме себя ведут. У формы Left/Top относительно экрана, у компонентов - относительно формы или другого родителя. И как тут изменение размеров мешает?

При вызове метода Free у меня возникает ошибка работы с памятью, так как объект контейнер хранит ссылки на удаленные объекты. Разъясните пожалуйста, как реализовать перенос самого объекта из одного списка в другой, а не ссылку на него (из списка контейнера в список объекта-родителя)? Или где это можно прочитать, а то для меня эта тема темный лес :)

Так, не совсем понял, если честно, почему возникает ошибка. Я бы сделал так: свойству Parent сделал бы сеттер, который извлекает объект из списка старого родителя (Extract метод), и заносит в список нового. А в деструкторе базового класса всех объектов - удаление все деток. Соотвтественно разгруппировка - это перенос всех объектов из группы, а потом удаление последней, а удаление группы со всеми объектами - просто Free.
 Ins


20-05-2009 05:47

Почему не хотите пойти по такому пути?

От недопонимания. С перемещением мне понятно (Относительная координата = левая верхняя координата родителя - текущая координата потомка). Но вот как поступить с изменением размеров? Если не трудно, то могли бы вы привести пример кода, для лучшего понимания. И я так понял, что поле FChildren перенести из объекта группы в базовый объект?

Ну, в простейшем случае можно сделать так, чтобы при уничтожении объект автоматом прибивал и всех своих деток.

При вызове метода Free у меня возникает ошибка работы с памятью, так как объект контейнер хранит ссылки на удаленные объекты. Разъясните пожалуйста, как реализовать перенос самого объекта из одного списка в другой, а не ссылку на него (из списка контейнера в список объекта-родителя)? Или где это можно прочитать, а то для меня эта тема темный лес :)


20-05-2009 02:47
сообщение от автора материала
Что-то мне подсказывает, что я сделал все неверно. Можете указать на ошибки?

Ну, я делал немного по-другому. Как уже сказал, координаты дочерних объектов пересчитывал в относительные, и тогда при перемещении ничего никому рассылать не требуется. Перемещение просто меняет координаты самой группы, а относительные координаты остаются неизменными. В общем, просто нужно ввести такую систему, чтобы координаты задавались относительно родителя, а не документа, если родитель есть, и при рисовании или мышиных операциях это учитывать. Почему не хотите пойти по такому пути? Несложно в реализации да и дополнительные бонусы дает, кроме возможности группировки, например - можно "привязывать" текстовые надписи к фигурам, которые будут таскаться вместе с ними, сохраняя свое относительное расположение.

И еще я не понял, как мне сделать удаление группы, т.е. удалить не только объект группа, но и её потомков.
Ну, в простейшем случае можно сделать так, чтобы при уничтожении объект автоматом прибивал и всех своих деток. Тогда удаление группы со всеми элементоми - это просто вызов Free. А разгруппировку реализовать по такому алгоритму:
1. В цикле по всем элементам переносим их из группы на непосредственно документ, не забывая менять координаты, чтобы абсолютные остались неизменными
2. Удаляем пустой объект-группу
 Ins


19-05-2009 11:51

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

Я поступил следующим образом:
1. Добавил в контейнере две операции: группировка и разгруппировка


TVisualContainer = class(TCustomControl, ICoordConvert)
...
  public
    procedure Group;
    procedure UnGroup;
...
end;
// Для примера группирую все объекты в конейнере
procedure TVisualContainer.Group;
var
   i : integer;
begin
  FCurrentObject := TGroup.Create;
  FCurrentObject.OnChange := ObjectChanged;
  Selected := FObjects.Add(FCurrentObject);
  for i := 1 to FObjects.Count-1 do begin
    if TBaseVisualObject(FObjects[i-1]).Parent = nil then (FCurrentObject as TGroup).AddObject(TBaseVisualObject(FObjects[i-1]));
  end;
end;

procedure TVisualContainer.UnGroup;
var
   i : integer;
begin
if FCurrentObject is TGroup then begin
    Selected := -1;
    i := FObjects.IndexOf(FCurrentObject);
    FObjects.Delete(i);
    Invalidate;
end;
end;


2. Добавил новый объект группа:


  TGroup = class(TRectVisualObject)
  private
    FChildren : TObjectList;
    procedure UpdatePoints;
    procedure VOCMove(var Command: TVOCMove); message VOC_MOVE;
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure AddObject(AObject:TBaseVisualObject);
  end;

constructor TGroup.Create;
begin
inherited Create;
FChildren := TObjectList.Create(True);
end;

destructor TGroup.Destroy;
var
j : integer;
begin
  for j := 1 to FChildren.Count do TBaseVisualObject(FChildren[j-1]).Parent := nil;
  inherited Destroy;
end;

procedure TGroup.AddObject(AObject:TBaseVisualObject);
begin
FChildren.Add(AObject);
AObject.FParent := Self;
UpdatePoints;
end;

procedure TGroup.UpdatePoints;
var i,j: integer;
    P1,P2:TFloatPoint;
begin
  if FChildren.Count = 0 then exit;
  P1 := TBaseVisualObject(FChildren[0]).BasePoints[0];
  P2 := TBaseVisualObject(FChildren[0]).BasePoints[0];
  BeginUpdate;
  for j := 1 to FChildren.Count do begin
    for i:=1 to TBaseVisualObject(FChildren[j-1]).BasePointsCount do
    begin
      P1.x := min(P1.x,TBaseVisualObject(FChildren[j-1]).BasePoints[i-1].x);
      P1.y := min(P1.y,TBaseVisualObject(FChildren[j-1]).BasePoints[i-1].y);
      P2.x := max(P2.x,TBaseVisualObject(FChildren[j-1]).BasePoints[i-1].x);
      P2.y := max(P2.y,TBaseVisualObject(FChildren[j-1]).BasePoints[i-1].y);
    end;
  end;
  BasePoints[0] := P1;
  BasePoints[1] := P2;
  EndUpdate;
end;

procedure TGroup.VOCMove(var Command: TVOCMove);
var
  i: Integer;
begin
  inherited;
  for i := 1 to FChildren.Count do  TBaseVisualObject(FChildren[i-1]).SendCommand(Command.CmdID, longint(Command.DeltaX), longint(Command.DeltaY));
end;



Алгоритм работы создания группы:
1. Создаю объект группа
2. Добавляю с помощью процедуры AddObject ссылку на объект и присваиваю объекту родителя
3. Обновляю контрольные точки группы
4. Когда группе приходит сообщение она рассылает его всем потомкам (В примере сообщение на перемещение).

Алгоритм работы удаления группы:
1. У потомков удаляю родителя
2. Удаляю сам объект группа.

Что-то мне подсказывает, что я сделал все неверно. Можете указать на ошибки?
И еще я не понял, как мне сделать удаление группы, т.е. удалить не только объект группа, но и её потомков.


21-04-2009 13:01
сообщение от автора материала
А кто будет тогда хранить информацию о дочерних объектах? Контейнер или объект-родитель?

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

Может лучше не переходить к относительным координатам, а просто в объекте-родителе рассылать сообщения дочерним объектам?

Не думаю, что это лучше. А в чем проблема то? Переход из относительных координат в абсолютные и наоборот очень прост.
 Ins


21-04-2009 12:01

1. Создать группирующий объект
2. Поместить в него дочерние объекты, изменив их координаты базовых точек таким образом, чтобы относительно самого документа они остались неизменными (теперь координаты будут задаваться относительно группирующего объекта).
А разгруппировка - обратное действие.

А кто будет тогда хранить информацию о дочерних объектах? Контейнер или объект-родитель?
Может лучше не переходить к относительным координатам, а просто в объекте-родителе рассылать сообщения дочерним объектам?


21-04-2009 07:27
сообщение от автора материала
Тут еще вот что. Объекты имеют Z-Order, который определяет порядок и рисования. Может получится так, что объект скрыт под другими и выделен. В этом случае, если рамочку выделения будет рисовать не контейнер, то ее не будет видно вовсе, а это не есть гуд. Хорошо бы показать границы выделенного объекта даже если он сам скрыт. Пользователь должен знать что за объект выделен. Например для того, чтобы знать что произойдет, если он нажмет на кнопку Delete ;)
 Ins


21-04-2009 07:20
>>> Мне кажется, что более правильно было бы сообщить объекту(ам), а они бы уже рисовали, причем, быть может, каждый по-своему, нет?
Насколько я понимаю, в общем случае должно быть и то, и это. Поясняю...

Возьмем тот же Visio. Если мы Выделим группу объектов, то, во-первых, у нас каждый объект, входящий в выделение, должен выглядеть иначе, чем не выделенный; во-вторых, должна быть отрисована общая рамка вокруг всего выделения. Разумно, чтобы внешний вид выделенного объекта рисовался самим объектом, а окружающую рамку всего выделения должен рисовать контейнер.

В частном случае, думаю, чего-то одного может и не быть (например, если мы не можем выделять группу объектов, соответственно, выделять можно только один объект, то он сам может рисовать и рамку выделения с квадратиками контрольных точек).
 Geo


21-04-2009 02:51
сообщение от автора материала
А теперь вопрос: каким образом в данном примере можно реализовать группировку объектов? По типу как в Corel Draw или Word?

Скорее всего, данный пример для этого потребует доработки. Я ниже писал, что
2. ВО теперь представляют собой не плоский список, а организованы в виде дерева. Любой ВО в общем случае может являться родителем для других ВО. Базовые точки задаются в относительных величинах, а началом координат для них является Origin родителя. Таким образом, при перемещении родитель перемещается со всеми его дочерними ВО.
Можно поступить таким же образом. А потом ввести класс группирующего объекта, цель которого просто быть родителем для других и перехватывать мышиные операции, не передавая их своим чаилдам, чтобы пользователь таскал мышью саму группу. Таким образом операция группировки - это:
1. Создать группирующий объект
2. Поместить в него дочерние объекты, изменив их координаты базовых точек таким образом, чтобы относительно самого документа они остались неизменными (теперь координаты будут задаваться относительно группирующего объекта).
А разгруппировка - обратное действие.

to чиполинский
Скажите, пожалуйста, сколько времени заняло создание того, что описано в статье, и сколько заняло усовершенстование (нужно знать для правильной расстановки ориентиров на будудщее)?
Не знаю, как ответить на этот вопрос. Если скажу, что от начала публикации статьи до теперешнего момента - то сильно Вас шокирую? А если уточню, что занимаюсь этим с свободное время и при наличии желания (которого чаще нет :) ), и в сумме на все про все ушло около сотни рабочих часов? Но тоже преувеличу, а точнее преуменьшу, так как наработки уже были, я по сути просто их собираю вместе.

И это... как бы скачать исходники с изменениями(ведь, насколько понимаю, проект открытый)?
Там все сыро, недоделано, и с ошибками. Устроит? :)

И последнее. Лично меня нескольок смутило то, что контейнеру поручено "отрисовывать состояние выделенности". Мне кажется, что более правильно было бы сообщить объекту(ам), а они бы уже рисовали, причем, быть может, каждый по-своему, нет?..
Если у Вас вид выделенного объекта может зависеть от его типа, то разумеется. Мне же тут повезло больше, достаточно нарисовать вершинки, которые есть у всех объектов. Да, и еще. Если будете делать так, как Вы предложили, учтите режим, при котором выделение при рисовании игнорируется. При печати же Вам скорее всего выделение показывать не нужно будет?! В моем случае его просто не нужно рисовать поверх объектов, а в Вашем нужно как-то учесть.
 Ins


20-04-2009 10:55
К сообщению Юрия Спектора от 16-02-2009 03:16.
Глянуть на озвученные изменения хоть краешком глаза - и можно смело помирать! :-) Немножо не в тему, но очень интересует такой вопрос. Скажите, пожалуйста, сколько времени заняло создание того, что описано в статье, и сколько заняло усовершенстование (нужно знать для правильной расстановки ориентиров на будудщее)? И это... как бы скачать исходники с изменениями(ведь, насколько понимаю, проект открытый)? И последнее. Лично меня нескольок смутило то, что контейнеру поручено "отрисовывать состояние выделенности". Мне кажется, что более правильно было бы сообщить объекту(ам), а они бы уже рисовали, причем, быть может, каждый по-своему, нет?..


20-04-2009 04:40
Статья очень понравилась, узнал много нового для себя, автор молодец!

А теперь вопрос: каким образом в данном примере можно реализовать группировку объектов? По типу как в Corel Draw или Word?


16-02-2009 03:16
сообщение от автора материала
Идея, кстати, получила дальнейшее развитие. Ниже приведу список некоторых нововведений и пересмотров, может кто переймет идею и реализует сам, а может как-нибудь созрею, чтобы написать к статье дополнение:

1. Контейнер теперь не является вместилищем визуальных объектов (далее ВО). Они содержаться в объекте "документ", который в свою очередь может быть загружен в контейнер. Документ реализует субъект паттерна "наблюдатель", а контейнер(ы) - слушатели. Любое изменение в документе приводит к уведомлению всех его слушателей, в частности - к перерисовке контейнера.
2. ВО теперь представляют собой не плоский список, а организованы в виде дерева. Любой ВО в общем случае может являться родителем для других ВО. Базовые точки задаются в относительных величинах, а началом координат для них является Origin родителя. Таким образом, при перемещении родитель перемещается со всеми его дочерними ВО. Также кроме смещения родитель может задать угол поворота. Таким образом, каждый ВО задает для дочерних свою систему координат, которая является суперпозицией смещения и поворота. Таким образом окончательное преобразование координат ВО - произведение всех матриц преобразований его предков. Была идея вообще любые афинные преобразования позволять, но передумал.
3. Для каждого ВО введены настройки визуализации - толщина, цвет линии, заливки и т.д.
4. Документ может быть сохранен в файл или стрим тремя разными способами: запись метафайла, запись битмапа, запись объектов (для этого способа предусмотрено и чтение). В последнем случае используется персистентность, ВО сами описывают что должно быть записано в поток, а то, каким образом это будет сделано определяет менеджер записи. Написаны два стандартных менеджера для бинарного формата и XML.
5. Код, отвечающий за обработку пользовательского ввода и вывода документа в контейнере вынесен в отдельные объекты-менеджеры ввода и вывода. Контейнер, ссылаясь на различные менеджеры, может вести себя по-разному, например, может реализовать рабочую область приложения, или область для предварительного просмотра печати как всего документа так и отдельных листов.
6. Различного рода оптимизации, главная из которых - при изменении в документе обновляется не весь контейнер, а только область, которую изменения затронули.
 Ins


12-02-2009 07:30
о, все понял..sorry за беспокойство и большое спасибо за статью, очень полезно.


12-02-2009 04:39
Что то я никак не пойму - каким образом задается, что Контейнер должен иметь полосы прокрутки, или все потомки CustomControl их имеют? Тогда вопрос - а как их отключить или хотя бы не показывать, чтобы реализовать перемещение по контейнеру с помощью мыши?

и наверное еще один глупый вопрос - не могу понять что именно значат FOrgin'ы смещение видимой части относительно "начала координат") и LeftCol, TopRow?


23-01-2009 15:56
Есть некие наследники от TBaseVisualObject, положение которых по вертикали (т.е. - Тор) должно быть одинаковым для всех объектов этого класса, как бы я ни таскал мышью отдельные его экземпляры. ...

Мне сложно представить ситуацию, при которой объекты TBaseVisualObject (или его наследники) были бы связаны по "классовому признаку".

Мне кажется, "идеологически верно" связывать объекты по какому-либо признаку предметной области, например, принадлежность объектов одному уровню иерархии в отношении между объектами.

Тогда возникает задача установления отношений между объектами TBaseVisualObject (или его наследниками): каждый подчиненный объект регистрирует себя у более "старшего" объекта (на это может указывать объект типа "линия связи"); или объекты объединяются в некий "равноправный" кластер, который ведет себя одинаково.

Тогда при перетаскивании этого старшего объекта, он рассылает сообщение "изменение положения" всем зарегистрировавшимся у него младшим объектам; или при перетаскивании "младшего" объекта, "старший" рассылает подобное сообщение остальным младшим объектам.


22-01-2009 07:06
сообщение от автора материала
Ааа, прошу прощения, я кажется несовсем правильно понял Ваш вопрос... Нужно подумать
 Ins


22-01-2009 04:57
сообщение от автора материала
Может, кто-нибудь подскажет что-то более "идеологически выдержанное"?

Перекрыть Get(Set)Vertex таким образом, чтобы Get при определенном индексе возвращал фиксированное по Y значение, а Set при этом индексе устанавливал только X ;-)
 Ins


21-01-2009 14:40
Пытаюсь реализовать следующую функциональность:
Есть некие наследники от TBaseVisualObject, положение которых по вертикали (т.е. - Тор) должно быть одинаковым для всех объектов этого класса, как бы я ни таскал мышью отдельные его экземпляры.
Ничего лучше такой схемы придумать не смог: объект генерирует событие "изменение положения", Контейнер его отлавливает и далее рассылает сообщение (или просто присваивает значение соотв. св-ву) всем объектам этого класса.
Может, кто-нибудь подскажет что-то более "идеологически выдержанное"?


20-01-2009 02:51
сообщение от автора материала
Блеск! Но, есть пожелание-замечание. Где персистентность?

Спасибо! И за замечание - тоже. Про персистентность - это Вы верно подметили :) На правах оправдания: мне показалось, что статья уже и так достаточно объемная, а персистентность тема широкая. В результате имеем две статьи вместо одной :)
 Ins


20-01-2009 00:29
Блеск! Но, есть пожелание-замечание. Где персистентность? Хотелось бы видеть, ведь для недалеко продвинутых - навроде меня - это было бы очень поучительно. Тем более, учитывая интерес автора к этой теме (вспоминаю его статью "Delphi и персистентность — новый взгляд").


07-01-2009 14:51
каким образом данный компонент можно создавать в runtime?

Точно так же, как и другие компоненты, здесь никакого принципиального отличия нет.
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=342


Наверное, я не понял вопроса и решил что речь идет не о Визуальном Контейнере, а об Объектах для Контейнера.


07-01-2009 14:45
каким образом данный компонент можно создавать в runtime?

Точно так же, как и другие компоненты, здесь никакого принципиального отличия нет.
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=342


Я считаю что здесь случай чуть другой, вот что у меня получилось:

// создаются два блока типа TActionBlock
// добавляется кнопка и ее обработчик
// некоторые методы пришлось сделать public, но это на скорую руку

procedure TForm1.ToolButton11Click(Sender: TObject);
var
  Pos: TFloatPoint;

begin

{}
  VisualContainer1.ObjectType := TActionBlock;
  VisualContainer1.StartConstruct;
  TActionBlock(VisualContainer1.SelectedObject).Text := 'Block1';
  VisualContainer1.ScreenToLog(100, 100, Pos.X, Pos.Y);
  VisualContainer1.SelectedObject.SendCommand(VOC_CONSTRUCTPOINT, 0, Longint(@Pos));
  VisualContainer1.ScreenToLog(200, 120, Pos.X, Pos.Y);
  VisualContainer1.SelectedObject.SendCommand(VOC_CONSTRUCTPOINT, 0, Longint(@Pos));
  VisualContainer1.FinishConstruct;
{}
{}
  VisualContainer1.ObjectType := TActionBlock;
  VisualContainer1.StartConstruct;
  TActionBlock(VisualContainer1.SelectedObject).Text := 'Block2';
  VisualContainer1.ScreenToLog(220, 100, Pos.X, Pos.Y);
  VisualContainer1.SelectedObject.SendCommand(VOC_CONSTRUCTPOINT, 0, Longint(@Pos));
  VisualContainer1.ScreenToLog(320, 120, Pos.X, Pos.Y);
  VisualContainer1.SelectedObject.SendCommand(VOC_CONSTRUCTPOINT, 0, Longint(@Pos));
  VisualContainer1.FinishConstruct;
{}

end;



04-01-2009 14:18
На самом деле, ответ лежит там же, т.е. в исходниках. Единственное, чем утешаюсь, так это тем, что уже извинился... ;) Хэппи нью е!


03-01-2009 07:16
Не, я конечно понимаю, что в данной реализации это не нужно, но я хочу прояснить этот момент для себя. Спасибо.


03-01-2009 07:14
Извиняюсь за свою глупость, но кактус буду кусать. Объясните, пож-та, такой момент:


...........

function TVisualContainer.FindObject(X, Y: Integer; var HitTest: Cardinal): Integer;
...
    HitTest := TBaseVisualObject(FObjects[i]).SendCommand(VOC_HITTEST,
      Longint(Self as ICoordConvert), Longint(@Params));
...

...........

procedure TBaseVisualObject.VOCHitTest(var Command: TVOCHitTest);
begin
  Command.Result := HT_OUT;
end;



Насколько я понимаю, в процедуре TBaseVisualObject.VOCHitTest можно при желании как-то использовать Longint(Self as ICoordConvert) для обращения к ICoordConvert. Но как? Что-то этот момент вызвал у меня затруднения. Вроде бы понимаю, что имеем адрес, но как в данном случае можно было бы обратиться к соотв. интерфейсу?


27-10-2008 07:02
ё-мое, ну надо же сначала потратить неделю на написание того же самого примерно, а потом натолкнуться на такую грамотную статью.
делал как Geo, через TGraphicControl, хотя знал, что придется переделывать.

сижу читаю, замечательная статья.


23-09-2008 01:34
сообщение от автора материала
каким образом данный компонент можно создавать в runtime?

Точно так же, как и другие компоненты, здесь никакого принципиального отличия нет.
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=342
 Ins


22-09-2008 13:41
У меня такой вопрос, каким образом данный компонент можно создавать в runtime? Нужно это мне так как пытаюсь разобраться с данным примером в Turbo Delphi 2006 (бесплатный), а он не поддерживает сторонние компоненты.


20-05-2008 05:35
Спасибо, я попробую!


19-05-2008 08:42
сообщение от автора материала
Игорь
Интересно, а можно использовать в качестве подложки графическое изображение? Как сделать прозрачный фон под вновь создаваемыми объектами?

А вы как делаете объекты и контейнер, так же, как в статье описано? Если да, то добавить изображение к контейнеру можно таким образом: определить свойство Picture у класса-контейнера, написать его реализацию, а в методе Paint вставить код, рисующий это изображение перед отрисовкой элементов. Ну а прозрачный фон у объектов совсем просто - это у класса TLogicalCanvas в методах DrawRect и пр. вместо

FCanvas.Brush.Style := bsSolid;


писать

FCanvas.Brush.Style := bsClear;



 Ins


19-05-2008 08:05
Здравствуйте!
Хорошая поучительная статья, спасибо.
Интересно, а можно использовать в качестве подложки графическое изображение? Как сделать прозрачный фон под вновь создаваемыми объектами?


08-05-2008 05:16
Спасибо Автору! Существенно помогло в реализации моего проекта! ^_^
 neys


23-04-2008 12:34
сообщение от автора материала
Я предпочитал идти другим путем. Наследование фигур от TGraphicControl и тесное взаимодействие абстрактного базового класса фигуры с подложкой...

Понятно, я так тоже делал некоторое время. Но вот именно универсальностью мне жертвовать и не хотелось бы. Это ведь такая вещь, сегодня у тебя один проект, завтра - другой, но задачи могут быть сходны по классу и хотелось бы использовать старые наработки, а не изобретать все заново. А достигается универсальность именно максимальной степенью абстракции.
Честно говоря, в приведенной реализации абстракция далека от максимальной. Ведь и контейнер можно было бы сделать самодостаточным, чтобы его практически (или полностью) без изменений можно было бы использовать в другой задаче. А для этого следовало бы "отвязать" от контейнера трансляцию пользовательского ввода в команды объектов. Чтобы в другой задаче, например, можно было бы выполнять клавиатурой и мышью совсем другие операции (так как и объекты могут быть совершенно другими). Отвязать и переложить на другую сущность - тот самый контроллер. Контейнер, получая ввод от пользователя, перенаправляет его контроллеру, а тот уже отправляет команды объектам. Таким образом, в другой задаче мы могли бы просто заменить контроллер, реализовать свой конкретные типы объектов от имеющегося базового класса, а контейнер и вовсе оставить без изменений. Это в идеале, разумеется.
 Ins


23-04-2008 10:42
Прочитал. Интересно, поучительно, полезно.

От моего подхода отличается. Мой тезка делал на максимально абстрактном уровне, наследуясь непосредственно от TObject. Причем сделал объекты максимально самодостаточными, что позволяет работать с ними на чем угодно (собственно, объект для размещения фигурок не рассматривается).

Я предпочитал идти другим путем. Наследование фигур от TGraphicControl и тесное взаимодействие абстрактного базового класса фигуры с подложкой, что позволяло (как мне кажется) эффективнее реализовать редактирование схем за счет распределения функционала между объектом и подложкой. Хотя, возможно, я несколько терял в универсальности и качестве перерисовки.

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

Но в любом случае, статья хороша.
 Geo


18-04-2008 08:58
>>> Наверное, профессиональное программистское образование
Думаю, что просто хорошее образование. Плюс практика. Плюс умение и желание работать.

Как и Fisher никак не могу даже дочитать до конца. Только начну, что-то сваоивается. Прочитаю обязательно, так как сам решал аналогичные задачи. И хочется сравнить.

Но за одно только вступление про декомпозицию задачи и объяснение, зачем она нужна, уже можно ставить пять баллов ;-)

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


18-04-2008 08:13
К сожалению, глубоко вникнуть пока времени нет, но выглядит замечательно. Обязательно вернусь к этому позже.


18-04-2008 08:01
Автор вообще молодец для своего возраста :-))) Наверное, профессиональное программистское образование.


18-04-2008 00:00
Автор - молодец. Очень грамотная статья и довольно технологичная. Поболее таких статей бы.


Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Однажды, в студеную зимнюю пору я из лесу вышел, был сильный ЧТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.

Оценка содержания
 
Содержит полезные и(или) интересные сведения
 
Ничего особенно нового и интересного
 
Написано неверно (обязательно укажите почему)


Оценка стиля изложения
 
Все понятно, материал читается легко
 
Есть неясности в изложении
 
Непонятно написано, трудно читается

Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования