Но, я всегда говорил и говорю теперь, что одну и ту же задачу можно решить множеством разных способов.
Вот в подтверждение своих слов я и хочу еще раз остановиться на том же интерфейсе, но модернизировать его под использование технологии перетаскивания (Drag & Drop).
Для начала нужно удалить некоторые элементы управления:
- DBGridEh3 и пару кнопок со стрелками. Компонент TDataSource по имени DataSourceAcc тоже не понадобится.
Соответственно, удалить и процедуры обработки (я воспользовался символами комментариев, поскольку, это не тот случай, когда "ломать - не строить: душа не болит"):
// procedure DBGridEh3DblClick(Sender: TObject);
// procedure Button2Click(Sender: TObject);
// procedure Button1Click(Sender: TObject);
и
{
procedure TGroupsFrm.Button1Click(Sender: TObject);
begin
MyAdd();
end;
procedure TGroupsFrm.DBGridEh3DblClick(Sender: TObject);
begin
MyAdd();
end;
procedure TGroupsFrm.Button2Click(Sender: TObject);
begin
MyDelete;
end;
}
На место удаленной сетки добавьте компонент TListBox, выровняв его как и прежде по правому краю:
(как в конструктор в детстве играю, ей Богу :-) )
Напишите новую процедуру, которая наполнит ListBox значениями:
Procedure TGroupsFrm.ListBoxRefresh();
Var
i: Integer;
begin
// Очистка списка
For i:=0 to ListBox1.Items.Count-1 do
ListBox1.Items.Delete(0); // Это важно - удалять всегда только 0-ой элемент
// Наполнение ListBox
With MainFrm.ADOTableAcc do
begin
// В источнике произведены изменения (присвоено новое значение
// признаку Groups, по которому настроен фильтр,
// поэтому необходимо вновь запросить данные из источника
Requery();
First;
While not eof do
begin
ListBox1.Items.Add(FieldByName('Name').AsString);
next;
end;
end;
end;
Обратите внимание, что
1. Подсчет элементов списка ведется от нуля до количества элементов списка минус единица. Например, если в списке 3 элемента, то их порядковые номера будут 0, 1, 2 (а не 1,2,3).
2. Из ListBox1 удаляется в цикле только 0-ой элемент, поскольку после удаления очередного элемента список перестраивается. В нулевой позиции всегда располагается некий Item вплоть до последнего.
В написанную ранее процедуру, обрабатывающую событие создания формы, необходимо добавить ListBoxRefresh, чтобы после появления формы на мониторе, список был наполнен значениями:
procedure TGroupsFrm.FormCreate(Sender: TObject);
Var MyStr: String;
begin
...
MainFrm.ADOTableAcc.Filtered:=True;
ListBoxRefresh(); // Урок 44
end;
В инспекторе объектов установите свойства DragMode для DbGridEh2 и ListBox1 в dmAutomatic.
Чтобы описываемый механизм Drag & Drop заработал, нужно написать обработчики двух событий для получателя, т.е. для .DBGridEh2 - сетки, отображающей участников группы:
1. onDragOver,
2. onDragDrop
С первым все довольно просто:
procedure TGroupsFrm.DBGridEh2DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept := Source = ListBox1;
end;
- иными словами - назначается источник данных ListBox1 для сетки DBGridEh2, когда курсор будет находиться над последней.
Для второго события давайте ограничимся пока только сообщением:
procedure TGroupsFrm.DBGridEh2DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
Showmessage('Обработать перетаскивание');
end;
И посмотрим, как это все работает.
Если прижать мышкой один из пунктов в списке и потащить его на сетку (2), то курсор над сеткой изменится. Рядом с ним появится прямоугольник, что и будет означать, что получатель готов принять данные из источника в результате Drag & Drop. Отпустив кнопку мышки, получим сообщение на экран:
как результат обработки события DragDrop.
Значит, именно в обработчик этого события и нужно встроить механизм добавления нового участника группы.
Если Вы помните, то процедура добавления называется MyAdd. Может быть, вписать ее в обработчик, и - дело с концом? Не получится. Дело в том, что пока у нас была сетка на месте списка, мы были уверены в том, какой ID у выбранного в ней счета. В списке же присутствуют лишь названия счетов. Беда...
Как и всегда, для решения задачи есть несколько способов. Можно создать массив и наполнять его ID тех счетов, что ложатся в ListBox, "отгадывая" на обратном пути по позиции в списке ID счета в массиве.
Но я добавлю на форму компонент TADOQuery, назвав его TempQuery. И перепишу процедуру MyAdd:
procedure TGroupsFrm.MyAdd();
Var
MyStr: String;
begin
// Найти счет по его названию // Урок 44
TempQuery.active:=False;
TempQuery.SQL.Clear;
TempQuery.Parameters.Clear;
MyStr:='SELECT Accounts.ID, Accounts.Groups ';
MyStr:=MyStr + 'FROM Accounts ';
MyStr:=MyStr + 'WHERE (((Accounts.Name)='''+ListBox1.Items[ListBox1.ItemIndex]+'''))';
TempQuery.SQL.Add(MyStr);
TempQuery.Active:=True;
If TempQuery.RecordCount>0
then
begin
// Добавление счета в группу
With ADOQueryMembers Do // Работаем с запросом
Begin
Insert; // Добавление новой записи
Try
// Присвоение значений полям
FieldByName('IDGroup').Value:=ADOTableGroups.FieldByName('ID').Value;
FieldByName('IDAcc').Value:=TempQuery.FieldByName('ID').Value;
// Запись в таблицу-источник
Post;
// Фиксирование признака в кодификаторе счетов (через временный запрос!)
TempQuery.Edit;
TempQuery.FieldByName('Groups').Value:=True;
TempQuery.Post;
// Обновление данных
Requery();
finally
ListBoxRefresh; // Ранее здесь располагался оператор, обновляющий таблицу счетов
end;
end;
end;
Как говорится: "Найдите 10 отличий" :-)
Осталась самая малость: при исключении счета из группы - обновить список (справа), для чего достаточно в процедуру MyDelete вписать одну строку:
finally
ADOQueryMembers.Requery();
ListBoxRefresh();
end;
Ну, а тем, кому не нравится таскать элементы списка, не полюбился им интерфейс на основе технологии Drag & Drop, мы обязаны (ВСЕГДА ПОМНИ О ПОЛЬЗОВАТЕЛЕ!) дать возможность добавлять счета в группу по двойному щелчку на элементе списка:
procedure TGroupsFrm.ListBox1DblClick(Sender: TObject);
begin
MyAdd;
end;
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.