Текущий архив: 2007.06.24;
Скачать: CL | DM;
Вниз
TMenu в KOL Найти похожие ветки
← →
Galkov © (2006-11-13 12:52) [0]Вот вопрос(ы) задаю, потому-что простой поиск по фрагменту "TMenu" полезного ничего не принес
1) Мне понятно, почему ВСЕ менюхи, подчиненные данному контроллу увязываются в один список. Мне непонятно, почему критерием MainMenu является fMenuObj=nil, а не совпадение хэндлов в TMenu с полем fMenu контролла
2) Мне непонятно, почему НИКТО не ставит себе в труд обнулить поле fMenuObj. Даже после fMenuObj.free (например в TMenu.SetMenu)
3) Мне непонятно, на кой ляд TMenu.free уничтожает весь список после себя. И почему уничтожением всего списка не занимается только TControl.destroy - кому это нужно еще, кроме него.
4) Мне непонятно, почему в TMenu.destroy происходит отстегивание MainMenu формы не интересуясь, а что к этому времени осталось от формы. Судя по моим скудным поискам по форуму - крах задачи зависит от оси... Но по-любому: делать SetMenu(..., 0) из TControl.Destroy (через fMenuObj.free) - неприлично. Но безусловно необходимо, если это независимый вызов TMenu.free
5) Мне непонятно, почему в TMenu.Destroy есть вольности с выходом без inherrted (а, следовательно, и без вызова Final)
Прошу прощения, если вопросы от банального непонимания (хотя мне сейчас представляется все одной большой багой) ....
Безусловно, мог бы предложить свой комплексный фиксинг, но опять не понимаю (:)) как это удобней сделать
← →
Vladimir Kladov (2006-11-13 16:25) [1]что за критерий MainMenu? Первый раз слышу. Если при создании, чтобы определить, главное это меню или нет, то как можно использовать совпадение хэндлов, когда их еще нет, и они не присвоены. Если про RedrawFormMenuBar, то потому сто так короче.
Поищите по тексту fMenuObj.free. Когда надо, оно обнуляется. Нет никакого смысла делать это в деструкторе непосредственно перед разрушением формы.
на кой ляд TMenu.free уничтожает весь список после себя
Так сделано. Чему это мешает? В KOL меню построены в список: первое - главное, прочие - pop up. Если нет главного, надо создать пустое первое. Так сделано изначально. Меню один раз сождаются, и один раз уничтожаются, вместе с формой.
Если про этот кусок (насчет выхода без inherited)if FParentMenu <> nil then
begin
Prnt := FParentMenu;
Next := Prnt.RemoveSubMenu( FId );
FParentMenu := nil;
Prnt.FItems.Remove( @ Self );
if Next = nil then Exit;
end;
То он никогда не срабатывает (по крайней мере у меня так получается). Надо бы вообще убрать, но сначала надо вспомнить, вообще откуда он взялся, и зачем был нужен.
← →
Galkov © (2006-11-13 22:49) [2]
> что за критерий MainMenu? Первый раз слышу. Если при создании,
> чтобы определить, главное это меню или нет, то как можно
> использовать совпадение хэндлов, когда их еще нет, и они
> не присвоены.
Ни в коем случае не имел в виду TControl.handle, но TMenu.handle и TControl.fMenu, которые создаются сразу, невзирая на создание окна windows. Мне так показалось. Про отложенные деструкторы мне, как бы, понятно ...
Но имелись в виду не технические детали, а постановочная часть. Мне понятно, что "так было сделано", и даже понятно как. Вопрос, по большому счету, что мешает сделать "по нормальному". И обсудить, конечно же, что есть нормально.
> Поищите по тексту fMenuObj.free. Когда надо, оно обнуляется
Дык поискал. Готов согласиться, что в TControl.destroy это не надо. Если считать, что TMenu.SetMenu может вызываться только из KOL, то это, по меньшей мере - странно. Св-во TMenu.Menu открыто на запись в разделе public.
Насколько я понимаю в кодах, после присваивания:MainMenu.Menu :=0
MainForm.free обязан приводить к краху.
> Так сделано. Чему это мешает?
Это мешает удалить (например, после долгой и успешной работы) одно из PopUp-ов и сопоставить освободившиеся события некому другому меню. К примеру - вновь созданному. Аналогично про главное меню. Извините, но повторюсь: мне вроде бы понятно как сделано изначально, мне непонятно почему так должно быть всю жизнь.
> То он никогда не срабатывает (по крайней мере, у меня так
> получается).
Здесь согласен, недосмотрел... Пожалуй, иPrnt.FItems.Remove( @ Self );
- тоже излишество...
================================================
Но больше меня интересует п.4, оставшийся без комментария. Попробую конкретизировать вопрос:
Если исходить из "так сделано", то единственная разумная возможность запустить TMenu.free - это уничтожить контролл, который, в свою очередь, сделает fMenuObj.free. Возможно, я не прав - тогда очень прошу разъяснить... Скажем, примером иной разумности.
Далее. КАКИЕ у нас гарантии, что, в процессе уничтожения контролла, строка из TMenu.Destroy:Windows.SetMenu( FControl.fHandle, 0 );
не закончится крахом.
Вопрос задаю, потому что я это исключение - имею... Если MainMenu назначено не аплету. И для меня большой вопрос - почему это живет до сих пор :(
Естественно, прежде всего, я подозревал свою безграмотность. Но здоровье уже кончилось, разбираться, как правильно составить программу из 4-х строк: создал аплет, создал форму, назначил форме меню, Run(Applet) - исключение по выходу. Проверил: именно на вышеуказанной операции SetMenu.
Вот и вопрошаю....
================================================
В режиме вопрос/ответ как-то сумбурно получается....
А хотелось, в основном-то, решить вопросы на более высоком уровне абстракции:
1) От пользователя библиотеки KOL должны быть скрыты все подробности с fMenuObj и полем Next. И ему (пользователю) должно быть все равно, в каком порядке, какие менюхи созданы.
2) У него должна быть возможность создавать/уничтожать их динамически: понадобилось новое – пожалуйста, NewMenu; надоело – TMenu.free, и всего делов.
3) И никаких нравоучений от библиотеки быть не должно: это сейчас, а это после, а для этого создай фиктивный контролл... Не дело это, ИМХО
Вот именно из этих предпосылок и представляется мне, что следует (по большому счету, пропуская сейчас технические детали) делать так:
1) fMenuObj может указывать не обязательно на MainMenu, но и на PopUp
2) Критерий в NewMenu для создания MainMenu/PopUp должен измениться – соображения в этом посте выше. Грубо говоря, возражений я не понял, и хотелось бы дополнительных разъяснений. Но, в любом случае – чего-нибудь да придумается…
3) Деструктор TMenu должен уничтожать только одну менюху из Next-цепочки. А деструктор TControl – всю цепочку, перелистыванием.
И в свете вышесказанного, мне хотелось бы, чтобы основной вопрос этого топика звучал примерно так: ЧТО НАМ МЕШАЕТ СДЕЛАТЬ ИМЕННО ТАК :?:
Вроде бы - ничего военного...
← →
Galkov © (2006-11-13 22:58) [3]
> Про отложенные деструкторы мне, как бы, понятно
Пардон, КОНСТРУКТОРЫ, конечно же... :(
btw: не пойму, как свой пост править... трудно ведь, сразу - и грамотно...
← →
Vladimir Kladov (2006-11-14 21:03) [4]TMenu.handle и TControl.fMenu, которые создаются сразу, невзирая на
создание окна windows
Эту фразу я не понял. Надо создавать не сразу? А когда?
Св-во TMenu.Menu открыто на запись в разделе public
Мало ли что где в public. Destroy тоже в public, потому что иначе компилятору не нравится. Но вызывать надо Free или RefDec, а не Destroy.
Меню уже переделывалось. Можно и еще (немного) переделать. Проблема в сохранении какой-то совместимости. Я не совсем понимаю: есть сложностис уничтожением popup меню, созданного в run-time? По замыслу, не должно было быть, ведь оно последнее в цепочке. Вообще, идея цепочки устарела примерно с версии 2.40, когда прямой вызов Free для каждого объекта формы отменен и заменено все на это на более активное использование Add2AutoFree. Если только в этом дело, это можно (наверное) исправить. Для любого исправления хотелось бы, чтобы изменения были по возможности минимальны, и в коде, и в концепции. Революции никому не нужны, ни мне, ни вам.
Далее. КАКИЕ у нас гарантии, что, в процессе уничтожения контролла, строка из TMenu.Destroy:Windows.SetMenu( FControl.fHandle, 0 );
не закончится крахом.
Не нужны здесь никакие гарантии. Пока еще работает деструктор (контрола), объект существует, и FControl на него показывает. fHandle в этот момент все еще жив должен быть.
Вопрос задаю, потому что я это исключение - имею... Если MainMenu назначено не аплету. И для меня большой вопрос -
почему это живет до сих пор
Вы наверное в своем коде что-то не так делаете? Простой пример со статическим меню работает корректно. Можно остановиться на этой строчке (Windows.SetMenu, и убедиться, поглядев стэк и переменные, что все в порядке и по-другому быть не может. У вас случайно не происходит повторного вызова деструктора уже разрушенного меню? (А что значит - меню назначено аплету? Ну, конечно, его можно назначить и отдельному контролу, и вообще любому TControl"у даже графическому, но кажется и так понятно, что так делать не надо).
составить программу из 4-х строк: создал аплет, создал форму, назначил форме меню, Run(Applet) - исключение по выходу.
Проверил: именно на вышеуказанной операции SetMenu
Я понимаю, что MCK становится все менее доступен из-за невозможности его использовать в BDS и Turbo-Delphi. Но может быть все-таки проблема в неправильном написании кода вручную? Простейший пример на MCK не падает, и работает корректно. Можно поставить себе какую-нибудь старенькую Delphi типа 5, чтобы хотя бы иногда сравнивать, что вы сами делаете с тем, как оно делается автоматом.
1) От пользователя библиотеки KOL должны быть скрыты все подробности с fMenuObj и полем Next. И ему (пользователю)
должно быть все равно, в каком порядке, какие менюхи созданы.
И так почти все равно. Кроме одной важной детали: главное меню создается первым.
Не дело это, ИМХО
Так сделайте дело. Моя задача минимальный код. Я ее сделал как сумел. Сумейте лучше.
1) fMenuObj может указывать не обязательно на MainMenu, но и на PopUp
Нет. В Windows MainMenu может быть только одно для формы, это вам не иксы. Поэтому и сделано так было. Цепочка была, чтобы минимизировать код, чтобы форма не хранила все свои меню в особом своем списке, и дополнительный код по удалению меню подключался только если есть хотя бы 1 меню. Сейчас можно в принципе перейти к авто-удалению, и убрать цепочки (но для каждого меню добавится еще 1 вызов Add2AutoFree). Но меню как объект нужно только для главного меню. И тогда уже не для удаления, а для перерисовки меню. (Для ссылок на popup меню механизм отдельный, и вообще этот автомат для удобства в простейшем случае - ручной обработчик может выбирать какие popup меню вызывать от обстоятельств).
хотелось бы дополнительных разъяснений Совместимость. Приходят разные революционеры, и давай все крушить. Вы где 8 лет назад были? (Я уже сыт по горло разбирательствами с GTK+, где даже не 50, а все 75% функций deprecated, потому что приходит некто и говорит: а вот так будет сделать лучше, давайте все переделаем, и каждая новая версия приводит к необходимости переделывать код для разработчиков. Или тот же DirectX в части directVideo/direct3D - после чего у разработчиков возникает естественное стремление больше никаких дел с этим directX не иметь вообще, благо есть альтернатива в лице OpenGL, примеры для которого написанные 10 лет назад, и сейчас для самых новых версий прекрасно компилируются без переделки кода).
Значит. 1) Сначала разберемся, что там у вас падает. Шлите мылом короткий пример, если никак не получается. Может, и правда, мне найдется что у себя поправить. 2) На отмену цепочек я и так собирался пойти, просто побоялся все исправления в 1 флакон засовывать.
← →
Galkov © (2006-11-14 23:59) [5]Тезисно:
1) Что значит "шлите мылом"? Собственно, я с этого и начинал, и предполагаю, что это попало в спам. Какие магические слова, в связи с этим, следует прописать в <Теме> ???
Конечно же - вышлю, как только узнаю как и куда :)
2) Идею про ликвидацию цепочек до конца не понял. В смысле, не увидел из поста, чем будет заменено сегодняшнее "листание" списка при обработке WM_COMMAND в аттаче WndProcMenu (извините, что использую данный форум не только для фиксинга, но и для самообразования)
3) Про совместимость мне понятно, и я тоже против диктата пользователю КАК он должен делать, и ЧТО. Даже еще больше против, чем Вы излагаете. Если присмотреться, то предложения заключались в расширение возможности работы, при полной работоспособности старого. Сегодня: это можно, а это нельзя. Предлагается сделать, чтобы можно было и это, и то. И я категорически против того, чтобы нельзя было то, что сегодня можно, но ЗА ТО...
4) С насчет "сначала разберемся" пока проблема: 4 строчки-то, оказывается - работают. Поэтому возьму денек паузы для дальнейшей трассировки. Не потому что полные коды являются неким секретом, а потому что я в них значительно лучше разбираюсь, чем любой новый человек.
Найду.
5) Это D4, и исключительно command line. Возможно, необходимы некоторые пояснения. Есть некий проект визуального программирования, функционирование которого состоит в том, что на основании графической информации (напоминающей эл.схему) генерируется код для некого компилятора, который честно и запускается в последствии.
Автор - не я, но за паскалевские коды необходимых для этой среды юнитов (KOL - не считается :)), как и за процесс кодогенерации отвечать могу.
Другими словами, существуют и иные причины не использования MCK, кроме невозможности его использовать в BDS и Turbo-Delphi :)
==================================
Мораль: для реализации Вашего предложения 1, беру маленький тайм-аут. Поскольку есть причина для поисков - будет и результат. Похоже на такое: кто-то думал, что в KOL так можно, ан фигушки :) Ибо версию с повторным проходов деструкторами я с негодованием отметаю: на контроллах честно перехвачено их уничтожение через onDestroy, как раз для предотвращения такого безобразия.
Надежность диагноза про SetMenu ??? Банальные вставки ДО и ПОСЛЕ этой строки. Скажем:Beep(1000,300) ;
Windows.SetMenu( FControl.fHandle, 0 );
Beep(2000,300);
Первый - есть, а вместо второго - Run Time Error
← →
Galkov © (2006-11-15 13:28) [6]Нашел...
В сухом остатке:
1) Run Time Error происходит в "моих" кодах, а не в кодах KOL
2) Вопрос N1 для меня закрыт, по большому счету. Но демонстрация баги может иметь методологическое значение и для KOL. Догадаться, что после OnDestroy может происходить вызов назначенных событий - было очень непросто. Поэтому демонстрирую...
Почему именно так (хотя исходное не совсем так :)) - это тема отдельного обсуждения. Сейчас, наверное, достаточно того, что это редукция более значительного кода, полученного неким ИИ, чтоб ему пусто было :)Program test;
uses windows,messages,kol;
type
TMainForm = class
public
Control:PControl;
constructor Create(Parent:PControl);
destructor Destroy; override;
function _OnMes(var Msg: tagMSG; var Rslt: Integer ): Boolean;
procedure _OnDestroy(Sender:PObj);
end;
constructor TMainForm.Create;
begin
Control := NewForm(Parent,"MainMenuTest");
Control.OnDestroy := _OnDestroy;
Control.OnMessage := _OnMes;
end;
procedure TMainForm._OnDestroy;
begin
Control := nil;
end;
destructor TMainForm.Destroy;
begin
Control.free;
inherited;
end;
function TMainForm._OnMes;
begin
Result := False;
//if Control=nil then exit; {!!! Это мой вынужденный фиксинг(и)}
{Это BUG_DEMO, поэтому не очень важно содержание - важно использование поля Control}
if (Msg.message = WM_MOVE) or (Msg.message = WM_SIZE) then
Applet.BoundsRect := Control.BoundsRect;
end;
var MainForm:TMainForm;
begin
Applet := NewApplet("Хи-Хи-Хи");
MainForm := TMainForm.Create(Applet);
NewMenu(MainForm.Control,0,
["File",
"(",
"New",
"Open",
"Save As..",
"-",
"&Exit",
")"],nil);
Run(Applet);
MainForm.Destroy;
end.
Страницы: 1 вся ветка
Текущий архив: 2007.06.24;
Скачать: CL | DM;
Память: 0.51 MB
Время: 0.029 c