Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.02.26;
Скачать: CL | DM;

Вниз

Активна не активна кнопка "Применить"   Найти похожие ветки 

 
San#444   (2006-01-25 18:22) [0]

Во многих окнах настроек Винды есть кнопка "Применить", которая не активна, пока что-нибудь не изменишь.

Тоже самое хочу сделать в своей программе.
Не подскажете, есть ли способ получше.
Не прописывать же мне в каждом компоненте формы при его изменении "разблокировку"(enabled) этой клавиши.(тем более что таких форм много)
Заранее спасибо за ответ или ссылку.


 
Gero ©   (2006-01-25 18:30) [1]

> Не прописывать же мне в каждом компоненте формы при его
> изменении "разблокировку"(enabled) этой клавиши.(тем более
> что таких форм много)

Именно. Но никто не мешает тебе вынести разблокировку в отдельную процедуру, а обработчких для однотиптых элементов тоже сделать один.
Можно прицепить к кнопке Action и обрабатывать его OnUpdate, но сути дела это все равно не меняет.


 
san#444   (2006-01-25 18:37) [2]

2Gero: Спасибо.
>Но никто не мешает тебе вынести разблокировку в отдельную процедуру
Че ее выносить там 1 строчка enabled:=true;

>Можно прицепить к кнопке Action и обрабатывать его OnUpdate,
немного не до понял? можно пояснить?
и даст ли это хоть какое-то облегчение труда.


 
Gero ©   (2006-01-25 18:52) [3]

> Че ее выносить там 1 строчка enabled:=true;

Для универсальности правильнее было бы вынести.

> немного не до понял? можно пояснить?

С компонентом TActionList знаком?

> и даст ли это хоть какое-то облегчение труда.

В принципе, нет, но будет логичнее.


 
Джо ©   (2006-01-25 19:20) [4]

Действительно, для централизованного управления лучше использовать TActionList.
А чтобы свести к миниму рутину проверок и автоматизировать ее предлагаю такое решение.

Ну, первое. Необходимо для кнопки "Применить" завести отдельный Action в TActionList"е.

Далее используем такое юнит.

unit ChangeFinder;

interface
uses SysUtils, Classes, Controls, Forms, Contnrs;

type

 IStateHolder = interface
   ["{335B2FA7-678D-4B3B-976A-9D139590575B}"]
   procedure SaveState (AComponent: TComponent; PropName: string);
   function IsChanged: Boolean;
 end;

function CreateStateHolder: IStateHolder;

implementation
uses TypInfo;

type
 TComponentState = class
 private
   FComponent: TComponent;
   FPropertyName: string;
   FValue: Variant;
 public
   constructor Create (AComponent: TComponent; APropertyName: string); reintroduce;
   property Component: TComponent read FComponent;
   property PropertyName: string read FPropertyName;
   function Equal (Another: TComponentState): Boolean;
 end;

 TStateHolder = class (TInterfacedObject, IStateHolder)
 private
   FList: TObjectList;
 public
   constructor Create;
   destructor Destroy; override;
   procedure SaveState (AComponent: TComponent; PropName: string);
   function IsChanged: Boolean;
 end;

function CreateStateHolder: IStateHolder;
begin
 Result := TStateHolder.Create
end;

function GetPropertyValue (Component: TComponent; PropertyName: string): Variant;
begin
if GetPropInfo(Component,PropertyName) = nil then
  raise Exception.CreateFmt ("Property %s not found",[PropertyName]);

Result := GetPropValue (Component,PropertyName);
end;

constructor TStateHolder.Create;
begin
 inherited Create();
 FList := TComponentList.Create(True);
end;

destructor TStateHolder.Destroy;
begin
 FList.Free;
 inherited;
end;

function TStateHolder.IsChanged: Boolean;
var
 I: Integer;
 State1,
 State2: TComponentState;
begin
 Result := False;
 for I := 0 to FList.Count - 1 do
 begin
   State1 := TComponentState(FList[I]);
   State2 := TComponentState.Create(State1.Component,State1.PropertyName);
   try
      if not State1.Equal(State2) then
      begin
        Result := True;
        Break
      end
   finally
     State2.Free
   end
 end
end;

procedure TStateHolder.SaveState(AComponent: TComponent; PropName: string);
begin
 FList.Add( TComponentState.Create(AComponent,PropName))
end;

constructor TComponentState.Create(AComponent: TComponent;
 APropertyName: string);
begin
 inherited Create();
 
 FValue := GetPropertyValue(AComponent,APropertyName);
 FComponent := AComponent;
 FPropertyName := APropertyName;
end;

function TComponentState.Equal(Another: TComponentState): Boolean;
begin
 Result := (FComponent=Another.FComponent) and
           (FPropertyName=Another.FPropertyName) and
           (FValue=Another.FValue);
end;

end.

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

Применять вот так.
В классе формы определяем
 private
   FStateHolder: IStateHolder;


В OnCreate формы, после установки значений по умолчанию для компонентов создаем экз. хранилища, а затем делаем "снимок" текущего состояния компонентов:
procedure TForm17.FormCreate(Sender: TObject);
begin
 ///
 /// тут можем устанавливаем (или нет) значения свойств компонентов
 ///

 // создаем экземпляр хранилища
 FStateHolder := CreateStateHolder;

 // сохраняем свойства компонентов
 with FStateHolder do
 begin
   SaveState(Edit1,"Text");
   SaveState(Edit2,"Text");
   SaveState(CheckBox1,"Checked");
   SaveState(CheckBox2,"Checked");            
 end;
end;


Далее, назначаем нашей кнопке созданный Action (пусть будет acApply) в дизайнере.
В событии OnUpdate нашего ActionList"а пишем:

procedure TForm17.ActionList1Update(Action: TBasicAction; var Handled: Boolean);
begin
 // если что-то изменилось, то Enabled
 acApply.Enabled :=
   FStateHolder.IsChanged;
end;


Всё :)

Достоинства:
1. Автомат.
2. Кнопка Apply опять становиться неактивной, если свойство компонента вернуть в первоначальное состояние.

П.С. Написано "на колене", но вроде работает.


 
Gero ©   (2006-01-25 19:23) [5]

> Джо ©   (25.01.06 19:20)

Мощно задвинул :)


 
Gero ©   (2006-01-25 19:27) [6]

> with FStateHolder do
> begin
>   SaveState(Edit1,"Text");
>   SaveState(Edit2,"Text");
>   SaveState(CheckBox1,"Checked");
>   SaveState(CheckBox2,"Checked");            
> end;

Только вот это вот неудобно, сам понимаешь, список может быть очень большим. Возможно, имеет смысл автоматически определять меняющееся свойство (для стандартных комоненетов), сделав параметр PropName default,  и учитывать его значение только если он непустой, в противном случае брать стандартное для объекта значение.

Хотя списко компонентов все равно придется руками набивать. Тут можно разве что комопнент визуальным сделать и PropertyEditor хороший :)


 
Джо ©   (2006-01-25 19:29) [7]

> [6] Gero ©   (25.01.06 19:27)

Возможности для расширения — безграничны :) Я просто идею предложил.


 
Rouse_ ©   (2006-01-25 19:52) [8]


> Джо ©   (25.01.06 19:20) [4]

Фига себе двинул мысль :) Надо поразмышлять над идейкой :) Маладца :)


 
Гаврила ©   (2006-01-25 20:02) [9]


> Достоинства:


> 2. Кнопка Apply опять становиться неактивной, если
> свойство компонента вернуть в первоначальное состояние.


Этого не отнять, но, имхо, не критично, если этого и не произойдет

>SaveState(Edit1,"Text");
>   SaveState(Edit2,"Text");
>   SaveState(CheckBox1,"Checked");
>    SaveState(CheckBox2,"Checked");            


а не проще ли тогда, если все равно перечислять:
Edit1.OnChange:=UpdateBtnState;
Edit2.OnChange:=UpdateBtnState;
CheckBox1.OnClick:=UpdateBtnState;
CheckBox2.OnClick:=UpdateBtnState;

и все?


 
pasha_golub ©   (2006-01-25 20:03) [10]

TAction рулит безбожно!!! Сам только недавно понял всю прелесть.


 
Джо ©   (2006-01-25 20:22) [11]

[9] Гаврила ©   (25.01.06 20:02)
> Edit1.OnChange:=UpdateBtnState;
> Edit2.OnChange:=UpdateBtnState;
> CheckBox1.OnClick:=UpdateBtnState;
> CheckBox2.OnClick:=UpdateBtnState;

Еще нужно в UpdateBtnState"е написать код :) Это раз.
В UpdateBtnState может быть другой код, причем, для некоторых компонентов — свой. Значит, код на изменения свойства нужно будет прописывать в каждый из OnChange. Это два :)
Кроме того, вот Gero неплохие идеи по расширению этого дела подкинул.
Если немного доработать, можно критически сократить формальную писанину.

Ну, и то, что мой вариант завязан на ActionList.OnUpdate, имхо, более универсально и стандартно.
:)


 
san#444   (2006-01-25 20:30) [12]

Всем ОГРОМНОЕ спасибо!!!
Попозже еще поразбераюсь и поищу может что нибудь получится если наткнусь на простое решение обязательно сюда напишу.


 
san#444   (2006-01-25 20:52) [13]

Помню где-то был кусок кода, проходил по всем компонентам формы.

Кажется это даст решение: применить идею Джо + реализовать предложение Gero
>сделав параметр PropName default
+
>SaveState(Edit1,"Text");
>   SaveState(Edit2,"Text");
>   SaveState(CheckBox1,"Checked");
>    SaveState(CheckBox2,"Checked");  
автоматизировать с помощью ране упомянутого куска кода=нет геморою:)

Осталось откопать в закромах этот "кусок" :)


 
Джо ©   (2006-01-25 20:58) [14]

> [13] san#444   (25.01.06 20:52)
> Помню где-то был кусок кода, проходил по всем компонентам
> формы.

Там кода на 2 строки
for I := 0 to FormVariable.ComponetsCount-1 do
 ... := FormVariable.Components[I]


 
Джо ©   (2006-01-25 21:00) [15]

Кроме того, смотри пост [3] в ветке
http://delphimaster.net/view/1-1138040948/

Возможно, появятся дальнейшие идеи :)


 
Джо ©   (2006-01-25 22:00) [16]

В общем, вот вариант такой вариант для сокращения писанины.

В интерфейсе добавляем метод:
 IStateHolder = interface
   ...
   procedure SaveStatesFor (AForm: TForm; AComponentClass:
   ...
 end;

И его реализацию:

 
 TStateHolder = class (TInterfacedObject, IStateHolder)
   ...
   procedure SaveStatesFor (Form: TForm; ComponentClass: TComponentClass;
     PropName: string);
 end;

...

procedure TStateHolder.SaveStatesFor(Form: TForm;
 ComponentClass: TComponentClass; PropName: string);
var
 I: Integer;
begin
 for I := 0 to Form.ComponentCount-1 do
   if Form.Components[I] is ComponentClass then
     SaveState (Form.Components[I], PropName)
end;


---
Использование выглядит совсем просто:

 with FStateHolder do
 begin
   // запоминается состояние всех наследников TEdit на форме
   SaveStatesFor(Self,TEdit,"Text");
   // запоминается состояние всех наследников TCheckBox на форме
   SaveStatesFor(Self,TCheckBox,"Checked");    
 end;

Тут есть маленькие нюансы, но, в принципе, можно пойти таким путем :)


 
san#444   (2006-01-25 22:45) [17]

Согласен хороший путь. В основном компоненты в которых что-то изменяется это Edit,Checkbox,Button,Combobox и несколько других самых распространенных, а остальные не лень и вручную написать.

Можно будет использовать для всех окон приложения в целом, так что круче могут быть только яйца:)



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

Текущий архив: 2006.02.26;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.046 c
3-1136217119
ищущий ответ
2006-01-02 18:51
2006.02.26
Ограничения Paradox


1-1138100653
VEZ
2006-01-24 14:04
2006.02.26
StringGrid


15-1138874515
Jeer
2006-02-02 13:01
2006.02.26
Энергоаудит


2-1139767591
Виталик___
2006-02-12 21:06
2006.02.26
Работа с файлами


1-1138158446
eugie
2006-01-25 06:07
2006.02.26
экспорт рисунка в Excel