Форум: "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 является (ну нет озабоченности в автоматическом освобождении памяти, наоборот - мешает)
И у меня есть возможность всем элементам сделать одинаковый формат начала области памяти (единого предка - по-научному) - на него и ссылаюсь
Получается махонькая системка RTTIvar 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