-
> [16] offff (25.01.08 16:42)
Не, не понял
Как устроен MenuManager непонял.
> Реализатор IItemsOperationsController пробегает по всем > его коммандам и делает вызов
Что за команды?
> ADDITEM.VISIBLE:=TRUE;
Какое-то жесткое присвоение
Нихрена не понял короче
-
> Нихрена не понял короче…
AddCommand=class; DeleteCommand=class; CurrentCommand=class;
AbstractCommandVisitor=class procedure VAdd(Command:AddCommand);virtual;abstract; procedure VCurrent(Command:CurrentCommand);virtual;abstract; procedure VDelete(Command:DeleteCommand);virtual;abstract; end;
MenuBarCommandVisitor=class(AbstractCommandVisitor) procedure VAdd(Command:AddCommand);override; procedure VDelete(Command:DeleteCommand);override; procedure VCurrent(Command:CurrentCommand);override; end;
AbstractCommand=class function Exec(const param):integer;virtual; procedure Accept(Visitor:AbstractCommandVisitor);virtual; end;
TAbstractCommandClass=Class of AbstractCommand;
AddCommand=class(AbstractCommand) function Exec(const param):integer;override; procedure Accept(Visitor:AbstractCommandVisitor);override; end;
DeleteCommand=class(AbstractCommand) function Exec(const param):integer;override; procedure Accept(Visitor:AbstractCommandVisitor);override; end;
CurrentCommand=class(AbstractCommand) function Exec(const param):integer;override; procedure Accept(Visitor:AbstractCommandVisitor);override; end;
DynaCommands=class Commands:Tlist; constructor create;overload; constructor create(Commands:array of AbstractCommand);overload; destructor destroy;override; procedure Accept(Visitor:AbstractCommandVisitor); function TryPerfomOp(CommandClass:TAbstractCommandClass;const param):boolean; end;
var Form1: TForm1;
implementation
{$R *.dfm}
{ DynaCommands }
constructor DynaCommands.create; begin Commands:=TList.Create; end;
procedure DynaCommands.Accept(Visitor: AbstractCommandVisitor); var i:integer; begin for i:=0 to commands.Count-1 do AbstractCommand(commands.Items[i]).Accept(Visitor); end;
constructor DynaCommands.create(Commands: array of AbstractCommand); var i:integer; begin create; for i:=0 to length(commands)-1 do self.Commands.Add(commands[i]); end;
destructor DynaCommands.destroy; var i:integer; begin for i:=0 to commands.Count-1 do Tobject(commands.Items[i]).Free; Commands.free; inherited; end;
function DynaCommands.TryPerfomOp(CommandClass:TAbstractCommandClass;const param):boolean; var i:integer; begin for i:=0 to commands.count-1 do if (AbstractCommand(commands.Items[i]) is CommandClass) then begin AbstractCommand(commands.Items[i]).Exec(param); result:=true; exit; end; result:=false; end;
{ AbstractCommand }
procedure AbstractCommand.Accept(Visitor: AbstractCommandVisitor); begin // end;
function AbstractCommand.Exec(const param): integer; begin // end;
{ AddCommand }
procedure AddCommand.Accept(Visitor: AbstractCommandVisitor); begin Visitor.VAdd(self); end;
function AddCommand.Exec(const param): integer; begin // end;
{ DeleteCommand }
procedure DeleteCommand.Accept(Visitor: AbstractCommandVisitor); begin Visitor.VDelete(self); end;
function DeleteCommand.Exec(const param): integer; begin // end;
{ MenuBarCommandVisitor }
procedure MenuBarCommandVisitor.VAdd(Command: AddCommand); begin Showmessage('Enable ADD Command'); end;
procedure MenuBarCommandVisitor.VCurrent(Command: CurrentCommand); begin Showmessage('Enable Current Command'); end;
procedure MenuBarCommandVisitor.VDelete(Command: DeleteCommand); begin Showmessage('Enable Delete Command'); end;
{ CurrentCommand }
procedure CurrentCommand.Accept(Visitor: AbstractCommandVisitor); begin Visitor.VCurrent(self); end;
function CurrentCommand.Exec(const param): integer; begin // end;
procedure TForm1.Button1Click(Sender: TObject); var DynaCmds:DynaCommands; MenuBar:MenuBarCommandVisitor; begin try DynaCmds:=DynaCommands.create([AddCommand.Create,CurrentCommand.Create]); try //Disable menu item MenuBar:=MenuBarCommandVisitor.Create; try //Menu init DynaCmds.Accept(MenuBar); if not DynaCmds.TryPerfomOp(DeleteCommand,self) then showmessage('Not such command DeleteCommand'); if DynaCmds.TryPerfomOp(CurrentCommand,self) then showmessage('Not such command CurrentCommand') finally MenuBar.free; end; finally DynaCmds.free; end; except end; end;
-
> if DynaCmds.TryPerfomOp(CurrentCommand,self) then showmessage('Not > such command CurrentCommand')
Есть такая команда. :)
-
> [21] oxffff © (26.01.08 01:24)
Смотрю
-
Понял, таки это решение с командами. А хотелось бы от них избавится.
Благодарю за обсужение. Пользу извлек такую если ты не пддерживаешь интерфейс, то нехрен говорить, что поддреживаешь.
:)
-
> Как дисэйблить кнопки если операция не поддерживается… ? >
Button.Enabled := false;
Чего гадать-то ?
В свое время тоже маялся подобной заумью, получилось следующее:
Есть MDI-форма с тулбаром, на тулбаре кнопки, на кнопках Actions, в зависимости от допустимости операций с текущим активным MDI-дитем, кнопки должны быть открыты или закрыты.
type TCommandType = (ctFind, ctGoto); TCommandTypes = set of TCommandType;
IToolbarCommands = interface ['{D97A7812-091F-4E2F-84DA-08A394646BC2}'] function SupportedCommands : TCommandTypes; procedure FindCommand; procedure GotoCommand; end;
И использование:
procedure TfrmMain.ActionList1Update(Action: TBasicAction; var Handled: Boolean); var Supported: TCommandTypes; IC: IToolbarCommands; begin if Assigned(ActiveMDIChild) and ActiveMDIChild.GetInterface(IToolbarCommands, IC) then Supported := IC.SupportedCommands else Supported := []; actFind.Enabled := ctFind in Supported; actGoto.Enabled := ctFind in Supported; end;
Теперь бы делал иначе.
> Понятно, что удобно узать стратегии.
Keep It Simple, Stupid
-
> получилось следующее:
Просто и понятно.
> Теперь бы делал иначе.
А как? если не секрет? Оч. интересно
Хотелось бы, чтобы дабавлять команды было просто, дисэбл делался автоматически и код был простым
> Keep It Simple, Stupid
В смысле Short and Simple ? :)
-
> actFind.Enabled := ctFind in Supported; > actGoto.Enabled := ctFind in Supported;
Вот это только плохой кусок, тут придется добавлять вручную
-
> Kolan © (27.01.08 09:53) [27] > > actFind.Enabled := ctFind in Supported; > > actGoto.Enabled := ctFind in Supported; > > Вот это только плохой кусок, тут придется добавлять вручную…
Рассмотри другой способ. Команда сама предоставляет callback процедуру и/или иконку. Твой Menu опрашивает команды на наличие этой функциональности. И в случае отсутствия ставит произвольную иконку. Так ты сможешь избавиться от статической привязки построителя меню к набору обрабатываемых им конанд. + обеспечишь подрузку внешних комманд.
-
Надо подумать
-
Kolan © (27.01.08 09:52) [26]
> А как? если не секрет? Оч. интересно…
Унаследовал бы класс формы от предка, в котором были бы методы CanFind, CanGoto (это в моем случае) и честно бы их опрашивал.
Код получился бы короче и яснее.
> В смысле Short and Simple ? :)
В смысле будь проще. Не умножай сущности сверх необходимости. Подумай что тебе важнее - иметь возможность быстро и с удовольствием прочитать исходный текст программы и понять, что она делает или городить огород с динамическими присвоениями, запутывая код нагромождением слоев.
Задай себе вопрос - что тебе чаще придется делать - читать код или дополнять его функциональность.
> Вот это только плохой кусок, тут придется добавлять вручную…
В твоем случае, как бы ты не сделал, тоже придется добавлять вручную.
Напоследок немножно помедитируй над цитатой:
"ОО-языки упрощают абстракцию, возможно, даже слишком ее упрощают. Они поддерживают создание структур с большим количеством связующего кода и сложными уровнями. Это может оказаться полезным в случае, если предметная область является действительно сложной и требует множества абстракций, и вместе с тем такой подход может обернуться неприятностями, если программисты реализуют простые вещи сложными способами, просто потому что им известны эти способы и они умеют ими пользоваться. Все ОО-языки несколько сколнны "втягивать" программистов в ловушку избыточной иерархии. Чрезмерное количество уровней разрушает прозрачность: крайне затрудняется их просмотр и анализ ментальной модели, которую по существу реализует код. Всецело нарушаются правила простоты, ясности и прозрачности, а в результате код наполняется скрытыми ошибкми и создает постоянные проблемы при сопровождении. Данная тенденция, вероятно, усугубляется тем, что множество курсов по программированию преподают громоздкую иерархию как способ удовлетворения правила представления. С этой точки зрения множество классов приравнивается к внедрению знаний в данные. Проблема данного подхода заключается в том, что слишком часто "развитые данные" в связующих уровнях фактически не относятся у какому-либо естественному объекту в области действия программы - они предназначены только для связующего уровня. Одной из причин того, что ОО-языки преуспели в большинстве характерных для них предметных областей (GUI-интерфейсы, моделирование, графические средства), возможно, является то, что в этих областях относительно трудно неправильно определить онтологию типов. Например, в GUI-интерфейсах и графических средствах присутствует довольно естественное соотвествие между манипулируемыми визуальными объектами и классами. Если выясняется, что создается большое количество классов, которые не имеют очевидного соответствия с тем, что происходит на экране, то, соотвественно, легко заметить, что связующий уровень стал слишком большим."
(с) Эрик Рэймонд, Искусство программирования для Unix
-
> честно бы их опрашивал
Что это значит? То есть кнопки бы всегда были активны?
> Напоследок немножно помедитируй над цитатой:
Медитирую
-
Kolan © (27.01.08 12:56) [31]
> Что это значит? То есть кнопки бы всегда были активны?
Это значит, что в обработчике события ActionListUpdate я бы смотрел, является ли текущее окно экземпляром класса, поддерживающего эти операции и если да, то опрашивал бы эти методы.
actFind.Enabled := (ActiveMDIChild is TMyClass) and TMyClass(ActiveMDIChild).CanFind
как-то так.
-
> Это значит,
Ааа, не увидел что тут CanFind. Понял. Тогда на каждую операцию еще надо добавить Can операцию. Довольно просто. Но мне кажется, что мой вариант с интерфейсам еще лучьше, бо не надо будет Can операцию добавлять и проверка попроще. Будет так: actFind.Enabled := ActiveMDIChild.GetInterface(IFind, TheInt); Вообщем понятно. Много вариантов получил. Благодарю за обсуждение.
-
> Будет так: > actFind.Enabled := ActiveMDIChild.GetInterface(IFind, TheInt); >
Тогда уж:
actFind.Enabled := Supports(ActiveMDIChild, IFind);
Небольшая разница, но код становится яснее.
-
> Небольшая разница, но код становится яснее.
Согласен.
Имхо ниче так решение особенно в сочетании со стратегиями. Можно сделать мелкие интерфейсы (IFind, IGoto), а стратегии(или MDI Children) будут реализовывать их комбинации.
Благодарю. :)
|