Форум: "Основная";
Текущий архив: 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