Добрый день. как исправить неудобство в контекстном меню фильтра формы...
Когда вносишь изменения в числовое поле - можно все сделать исключительно мышью. выбрал поле с цифровыми значениями, кликнул левой по столбцу "Значение", кликнул правой - открылось контекстное меню вставки значения.
совершенно иначе происходит, когда пытаешься вставить текстовое содержимое в текстовое поле. Клик правой кнопкой мыши тоже выводит контекстное меню. но. оно предыдущего уровня, когда выбираешь действия "Добавить поле", "Удалить поле" и т.д. А контекстное меню вставки значений почему то нет на текстовом поле.
Неудобно. как то можно это поправить?
Фильтр формы -разнобой в контекстном меню.
-
neznayka-na-lune
- Интересующийся
- Сообщения: 130
- Зарегистрирован: 22 дек 2025, 16:10
- Благодарил (а): 21 раз
- Поблагодарили: 17 раз
-
neznayka-na-lune
- Интересующийся
- Сообщения: 130
- Зарегистрирован: 22 дек 2025, 16:10
- Благодарил (а): 21 раз
- Поблагодарили: 17 раз
Фильтр формы -разнобой в контекстном меню.
admin писал(а):Доработаю.
доброго здравия. достала меня эта проблема. потому попросил нечеловеческий интеллект предложить решение. далее нечеловеческий текст и код.
Изучив исходный код модулей, отвечающих за интерфейс фильтра формы в DataExpress (`formfiltersform.pas` — управление пресетами и `filtercontrol.pas` — сам UI-компонент грида фильтра), я действительно вижу ряд архитектурных и логических недоработок.
Поскольку вы не уточнили, с чем именно столкнулись, я приведу наиболее критичные проблемы, которые бросаются в глаза при анализе кода.
### 1. Отсутствие проверки уникальности имен (Критично)
В модуле `formfiltersform.pas` при добавлении или переименовании фильтра не проверяется, существует ли уже пресет с таким именем.
**Проблемный код:**
```pascal
procedure TFormFiltersFm.MenuItem1Click(Sender: TObject);
var S: String;
begin
S := InputBox(rsFilterName, rsEnterFilterName, '');
if S <> '' then
begin
List.Items.Add(S); // Дубликаты разрешены!
...
```
**Почему это плохо:** При сохранении (`SaveList`) данные пишутся в `FFm.Filters` в формате `Name=Value`. Если в списке будет два фильтра с одинаковыми именами, это может сломать логику поиска пресетов в `TStringList` или привести к перезаписи значений.
**Решение:** Необходимо добавить проверку `List.Items.IndexOf(S) >= 0` и, при совпадении, выдавать предупреждение и прерывать операцию.
### 2. Небезопасный разделитель в `SaveList` / `LoadList`
Сохранение пресетов реализовано через простое склеивание строк:
```pascal
L.Add(List.Items[i] + '=' + FFilters[i]);
```
Если пользователь назовет фильтр, например, *«Прибыль = 1000»* или в самом XML/сериализации фильтра (`FFilters[i]`) встретится неэкранированный знак `=`, стандартный парсер `TStringList` (`Names` и `ValueFromIndex`) разобьет строку некорректно. Это приведет к «битым» пресетам при следующей загрузке.
**Решение:** Использовать более надежный формат (например, JSON, INI или экранирование спецсимволов).
### 3. Логика копирования пресетов
При копировании фильтра (`MenuItem9Click`) создается полная копия с тем же самым именем, но диалог редактирования (`EditFilter`) **не открывается** автоматически.
```pascal
List.Items.Add(S);
FFilters.Add(SS);
List.ItemIndex := List.Count - 1;
FModified := True;
```
В результате пользователь получает два абсолютно одинаковых пресета в списке, что путает. Логичнее либо сразу предлагать ввести имя для копии, либо автоматически открывать окно редактирования.
### 4. Управление памятью и владение формами
В методе `EditFilter` форма редактора создается без владельца:
```pascal
FilterFm := TFilterFm.Create(nil);
```
Хотя далее следует `FilterFm.Free`, в случае возникновения исключения (например, при некорректных данных внутри `TFilterObject`) форма останется висеть в памяти. В LCL принято передавать владельца (`Self` или `Application`) или использовать конструкцию `try...finally`.
### 5. Архитектура `filtercontrol.pas` (Сам UI-грид)
Модуль `filtercontrol.pas` перегружен наследниками `TCustomControl` (`TFilterRange`, `TFilterPeriod`, `TTimeIntervalEdit`), которые сами по себе являются «контейнерами» для других контролов (например, `FBegin`, `FEnd: TFilterDate`).
* **Проблема:** Обработка фокуса (`SetFocus`), порядка обхода (Tab Order) и всплывающих меню (`MenuPopup`) в таких составных контролах часто работает нестабильно, особенно в Linux (GTK2/Qt), на что косвенно указывают недавние коммиты с «адаптацией для линукс» и исправлениями «ограничения размера сетки».
* **Проблема:** Использование кастомных сообщений (`GM_SETGRID`, `GM_SETPOS`) для привязки редакторов к гриду вместо стандартных механизмов `Parent` и `Align` усложняет отладку и поддержку.
---
**Уточните, пожалуйста:** с какой именно проблемой вы столкнулись?
1. Пользователи теряют фильтры или получают ошибки при сохранении/загрузке (баг с `=`)?
2. Форма фильтров «разваливается» или теряет фокус в Linux?
3. Или вы планируете рефакторинг этого модуля и хотите обсудить архитектуру?
Если у вас есть конкретные шаги для воспроизведения бага, напишите их, и я предложу готовый патч (исправленный код).
### Причина проблемы
Разница в поведении меню между числовыми и текстовыми полями кроется в архитектурной реализации их редакторов в `filtercontrol.pas`:
1. **Числовые поля (`TFilterRange`):** Это составной контрол (`TCustomControl`), внутри которого размещены полноценные `TEdit` (`TFilterEdit`), имеющие установленного родителя (`Parent`). При правом клике LCL корректно маршрутизирует событие в дочерний элемент, и всплывает его собственное меню.
2. **Текстовые поля (`TTextEdit`):** Это наследник `TStringCellEditor`, который `TStringGrid` динамически размещает поверх ячейки. У самого грида (`TFilterControl`) жестко задано глобальное контекстное меню (`FPopup`). В LCL `TStringGrid` перехватывает правый клик (`LM_RBUTTONDOWN`/`LM_CONTEXTMENU`) на уровне своего окна, чтобы показать свое меню, и не дает "виртуальному" редактору показать свое.
### Решение
Необходимо перехватить метод `DoContextPopup` в `TFilterControl`. Этот метод вызывается непосредственно перед показом контекстного меню. Мы можем проверить: если активен текстовый редактор и клик пришелся на него, показать его собственное меню, запретив показ меню грида.
#### Инструкция по применению (Патч)
Вам нужно внести изменения в модуль `filtercontrol.pas`:
**1. В секции `interface` добавьте объявление метода в класс `TFilterControl`:**
```pascal
{ TFilterControl }
TFilterControl = class(TStringGrid)
// ... (остальной код)
protected
function DoContextPopup(MousePos: TPoint; var Handled: Boolean): Boolean; override;
// ... (остальной код)
```
**2. В секции `implementation` добавьте реализацию метода:**
```pascal
function TFilterControl.DoContextPopup(MousePos: TPoint; var Handled: Boolean): Boolean;
var
ScreenPos: TPoint;
begin
// Проверяем, активен ли сейчас текстовый редактор, виден ли он,
// и пришелся ли правый клик именно на его область
if (Editor <> nil) and (Editor is TTextEdit) and Editor.Visible and
PtInRect(Editor.BoundsRect, MousePos) then
begin
// Преобразуем координаты в экранные и показываем меню редактора
ScreenPos := ClientToScreen(MousePos);
TTextEdit(Editor).PopupMenu.Popup(ScreenPos.X, ScreenPos.Y);
Handled := True; // Сообщаем LCL, что мы сами обработали контекстное меню
Exit(True);
end;
// Во всех остальных случаях (клик по пустому месту, по заголовку или по другим типам редакторов)
// пусть грид показывает свое стандартное меню (Добавить/Удалить поле и т.д.)
Result := inherited DoContextPopup(MousePos, Handled);
end;
```
### Нюансы использования
* **Вход в режим редактирования:** Чтобы меню "Вставить/Копировать" всплыло, ячейка должна быть в режиме редактирования. Пользователь должен сначала кликнуть левой кнопкой (или нажать `F2`/`Enter`), чтобы текстовый редактор активировался, и только затем нажимать правую кнопку мыши. Это стандартное поведение для ячеек `TStringGrid`.
* **Безопасность:** Патч не ломает логику для других типов полей (числовых, дат, списков). Для них `DoContextPopup` либо не вызовется (если клик уйдет в дочерний контрол), либо корректно сработает `inherited`, показав меню грида.
может это ускорит внесение исправлений.
- admin
- Разработчик
- Сообщения: 8036
- Зарегистрирован: 14 мар 2016, 11:32
- Откуда: Ленинградская
- Благодарил (а): 291 раз
- Поблагодарили: 1913 раз
Фильтр формы -разнобой в контекстном меню.
neznayka-na-lune писал(а):может это ускорит внесение исправлений.
Это вы напрасно.
Я уже исправил. Ждите обновление.
- admin
- Разработчик
- Сообщения: 8036
- Зарегистрирован: 14 мар 2016, 11:32
- Откуда: Ленинградская
- Благодарил (а): 291 раз
- Поблагодарили: 1913 раз
Фильтр формы -разнобой в контекстном меню.
admin писал(а):neznayka-na-lune писал(а):может это ускорит внесение исправлений.
Это вы напрасно.
Ну не совсем...
-
neznayka-na-lune
- Интересующийся
- Сообщения: 130
- Зарегистрирован: 22 дек 2025, 16:10
- Благодарил (а): 21 раз
- Поблагодарили: 17 раз
Фильтр формы -разнобой в контекстном меню.
admin писал(а):admin писал(а):neznayka-na-lune писал(а):может это ускорит внесение исправлений.
Это вы напрасно.
Ну не совсем...
С нетерпением ждем обновлений. Интригующе.