Показать сообщение отдельно
  #7  
Старый 20.07.2007, 12:19
Аватар для 4kusNick
4kusNick 4kusNick вне форума
Местный
 
Регистрация: 06.09.2006
Адрес: Россия, Санкт-Петербург
Сообщения: 444
Репутация: 550
По умолчанию

Рассмотрим теперь перенос ячеек в StringGrid1. Поскольку, как и в случае с Memo, простое нажатие левой кнопки занято под другие действия, установим DragMode = dmManual и будем запускать Drag при нажатии левой кнопки, удерживая клавиши Alt или Ctrl. Запишем в OnMouseDown:
Код:
var
col, ARow: Integer;
begin
with StringGrid1 do
   if (ssAlt in Shift) or (ssCtrl in Shift) then
   begin
     MouseToCell(X, Y, Acol, Arow);
     if (Acol >= FixedCols) and (Arow >= FixedRows) then
// не будем перетаскивать из фиксированных ячеек
     begin
       if ssAlt in Shift then
         Tag := 1
       else
         if ssCtrl in Shift then
           Tag := 2;
// запомним что нажато - Alt или Ctrl -  в Tag StringGrid1
       BeginDrag(True)
     end
     else
       Tag := 0;
   end;
end;
Код OnDragOver учитывает также возможность перетаскивания из StringGrid2 (описание ниже)
Код:
var
Acol, ARow: Integer;
begin
with StringGrid1 do
begin
   MouseToCell(X, Y, Acol, Arow);
   Accept := (Acol >= FixedCols) and (Arow >= FixedRows)
     and (((Source = StringGrid1) and (Tag > 0))
     or (Source = StringGrid2));
end;
Часть OnDragDrop, относящаяся к внутреннему переносу:
Код:
var
ACol, ARow, c, r: Integer;
GR: TGridRect;
begin
StringGrid1.MouseToCell(X, Y, ACol, ARow);
if Source = StringGrid1 then
   with StringGrid1 do
   begin
     Cells[Acol, Arow] := Cells[Col,Row];
//копируем ячейку-источник в приемник
     if Tag = 1 then
       Cells[Col,Row] := '';
// очищаем источник, если было нажато Alt
     Tag := 0;
   end;
А вот из StringGrid2 сделаем перенос выбранного диапазона ячеек с помощью правой кнопки, для этого в OnMouseDown
Код:
if Button = mbRight then StringGrid2.BeginDrag(True);
И теперь часть StringGrid1DragDrop, относящаяся к переносу из StringGrid2:
Код:
if Source = StringGrid2 then
begin
   GR := StringGrid2.Selection;
// Selection - выделенные в StringGrid2 ячейки
   for r := 0 to GR.Bottom - GR.Top do
     for c := 0 to GR.Right - GR.Left do
       if (ACol + c < StringGrid1.ColCount) and
         (ARow + r < StringGrid1.RowCount) then
// застрахуемся от записи вне StringGrid1
         StringGrid1.Cells[ACol + c, ARow + r] :=
           StringGrid2.Cells[c + GR.Left, r + GR.Top];
end;

Теперь покажем, как этот диапазон ячеек из StringGrid2 перенести в Memo2. Для этого в OnDragOver Memo2 пишем:
Код:
Accept := (Source = StringGrid2) or (Source = DBGrid1);
и в OnDragDrop Memo2:
Код:
var
c, r: integer;
s: string;
begin
Memo2.Clear;
if Source = StringGrid2 then
   with StringGrid2 do
     for r := Selection.Top to Selection.Bottom do
     begin
       s := '';
       for c := Selection.Left to Selection.Right do
         s := s + Cells[c, r] + #9;
// разделим ячейки табуляцией
       memo2.lines.add(s);
     end
Кроме того, в Memo2 можно переносить выбранную запись из DBGrid1, у которого установлено в Options dgRowSelect = True. В сетке отображается таблица из стандартной поставки Delphi DBDEMOS - Animals.dbf. Перетаскивание осуществляется аналогично StringGrid2, правой кнопкой мыши, только по событию OnMouseMove

Код:
if ssRight in Shift then
   DBGrid1.BeginDrag(true);

Код в Memo2DragDrop, относящийся к переносу из DBGrid1:
Код:
else
   with DBGrid1.DataSource.DataSet do
   begin
     s := '';
     for c := 0 to FieldCount - 1 do
       s := s + Fields[c].AsString + ' | ';
     memo2.lines.add(s);
   end;
// в случае dgRowSelect = False для переноса одного поля достаточно сделать
// memo2.lines.add(DbGrid1.SelectedField.AsString);

Drag из DBGrid1 принимается также на Panel3, условие приема очевидно, а OnDragDrop выглядит так:
Код:
Panel3.Height := 300;  // раскрываем панель
Image1.visible := True;
OleContainer1.Visible := false;
Image1.Picture.Assign(DBGrid1.DataSource.DataSet.FieldByName('BMP'));
// показываем графическое поле текущей записи таблицы
Теперь покажу, как можно передвигать мышью визуальные компоненты в Run-Time. Для Panel1 установим DragMode = dmAutomatic, в OnDragOver формы пишем:
Код:
var
Ct: TControl;
begin
Ct := ControlAtPos(Point(X + Panel1.Width, Y + Panel1.Height), True, True);
// для упрощения проверяем перекрытие с другими контролами только правого нижнего угла
Accept := (Source = Panel1) and ((Ct = nil) or (Ct = Panel1));
и в OnDragDrop формы очень просто
Код:
Panel1.Left := X;
Panel1.Top := Y;
Другой метод перетаскивания можно встретить в каждом FAQ по Delphi:
Код:
procedure TForm1.Panel2MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
const
SC_DragMove = $F012;
begin
ReleaseCapture;
Panel2.Perform(WM_SysCommand, SC_DragMove, 0);
end;
И в завершение реализация популярной задачи перетаскивания значков файлов на форму из Проводника. Для этого следует описать обработчик сообщения WM_DROPFILES
Код:
private
procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES;
В OnCreate формы разрешить прием файлов
Код:
DragAcceptFiles(Handle, true);
и в OnDestroy отключить его
Код:
DragAcceptFiles(Handle, False);
Процедура обработки приема файлов может выглядеть так:
Код:
procedure TForm1.WMDropFiles(var Msg: TWMDropFiles);
const
maxlen = 254;
var
h: THandle;
//i,num:integer;
pchr: array[0..maxlen] of char;
fname: string;
begin
h := Msg.Drop;

// дана реализация для одного файла, а 
//если предполагается принимать группу файлов, то можно добавить:
//num:=DragQueryFile(h,Dword(-1),nil,0);
//for i:=0 to num-1 do begin
//  DragQueryFile(h,i,pchr,maxlen);
//...обработка каждого
//end;

DragQueryFile(h, 0, pchr, maxlen);
fname := string(pchr);
if lowercase(extractfileext(fname)) = '.bmp' then
begin
   Image1.visible := True;
   OleContainer1.Visible := false;
   image1.Picture.LoadFromFile(fname);
   Panel3.Height := 300;
end
else if lowercase(extractfileext(fname)) = '.doc' then
begin
   Image1.visible := False;
   OleContainer1.Visible := True;
   OleContainer1.CreateObjectFromFile(fname, false);
   Panel3.Height := 300;
end
else if lowercase(extractfileext(fname)) = '.htm' then
   ShellExecute(0, nil, pchr, nil, nil, 0)
else if lowercase(extractfileext(fname)) = '.txt' then
   Memo2.Lines.LoadFromFile(fname)
else
   Memo2.Lines.Add(fname);
DragFinish(h);
end;
При перетаскивании на форму файла с расширением Bmp он отображается в Image1, находящемся на Panel3, Doc загружается в OleContainer, для Htm запускается Internet Explorer или другой браузер по умолчанию, Txt отображается в Memo2, а для остальных файлов в Memo2 будет просто показано имя.

Полагаю, на основе содержащихся в статье приемов будет нетрудно организовать перетаскивание и для других, не описанных здесь, визуальных компонентов.

В заключение хочу выразить благодарность Игорю Шевченко и Максиму Власову за ценные советы при подготовке примеров... Автор статьи: Борис Новгородов, Новосибирск, 2002
Взято с сайта www.emanual.ru
__________________
THE CRACKER IS OUT THERE
Ответить с цитированием