Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "KOL";
Текущий архив: 2008.06.22;
Скачать: [xml.tar.bz2];

Вниз

Непонятка с аттачами к паренту   Найти похожие ветки 

 
Galkov ©   (2007-08-07 08:41) [0]

Требуются советы Мастеров

Есть на форме 2 элемента: KOLMHTrackBar и KOLMHUpDown
Оба приклеивают по аттачу к паренту:

function WndProcTrackbarParent(Sender: PControl; var Msg: TMsg; var Rslt: Integer): Boolean;
var
 Trackbar: PMHTrackbar;
 Bar: TScrollerBar;
begin
 Result := FALSE;
 if ((Msg.message = WM_HSCROLL) or (Msg.message = WM_VSCROLL)) and (Msg.lParam <> 0) then
 begin
   Trackbar := Pointer(GetProp(Msg.lParam, ID_SELF));
   if Trackbar <> nil then
   begin
     if Assigned(Trackbar.OnScroll) then
     begin
       if Msg.message = WM_VSCROLL then
         Bar := sbVertical
       else
         Bar := sbHorizontal;
       Trackbar.OnScroll(Trackbar, Bar, LoWord(Msg.wParam), HiWord(Msg.wParam));
     end;
   end;
 end;
end;


function WndProcUpDownParent(Sender: PControl; var Msg: TMsg; var Rslt:  Integer): Boolean;
var
 UpDownNow: PMHUpDown;
 Bar: TScrollerBar;
begin
 Result := False;
 if ((Msg.message = WM_HSCROLL) or (Msg.message = WM_VSCROLL)) and (Msg.lParam <> 0) then
 begin
   UpDownNow := Pointer(GetProp(Msg.lParam, ID_SELF));
   if UpDownNow <> nil then
   begin
     if Assigned(UpDownNow.OnScroll) then
     begin
       if Msg.message = WM_VSCROLL then
         Bar := sbVertical
       else
         Bar := sbHorizontal;
       UpDownNow.OnScroll(UpDownNow, Bar, LoWord(Msg.wParam), HiWord(Msg.wParam));
     end;
   end;
 end;
end;


Рискну заявить, что это тождественные аттачи. Т.е., сразу нарушена идеология кодоэкономичности.
И использование свойств, отличных от TControl - обязано приводить к неприятностям (видимо с этим и связано комментирование перекрытия св-ва OnScroll в KOLMHTrackBar).
Ибо аттачу АБСОЛЮТНО неизвестно от которого из контроллов (TrackBar или UpDown) пришла нотификация.

Но бог с ней (на минуту) с кодоэкономичностью. Аттач возвращает false, следовательно сработает второй на ту же самую мессагу.

Или это явный криминал, или я чего-то недопонимаю, и прошу разъяснений :(

Если снова вспомнить про кодоэкономичность, то увидим, что к самим контроллам приаттачен при этом WndProcOnScroll (через property onScroll)
Чего он там делает - совершенно непонятно. Видимо думает, что и TrackBar, или UpDown - являются ScrollBox-ами...

Вопрос-то такой: как это все поправить ???

И второй, более философский: а как в принципе-то клеить аттачи к паренту, если СОВЕРШЕННО разные (CustomData указывает на разные типы) контроллы имеют одного типа нотификации ???


 
Vladimir Kladov   (2007-08-07 11:16) [1]

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


 
Galkov ©   (2007-08-07 13:15) [2]

Владимир, мне известны способы преодоления проблемы !!!

Но меня интересуют принципиальные вопросы: НЕПРАВИЛЬНО то, что эта проблема есть.
Простите - воспитание такое. Думал, что Вам это будет понятно - нас "воспитывали" в одном месте :))

Следовательно, необходимы аргументы существования проблемы.


> Это разные обработчики, которые только выглядят  похоже

Неправда!!! Они не только выглядят похоже, но и ОДИНАКОВЫ
Не хотелось бы опускаться до "сличения почерка", но если Вы настаиваите - можно ведь и дизасм предъявить

Вы, наверное, не обратили внимание на то, что в KOLMHTrackBar.pas закоментированы перехваты св-ва onScroll. Вот если бы они были раскоментированы, тогда ДА - разные.

Внимание, утверждение: в таком случае могут начаться более серьезные проблемы (чем лишние коды), связанные с AV. Именно потому, что в этом случае обработчик для TrackBar начнет искать fOnScroll в CustomData, а нотификация пришла от UpDown.

Так вот, что мы имеем.
Даже в случае "разных парентов" - один лишний WndProcUpDownParent, и никому не нужный (в данной задаче конечно же) WndProcOnScroll

Припоминаются слова, типа:
> KOL существует потому, что VCL не дает такой возможности
> - отказаться от кода, который в данном конкретном приложении
> не нужен. Даже если бы только 1 приложение из 100 было таким,
>  которое не нуждается ....


Пусть это одно приложение будет мое - оно не нуждается ни в лишнем контролле (паренте), ни в лишних аттачах :))


 
Vladimir Kladov   (2007-08-07 14:13) [3]

Найдите автора, и решите с ним свою проблему, или поправьте сами. Мне лично эти контролы не понадобились пока. С моей точки зрения, добавление лишнего родителя, раз оно снимает проблему полностью, является достаточно приемлемым решением. По-хорошему, там в процедуре обработчика, прицепляемого к родителю, должна быть какая-то проверка, что речь идёт именно о том контроле. Нешто гигантское количество кода дублируется. Речь-то идёт о нескольких десятках байтов, чего из-за них так шуметь? Я бы еще понял, если бы этот код добавлялся во ВСЕ проекты, написанные на KOL. А так - только к тем, кто решил использовать эти контролы.


 
Galkov ©   (2007-08-07 14:47) [4]

Владимир, решил у себя я эту проблему.
И не задаю же вопросы про не принципиальную ерунду: аттачи пристегиваются безусловно, а не по св-ам onScroll, OnChangingEx, и т.п..

Ну не об этом речь. Вопрос в том, как надо писать контроллы

> а как в принципе-то клеить аттачи к паренту, если СОВЕРШЕННО
> разные (CustomData указывает на разные типы) контроллы имеют
> одного типа нотификации ???

Хорошо, пусть будет по шагам:
1) Пишу контрол, который имеет в качестве нотификаций WM_VSCROLL, предположим.
2) Прочитал MSDN, и мне все известно, что надо делать дальше.
3) Дополнительные поля, и event-ы располагаю в структуре данных, на которую указывает, предположим - CustomData.
4) В аттаче к паренту вычислил контрол-sender. Лезу в его поле CustomData...

И все - СТОП.
Дальше делать ничего нельзя !!!
Нет НИКАКИХ гарантий, что это CustomData от моего нового контрола, а не от TrackBar, UpDown, или ScrollBar.

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

Ну и в чем я ошибаюсь, интересно ???


 
Vladimir Kladov   (2007-08-07 15:44) [5]

Ну и где проблема, если вы знаете, что нужно проверять, что обработчик относится к своему контролу. Просто Жаров про это не подумал. А вы подумаете, и придумаете способ. Способом может быть хотя бы сигнатура в CustomData.

if (CustomData <> nil) and (PMyCustomData(CustomData).Signature = MySignature) then двигаемся дальше. Если сигнатура например 4 байтное с символоами MHTR или MHUD, это уже больше чем достаточно, чтобы практически 100% всё было как ожидается. Кроме того, у контрола типа Trackbar или Updown не задействуется Caption - вообще пиши чего хочешь туда и проверяй. Можно через свойство Caption, а можно напрямую выделять поле и записывать в fCaption, чтобы не дёргать WinApi.

Ошибаетесь в том, что поднимаете проблему там, где её и нет вовсе. Добавил парента своего, у него только 1 этот контрол - никогда ничего не перепутается. Пара-тройка десятков байтов кода на создание контрола.


 
Galkov ©   (2007-08-07 18:18) [6]

Что характерно, я примерно так и сделал.

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

var TRACK_GUID:integer=0;

procedure THITrackBar.Init;
begin
  GenGuid(TRACK_GUID);
  Guid := TRACK_GUID;
  DoInitCommonControls( ICC_BAR_CLASSES );
....

function WndProcTrackbarParent( Sender: PControl; var Msg: TMsg; var Rslt: Integer ): Boolean;
var Bar: THITrackBar; P:integer;
begin
  Result := FALSE;
  if ((Msg.message<>WM_HSCROLL)and(Msg.message<>WM_VSCROLL))or(Msg.lParam=0) then exit;
  Sender := Pointer( GetProp( Msg.lParam, ID_SELF ) ); //не обращайте внимания :)
  if Sender = nil then exit;
  Bar := THITrackBar(Sender.Tag);
  if (Bar = nil)or(Bar.Guid <> TRACK_GUID) then exit;
  with Bar do begin
....


И есть определение "генератора" в общем юните

var _guids_:integer=0;

procedure GenGUID(var g:integer);
begin
  if g = 0 then begin
    inc(_guids_);
    g := _guids_;
  end;
end;


Но из этого всего что вытекает-то !!!
Это тогда должно быть неким правилом для ВСЕХ авторов KOL-элементов, например: начало поля CustomData должно быть сигнатурой (мне обыкновенного dword хватило).

А не только для меня.

Создаю я сегодня некий "UpDown", и мне невдомек (и не должно быть по-правильному), что завтра некто будет сочинять некий "TrackBar"


 
Vladimir Kladov   (2007-08-07 18:32) [7]

Совсем не вижу необходимости вводить такое правило. Далеко не все дополнительные контролы требуют обработчика, прикрепляемого к родителю, да ещё из-за такого сообщения, из которого не следует явственно, какого типа этот контрол. Решние с единственным родителем гораздо рациональнее. Если очень хочется, то можно сам контрол оформить как связка parent+control, для этих случаев, чтобы уже вопросов точно не возникало. Но кого-то вполне устроит и обычный вариант. Ведь ситуация, когда updown и trackbar на одном родителе, это далеко не очень вероятный частный случай. От всех проблем заранее хотите избавить программиста? Какой же это программист, если он с такими проблемками не сможет разобраться. В крайнем случае, напишите комментарий о том, что есть вероятность такой проблемы, и вариант для ее оперативного устранения. Хорошая и краткая документация - лучший способ помочь программисту.

Кроме того, правило это вводить поздновато: на данный момент есть адаптации практически всех полезных и даже бесполезных (типа IPEdit) контролов. Переписывать их? При наличии большого количества энергии, лучше направить ее в русло более продуктивной деятельности. Например, адаптация к GTK/Linux зависла в ожидании. Я понимаю: я начал, мне и продолжать. Но у меня сверх этого есть еще масса интересных недоделанных проектов.


 
Galkov ©   (2007-08-08 11:06) [8]

Ну можно и итог подводить...

Все-таки дискомфорт остается от того что можно при написании компонента нечаяно "заложить мину".
Т.е., при создании контрола надо прочитать MSDN не только про соответствующий "TrackBar", но и про ВСЕ виндячие использования соответствующего "WM_HSCROLL".
Сомнения в том, что все так и будут поступать - обоснованы, ИМХО.


> От всех проблем заранее хотите избавить программиста? Какой
> же это программист, если он с такими проблемками не сможет
> разобраться

Да нет, не хочу :))
Это у меня почти в рефлексах профессиональное правило срабатывает: не планируй себе проблем "на потом". "Потом" - их и без нашего планирования выше крыши будет (что проверенно неоднократно :))
А насчет проблемок: это с самого начала у них суфикс уменьшительный. А когда начинаешь раскапывать какое-нибудь "двойное срабатывание" события в навороченной программе - это чуток другой разговор о требуемом классе программиста. Мне около дня понадобилось чтобы во всем разобраться.
Потом пол дня пребывал в неуверенности
Еще столько же искал выход.

Уверенности в том, что все технологии KOL мне известны, и я не чешу левой ногой правое ухо - никакой.
Поэтому создал топик.
По результатам вижу, что вроде не такой уж и лох. Можно даже надеяться, что найденное решение близко к оптимальному, раз уж оно возникает "независимо".
За что Вам - огромное спасибо.

Что каcается "почти штатных" компонентов, то видно, что они как-то не очень сопровождаются. Мне понятно в какую сторону их надо причесывать, и без "RTTI тхнологии" там можно и обойтись:
1) Видимо объединять в один юнит и делать им действительно общий аттач для парента
2) Св-во onScrool надо действительно перехватывать, но не размещать fOnScroll в CustomData^, а использовать штатное положение - просто исключить пристегивание аттача из KOL
3) Пристегивать аттачи не безусловно в конструкторах, а только по св-вам установки соответствующих событий
4) ну и по мелочам: поубирать "почти пустые" функциональные вызовы в св-вах... за "один проход" все делается

Вот только создание компонента для IDE не в сфере моих интересов немножко. Так-что, вышестоящие строки - необязательные пожелания автору, коль скоро он сюда забредет :)

Владимир, но ведь мимоходом аналогичный вопрос возникает и про содержимое KOL
А нужно ли подключать аттач WndProcScrollBarParent, если пользователь не подключил события OnSB[Before]Scroll ???


> Кроме того, правило это вводить поздновато: ...

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


 
Vladimir Kladov   (2007-08-08 12:13) [9]

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

Я все-таки думаю, что это был просто весьма неожиданный частный случай, хотя автор компонентов один.

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

Абсолютно чистых от возможных багов компонентов практически не бывает. Если не мы сделаем баг, он появится из-за очередного бага MS или Borland или производителя оборудования. Никто не безгрешен, не ошибается тот, кто ничего не делает (но он тоже ошибается, потому что ничегонеделание - это самая большая ошибка), и т.д.


 
Galkov ©   (2007-08-08 15:18) [10]


> Но необязательность сама по себе может добавлять код, хотя и мало

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

Естественно, решение за Вами. Для меня в таких случаях лишь важно, чтобы мои слова (мысли) были правильно поняты. Что далеко не всегда бывает на нашем Великом и Могучем :))

BTW:
Если бы (!!!) TControl содержал некое поле типа ChildSinature, то его использование могло бы отменить необходимость "переделывать" уже сотворенное для реализации вышеобсужденной технологии а-ля RTTI.

В чем смысл:
Я пишу некий "TrackBar" (имена в двойных кавычках - условные, конечно)
А проверку ставлю еще проще, чем ранее:
 if Sender.ChildSinature <> GUID) then exit;
А конструкторе контрола прописываю это поле - да хоть бы и адресом константной строки типа "msctls_trackbar32"
И мне, при такой реализации, совершенно не мешает (в отличие от случая расположения сигнатуры в CustomData^) тот факт, что некий автор, написавший ранее некий "UpDown" ничего про это не знал - это поле там нулевое.
В "моем" элементе наложений событий от чужого контрола - не будет.
А если они будут у вышеупомянутого автора - это его проблемы, по большому счету-то.
Это же он не предусмотрел, что обрабатываемые им нотификации не только от его контрола могут прилететь... Все правильно, вроде...

Получается, что лишнее поле - это плата за совместимость

Справка - ДА, дело хорошее.
Вот только кажется, что место ей не в ReadMe на конкретный элемент, а в неком Tutorial (уроках) по созданию элементов...
А хинт для поля типа ChildSinature в Kol.pas мог бы быть намеком на то, что этот Tutorial можно бы и перечитать...


 
Galkov ©   (2007-08-09 01:19) [11]

:wink:


 
Galkov ©   (2007-08-22 16:42) [12]

Тест: кажется меня "мастера" забанили


 
имя   (2007-09-19 18:28) [13]

Удалено модератором


 
имя   (2007-09-20 06:31) [14]

Удалено модератором



Страницы: 1 вся ветка

Форум: "KOL";
Текущий архив: 2008.06.22;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.043 c
15-1209656258
NaRuTo
2008-05-01 19:37
2008.06.22
Написание OS на Delphi


2-1211955635
Magos
2008-05-28 10:20
2008.06.22
Как убрать выделение последней выбранной ячейки StringGrid?


15-1210615430
No_Dead
2008-05-12 22:03
2008.06.22
php input readonly


1-1194937505
DancerMan
2007-11-13 10:05
2008.06.22
Обмен значениями элементов ListView


15-1210502269
Kolan
2008-05-11 14:37
2008.06.22
Новости проекта DMClient.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский