powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Кто подскажет как сделать оптимально? Фильтрация
12 сообщений из 12, страница 1 из 1
Кто подскажет как сделать оптимально? Фильтрация
    #32234744
Alexander2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Привет!

Ситуация была такая: 5 TEdit окошек для ввода подстроки для фильтра

на кнопку Поиск повесил:

Screen.Cursor := crSQLWait;
with dsProjects.DataSet do
begin
Filtered := False;
Filtered := True;
end;
Screen.Cursor := crDefault;

Однако новые окна появились для фильтра: Страна и Город
теперь всего 7 фильтров!

код клиента
имя клиента
код проекта
имя проекта
регион
страна
город

а сколько из них комбинаций!!!!!
вначале (когда было 5) я по-тупому прописал все 28 комбинаций

1
2
3
4
5
===
1-2
1-3
1-4
1-5
--------
1-2-3
1-2-4
1-2-5
-------
1-3-4
1-3-5
------
1-4-5
---------
1-2-3-4
1-2-3-5
---------
1-2-4-5
---------
1-3-4-5
-----------
1-2-3-4-5
=====
2-3
2-4
-------
2-3-4
2-3-5
=====
3-4
3-5
----------
3-4-5
====
4-5
====

прописал так для ClientDataSet для события OnFilterRecord: (это примеры)

// ================== 1
If (eClient.Text <> '')
and (eNameClient.Text = '')
and (eProject.Text = '')
and (eName.Text = '')
and (eSite.Text = '')
then
Accept := Pos(LowerCase(eClient.text), LowerCase(dsProjects.Dataset.fieldbyname('AcuityClientCode').asstring))>0;
....
// ================= 2-4
If (eClient.Text = '')
and (eNameClient.Text <> '')
and (eProject.Text = '')
and (eName.Text <> '')
and (eSite.Text = '')
then
Accept :=(Pos(LowerCase(eName.text),LowerCase(dsProjects.Dataset.fieldbyname('title').asstring))>0)
and(Pos(LowerCase(eNameClient.text),LowerCase(dsProjects.Dataset.fieldbyname('Client').asstring))>0);
......
// =============== 1-2-3-4
If (eClient.Text <> '')
and (eNameClient.Text <> '')
and (eProject.Text <> '')
and (eName.Text <> '')
and (eSite.Text = '')
then Accept:=(Pos(LowerCase(eClient.text),LowerCase(dsProjects.Dataset.fieldbyname('AcuityClientCode').asstring))>0)
and (Pos(LowerCase(eNameClient.text), LowerCase(dsProjects.Dataset.fieldbyname('Client').asstring))>0)
and (Pos(LowerCase(eProject.text),LowerCase(dsProjects.Dataset.fieldbyname('ProjOrder').asstring))>0)
and (Pos(LowerCase(eName.text), LowerCase(dsProjects.Dataset.fieldbyname('title').asstring))>0);
.......
короче, пришлось все варианты прописать.

А кто знает как сделать оптимальнее, потому что если добавить еще 2 окна - то вариантов будет для присутствия "1" уже 48
а всего я даже боюсь считать
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32234754
Alexander2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
насчитал 95 вариантов
1
1-2
1-2-3
1-2-3-4
1-2-3-4-5
1-2-3-4-6
1-2-3-4-7
1-2-3-5
1-2-3-6
1-2-3-7
1-2-4
1-2-4-5
1-2-4-6
1-2-4-7
1-2-5
1-2-5-6
1-2-5-7
1-2-6
1-2-7
1-3
1-3-4
1-3-4-5
1-3-4-5-6
1-3-4-5-7
1-3-4-6
1-3-4-7
1-3-5
1-3-5-6
1-3-5-7
1-3-6
1-3-7
1-4
1-4-5
1-4-5-6
1-4-5-6-7
1-4-5-7
1-4-6
1-4-7
1-5
1-5-6
1-5-6-7
1-5-7
1-6
1-6-7
1-7
2
2-3
2-3-4
2-3-4-5
2-3-4-5-6
2-3-4-5-7
2-3-4-6
2-3-4-6-7
2-3-4-7
2-3-5
2-3-6
2-3-7
2-4
2-4-5
2-4-6
2-4-7
2-5
2-5-6
2-5-7
2-6
2-6-7
3
3-4
3-4-5
3-4-5-6
3-4-5-7
3-4-6
3-4-6-7
3-4-7
3-5
3-5-6
3-5-7
3-6
3-6-7
3-7
4
4-5
4-5-6
4-5-6-7
4-5-7
4-6
4-6-7
4-7
5
5-6
5-6-7
5-7
6
6-7
7
неужели все придется прописать?
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32234800
Andrew_256
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не проверял в Delphi, но работать должно.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
var
  Filters : TStringList;
  i : Integer;
  FilterSatisfy : Boolean;
begin
  Accept := false;
  FilterSatisfy := true;

  Filters := TStringList.Create;
  try
    Filters.Add(Format('%s=%s',['AcuityClientCode',eClient.text]));
    Filters.Add(Format('%s=%s',['Client',eNameClient.text]));

    for i:= 1  to Filters.Count do
      if(Filters.Values[Filters.Names[i- 1 ]] <> '') and
        (Pos(LowerCase(Filters.Values[Filters.Names[i- 1 ]]),
            LowerCase(dsProjects.Dataset.fieldbyname(Filters.Names[i- 1 ]).asstring))=  0 ) then
    begin
       FilterSatisfy := false;
       break;
    end;
    Accept := FilterSatisfy;
  finally
    Filters.Free;
end;
 
end;
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32234842
Alexander2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Andrew

не понял как этот кусок будет работать для других полей, хоть стукните меня!
-----------------------------------------
пока ждал ответов - нарисовал так

var
mystring,
mystring1,
mystring2,
mystring3,
mystring4,
mystring5,
mystring6,
mystring7: String;
myinteger :Integer;

If eClient.Text <> '' then mystring1:='1';
If eNameClient.Text <> '' then mystring2:='2';
If eProject.Text <> '' then mystring3:='3';
If eName.Text <> '' then mystring4:='4';
If eSite.Text <> '' then mystring5:='5';
If eCountry.Text <> '' then mystring6:='6';
If eCity.Text <> '' then mystring7:='7';

myinteger:=StrToInt(mystring1+mystring2+mystring3+mystring4+mystring5+mystring6+mystring7);

Case myinteger of

1: Accept := Pos(LowerCase(eClient.text), LowerCase(dsProjects.Dataset.fieldbyname('AcuityClientCode').asstring))>0;
2: ......
.....
1234: Accept:=(Pos(LowerCase(eClient.text),LowerCase(dsProjects.Dataset.fieldbyname('AcuityClientCode').asstring))>0)
and (Pos(LowerCase(eNameClient.text), LowerCase(dsProjects.Dataset.fieldbyname('Client').asstring))>0)
and (Pos(LowerCase(eProject.text),LowerCase(dsProjects.Dataset.fieldbyname('ProjOrder').asstring))>0)
and (Pos(LowerCase(eName.text), LowerCase(dsProjects.Dataset.fieldbyname('title').asstring))>0);
.....
и так 98 вариантов

end;
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32234922
Andrew_256
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Что значит "для других" полей?

В куске
Код: plaintext
1.
  Filters.Add(Format('%s=%s',['AcuityClientCode',eClient.text]));
   Filters.Add(Format('%s=%s',['Client',eNameClient.text]));
добавляешь все пары поле БД- текст из edit, которые у тебя есть в фильтре и все. А работает по простому принципу:
1. Проверяем каждый фильтр (текст из edit). Если не "" и не подходит, то не делаем отсальные проверки - у тиебя же условие И везде.
2. Если нигде не прервали - значит запись подходит.
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32234946
Дмитрий Мыльников
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну и зачем так усложнять?
Заводим текстовую строку, которую перед началом генерации строки фильтра обнуляем.
Далее проверяем первый TEdit, если он не пустой, то добавляем к строке условие.
Для всех остальных TEdit, если он не пустой, сначала проверяем что там в стороке фильтра. Если она пустая, то просто добавляем к ней условие, если же в ней уже что-то есть, то в начале добавляем ' and '

if TEdit.Text<>'' then
if s<>'' then s:=s+' and '+условие else s:=условие;

после чего эту строку вставляем в фильтр.

То есть, вместо н-цати вариантов получится столько проверок, сколько есть TEdit
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32234964
Andrew_256
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А что потом делать со строкой '... and ... and ...'? Мы же не SQL выражение формируем, нам нужно проверять в pascal коде.
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32235002
а дальше пишим что-то типа такого:


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
IsFirst:=false;
str:='';
if(Edit1<>'')then
begin
  if IsFirst then IsFirst:=false
  else str:=str+' and ';
  str:=str+'field1 = '+Edit1.Text;
end
if(Edit2<>'')then
begin
  if IsFirst then IsFirst:=false
  else str:=str+' and ';
  str:=str+'field2 = '+Edit2.Text;
end
if(Edit3<>'')then
begin
  if IsFirst then IsFirst:=false
  else str:=str+' and ';
  str:=str+'field3 = '+Edit3.Text;
end

//Таких условий повторяеш столько сколько полей надо проверить,
//потом накладываеш фильтр

DataSet.Filtered:=false;
DataSet.Filter:=str;
DataSet.Filtered:=true;
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32235096
Андрей Бабенко
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С описаным вами подходом можно мягко говоря быстро устать.
Я бы посоветовал создать для себя универсальный компонент для такого рода фильтрации.

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

Например структура типа
FieldName - имя поля
TypeField - тип поля (хотя не обязательно, вы его и так можете определить)
DisplayName
....

В зависимости от типа поля создавайте контрол типа Tedit, TDatePicker и т.д.

Необходимо учесть также, что ваш набор данных отображаемых клиенту, так же может быть уже с наложенным фильтром, который пользователь не должен "сбросить". Его придется где-то хранить и добавлять перед включением фильтрации.

Также желательно добавить критерий с которым добавляемое условие фильтрации связывается с уже существующим (И, ИЛИ....)

Посоветовал бы вам посмотреть компоненты от InfoPower, там достаточно неплохой фильр имеется

Вобщем вариантов много, и "оптимального" наверное не существует.
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32235444
Ulyanitsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вот так бы сделал я:
// 1) Не знаю как в других версиях Делфи, но в Д7 в TADODataSet filter есть и работает,
// так воспользуемся им:

procedure TForm1.Button1Click(Sender: TObject);
var
flt: String;

procedure AddFilterEquation(
AFieldName, //имя поля
AString: String; //параметр для фильтрации
AFirstDelimiter: String = ''; ALastDelimiter: String = ''; // если строка, то здесь должны передаваться кавычки
AOperator: String = '=' //операция
);
begin
if AString = '' then //нечего фильтровать
Exit;

if flt <> '' then //если несколько условий добавляем and
flt := flt + ' and ';

if (AString in ['=', '<', '>']) then
AOperator := ''; //пользователь сам задал операцию, напр.:
//<>1000
//=999
//>666
flt := flt + AFieldName + AOperator +
AFirstDelimiter + AString + ALastDelimiter;
end;

begin
flt := '';

AddFilterEquation('Field1', Edit1.Text); //числовое значение, без кавычек
AddFilterEquation('Field2', Edit2.Text); //числовое значение, без кавычек
AddFilterEquation('Field3', Edit3.Text, '''', ''''); //полное сравнение строк, кавычки надо
AddFilterEquation('Field4', Edit3.Text, '''', '*''', ' like '); //частичное совпадение строк
// и так далее...

ADODataSet1.Filtered := False;
ADODataSet1.Filter := flt;
ADODataSet1.Filtered := True;
end;

// 2) Если filter не работает, то обрабатываем событие OnFilterRecord:

procedure TForm1.Button3Click(Sender: TObject);
begin
ADODataSet1.Filtered := False;
ADODataSet1.Filtered := True;
end;

procedure TForm1.ADODataSet1FilterRecord(DataSet: TDataSet;
var Accept: Boolean);
begin

Accept := True;

//число
if Edit1.Text <> '' then
Accept := Accept and (DataSet['Field1'] = Edit1.Text);

//строка, полное совпадение
if Edit2.Text <> '' then
Accept := Accept and (AnsiCompareText(DataSet['Field2'], Edit2.Text) = 0);

//строка, неполное совпадение начиная с начала
if Edit3.Text <> '' then
Accept := Accept and (AnsiStartsText(Edit3.Text, DataSet['Field3']));

// и так далее, хоть до бесконечности...
end;

//P.S.
// во втором примере не забудь(те) uses StrUtils;
// Удачи!
// Nicholas Ulyanitsky, Ulyanitsky@list.ru, ICQ: 161262935
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32235969
Alexander2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
спасибо за комментарии!
===================================================
млин! все гораздо проще оказалось = 8 строк кода !!!!!

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

нужны были скобки - поэтому вначале я сразу отбросил этот вариант


Accept:=Accept and (блаблабла);

блаблабла = Pos((LowerCase(eClient.text),LowerCase(dsProjects.Dataset.fieldbyname('AcuityClientCode').asstring))>0

то есть можно прописать сколько угодно полей для фильтра
главное, чтоб логическое выражение было правильнь написано

----------------- а вот сами 8 строк



Accept:=True;

If (eClient.text <> '') then Accept:=Accept and (Pos(LowerCase(eClient.text),LowerCase(dsProjects.Dataset.fieldbyname('AcuityClientCode').asstring))>0);
If (eNameClient.Text <> '') then Accept:=Accept and (Pos(LowerCase(eNameClient.text),LowerCase(dsProjects.Dataset.fieldbyname('Client').asstring ))>0);
If (eProject.Text <> '') then Accept:=Accept and (Pos(LowerCase(eProject.text), LowerCase(dsProjects.Dataset.fieldbyname('ProjOrder').asstring ))>0);
If (eName.Text <> '') then Accept:=Accept and (Pos(LowerCase(eName.text), LowerCase(dsProjects.Dataset.fieldbyname('title').asstring ))>0);
If (eSite.Text <> '') then Accept:=Accept and (Pos(LowerCase(eSite.text), LowerCase(dsProjects.Dataset.fieldbyname('Region').asstring ))>0);
If (eCountry.Text <> '') then Accept:=Accept and (Pos(LowerCase(eCountry.text), LowerCase(dsProjects.Dataset.fieldbyname('Country').asstring ))>0);
If (eCity.Text <> '') then Accept:=Accept and (Pos(LowerCase(eCity.text), LowerCase(dsProjects.Dataset.fieldbyname('Municipality').asstring))>0);
...
Рейтинг: 0 / 0
Кто подскажет как сделать оптимально? Фильтрация
    #32236571
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну вот видишь - когда хорошо и правильно подумаешь, получается 8 строк кода, а так - 48
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Кто подскажет как сделать оптимально? Фильтрация
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]