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

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.041 c
6-1132520333
Balex
2005-11-20 23:58
2006.02.26
Как программно открыть Word овский документ Word ом


4-1133792051
MAXHo
2005-12-05 17:14
2006.02.26
Как скрыть программу в диспетчере задачь? WindowsXP


3-1135769758
Id
2005-12-28 14:35
2006.02.26
SQL error code = -804


4-1134246335
Matrex
2005-12-10 23:25
2006.02.26
Работа с сотовым телефоном


2-1139156692
Glex
2006-02-05 19:24
2006.02.26
Как присвоить TImage другой TImage?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский