Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Программно Cut\Paste


Автор: Illusion Dolphin 6.6.2004, 11:15
Как в программе программно реализовать методы Cut\Paste в бефер обмена применимо к файлам (и пипкам, если есть различия)? Желательно также узнать, есть ли в буфере обмена данные этого типа (т.е. файлы)... В FAQ есть только копирование файлов.

Автор: Vex 6.6.2004, 14:47
Чтобы вырезать нужно скопировать исходный файл а потом его удалить.
А проверять буфер на наличие в нем файлов можешь так:

Код

procedure TForm1.FormActivate(Sender: TObject);
begin
CLB:=TClipBoard.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
bufer: array[0..60] of Char;
begin
for i:=1 to CLB.FormatCount-1 do begin
 GetclipboardFormatName(CLB.Formats[i], bufer, Pred(Sizeof(bufer)));
 if StrPas(bufer)='FileNameW' then showmessage("В буфере обмена уже есть файл");
end;
end;

Автор: Vex 6.6.2004, 15:47
Вставку можно сделать, посылая в нужное тебе окно сообщение о вставке:

Код
procedure TForm1.Paste1Click(Sender: TObject);
begin
 SendMessage (ActiveControl.Handle, WM_Paste, 0, 0);
end;

Автор: Illusion Dolphin 6.6.2004, 20:55
Vex, спасибо за пример работы с буфером обмена, но...
Проблема состоит в том, что необходимо сделать дву кнопки: Cut & Paste. Первая должна уметь "вырезать" фалы так, чтобы в проводнике можно было их вставить, а Paste - нужно определить, скопированы или вырезаны файлы в буфер (из того же проводника), а потом уже Copy (копировать) или Cut (копировать и удалять) их "в программу". Как это сделать?

Автор: Vex 6.6.2004, 22:01
Цитата
Vex, спасибо за пример работы с буфером обмена, но...
Проблема состоит в том, что необходимо сделать дву кнопки: Cut & Paste. Первая должна уметь "вырезать" фалы так, чтобы в проводнике можно было их вставить


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

Цитата
а Paste - нужно определить, скопированы или вырезаны файлы в буфер (из того же проводника), а потом уже Copy (копировать) или Cut (копировать и удалять) их "в программу". Как это сделать?


Как ты можешь из буфера вырезать или копировать данные в программу, ты можешь только туда вставить? Или я чего-то не понял.


Автор: Illusion Dolphin 6.6.2004, 22:54
Цитата
Или я чего-то не понял.

Объясняю:
Я открываю окно проводника, выделяю файл и нажимаю ВЫРЕЗАТЬ. Потом преспокойно закрываю его, и открываю другое окно, где нажимаю ВСТАВИТЬ. После этого файл скопируется в другое место и удалиться в исходном, т.е. второе окно будет знать, что файл именно вырезали, а не скопировали, т.к. в последнем случае он не будет удалён в начальном месте. Отсюда следует, что кроме того, что файл находится в буфере обмена, там содержится также информация системного характера (скопирован или вырезан).
Цитата
Если файл в буфере,то почему ты его не можешь вставить в проводнике?

А как проводник узнает, что я данные именно вырезал, а не скопировал (как, например, в faq есть функция КОПИРОВАНИЯ файлов в буфер обмена)?
Цитата
Как ты можешь из буфера вырезать или копировать данные в программу, ты можешь только туда вставить? Или я чего-то не понял.

Мне нужно определить: в проводнике пользователь нажал "скопировать" или "вырезать" чтобы знать, что делать с файлом.

Автор: Vex 6.6.2004, 23:11
Цитата
т.е. второе окно будет знать, что файл именно вырезали, а не скопировали


Хм... не знаю, думаю второму окну все равно вырезан файл или скопирован...


Добавлено @ 23:15
Вот из MSDN:
Цитата

Clipboard Commands

Cut: Places a copy of the current selection on the clipboard and deletes the selection from the document. The previous content of the clipboard is destroyed.

Copy: Places a copy of the current selection on the clipboard. The document remains unchanged. The previous content of the clipboard is destroyed.

Paste: Replaces the current selection with the content of the clipboard. The content of the clipboard is not changed.


Думаю в ClipBoarde храниться только сам объект и идентификатор формата, ИМХО.

Автор: youri 7.6.2004, 02:23
Цитата
procedure TForm1.FormActivate(Sender: TObject);
begin
CLB:=TClipBoard.Create;
end;

Я тут нашел в help'е такую штуку:
Цитата
Do not instantiate separate TClipboard objects by calling the constructor. Instead, use the global instance of TClipboard that is returned by calling the Clipboard function. Using this global instance safeguards against accidentally deleting the clipboard, while allowing the application to share a single instance of TClipboard for all use of the Clipboard. Before calling the Clipboard method, be sure that the uses clause includes Clipbrd.

правда не совсем понял, почему нельзя создавать собственный объект TClipBoard, может подскажете?

Автор: Illusion Dolphin 7.6.2004, 08:42
1)
Цитата
Хм... не знаю, думаю второму окну все равно вырезан файл или скопирован...

Открой одно окно проводника и "вырежи" вайл, потом закрой его и вставь... В исходном место его не будет. Если проделать то же самое, но в исходном месте его скопировать, но он просто скопируется.
2)
Цитата
Cut: Places a copy of the current selection on the clipboard and deletes the selection from the document.

А что понимать в данном слечае под документом? Жёсткий диск? Я сомневаюсь, что если я вырежу на диске С: фильм в 700 мегов, то он сразу же удалится с диска и поместится в буфер :/... Эта цитата применима к тексовым (и ещё многим другим) форматам, а к файлам вроде не то...
3)
Цитата
Думаю в ClipBoarde храниться только сам объект и идентификатор формата, ИМХО.

А как это сочетается с первым пунктом?

Автор: Vex 7.6.2004, 09:06
Цитата
Открой одно окно проводника и "вырежи" вайл, потом закрой его и вставь... В исходном место его не будет. Если проделать то же самое, но в исходном месте его скопировать, но он просто скопируется.


Я точно не знаю, но ИМХО когда мы вырезаем файл он копируется и удаляется.
я на 70% процентов уверен, что при вырезании происходит следующее:
1. Копировать файл в буфер обмена
2. Удалить файл
Какие мог доказательства я привел, но точно не знаю.

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

У тебя есть Clipboard Viewer?

Автор: Vex 7.6.2004, 09:18
Вывод: скопирован был файл или вырезан ИМХО невозможно, не считая всяких хитростей, если ты знаешь откуда был этот файл вырезан/скопирован, то можешь просканить каталог, если есть такой файл, значит скопирован, если нет вырезан.

Автор: Girder 7.6.2004, 11:30
Буфер обмена содержит только полный путь к файлам(с именем файла).
Чтобы определить что с ними надо делать (копировать или вставлять) разберется сам Explorer.

Пример определения какие файлы или папки перемещаются(копируются).
Код

uses ... ShellAPI;

procedure TForm1.BBClick(Sender: TObject);
var Hand:THandle;
   Count:integer;
   pfname: array[0..1023] of char;
   Item:TListItem;
begin        
if IsClipboardFormatAvailable(CF_HDROP) then
 begin
  if OpenClipboard(Self.Handle)=false then exit;
  Hand:=GetClipboardData(CF_HDROP);
  if (Hand<>NULL) then
   begin
    CBDInfo.Clear;
    Count:=DragQueryFile(Hand,$FFFFFFFF,nil,0);
    if Count>0 then
     repeat
      dec(Count);
      DragQueryFile(Hand,Count,pfname,1024);
      Item:=CBDInfo.Items.Add();
      Item.Caption:=string(pfname);
     until (Count=0);
   end;
  CloseClipboard();
 end;
end;


См. также:
http://www.delphimaster.ru/articles/dragndrop/
http://www.delphivsvb.by.ru/delphisol/desapprazr.html
http://www.vcl.ru/html/win31/mdi/ch2.htm

Удачи.

Автор: Illusion Dolphin 7.6.2004, 13:58
Vex:
Цитата
Я точно не знаю, но ИМХО когда мы вырезаем файл он копируется и удаляется.

А)
1) Создай файл 1.txt в любой директории.
2) открой его блокнотом и напиши там "Это только тест!"
3) Закрой его
4) Нажми правой кнопкой мыши и выбери "Вырезать" (файл удалён???)
5) Файл остался на месте, хотя стал "полупрозрачным".
6) Для проверки существования файла открываем его тем же блокнотом.
7) ФАЙЛ ПОСЛЕ ВЫРЕЗКИ СУЩЕСТВУЕТ!
Б)
1) Возьми файл существенным размером размером (фильм в 700 мегов).
2) Засекаешь время по часам
3) Попробуй "вырежь" его.
4) Засекаешь разность ввремени между текущим временем и операцией 2.
5) Думаем, как файл в 700 мегобайс прочитался за такое короткое время, да ещё и скопировался в оперативную память (пусть даже с свопом)
Вывод: Вырезать файл - это не УДАЛИТЬ ЕГО с помещением копии в буфере обмена.

Girder
Цитата
Чтобы определить что с ними надо делать (копировать или вставлять) разберется сам Explorer.

8) Explorer-то разберётся, а как быть мне? Мне нужно определить, что сделано с данными и потом уже (пусть даже с помощью эксплорера и интерфейсов как-то его скопировать\переместить\вставить. И ещё нужно сделать так, чтобы Explorer разобрался в том, что я хочу сделать с файлом: его скопировать или вырезать, чтобы ПОТОМ (см, что я написал Vex'у) над ними совершить нужное действие.

Пример кода - то же самое: файлы-то есть, но что с ними делать??? Как мне их туда ИЛИ СКОПИРОВАТЬ ИЛИ ВЫРЕЗАТЬ?

Автор: Vex 7.6.2004, 14:11
Цитата

1) Создай файл 1.txt в любой директории.
2) открой его блокнотом и напиши там "Это только тест!"
3) Закрой его

OK

Цитата

4) Нажми правой кнопкой мыши и выбери "Вырезать" (файл удалён???)

нет adv/225.gif
в буфер обмена поместился путь к файлу и где-то в недрах эксплорера переменная удаления стала TRUE и когда мы вставляем файл, то эксплорер копирует этот файл а затем удаляет.

Цитата

5) Файл остался на месте, хотя стал "полупрозрачным".
6) Для проверки существования файла открываем его тем же блокнотом.
7) ФАЙЛ ПОСЛЕ ВЫРЕЗКИ СУЩЕСТВУЕТ!

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


Добавлено @ 14:15
Illusion Dolphin, может более детально опиши свою задачу, попробуем как-то эту фигню с буфером.

З.Ы. Если бы достать какой-то исчерпывающий мануал о работе и структуре буфера обмена, то все бы вопросы решились.

Автор: Illusion Dolphin 7.6.2004, 14:41
Цитата
и где-то в недрах эксплорера переменная удаления стала TRUE

Гы smile.gif))). Гениально, шэф (с). Мне-то туда и нужно, т.е. где те недры, куда мне запихнуть эту TRUE (и откуда доставать)?
На счёт З.Ы. полностью согласен, но я нигде не могу найти его... Уже всё перерыл и ноль...

Автор: Vex 7.6.2004, 15:17
Illusion Dolphin, слухай, Girder же привел пример какие папки перемещаются/копируються, так попробуй их открыть, если файла нет, то он вырезан. smile.gif


Цитата
На счёт З.Ы. полностью согласен, но я нигде не могу найти его... Уже всё перерыл и ноль...

аналогично sad.gif

Автор: Girder 7.6.2004, 15:46
По моему здесь все доходчиво описанно:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_programming/transferring/clipboard.asp

Но можно и схитрить (хитрость номер 1):

Код
procedure TForm1.Button2Click(Sender: TObject);
var Hand:THandle;
   Count:integer;
   pfname: array[0..1023] of char;
   Item:TListItem;
   CD:Cardinal;
   s:string;
begin
CBDInfo.Clear;
if IsClipboardFormatAvailable(CF_HDROP) then
 begin
  if OpenClipboard(Self.Handle)=false then exit;
  CD:=0;
  repeat
   CD:=EnumClipboardFormats(CD);
   if (CD<>0)and(GetClipboardFormatName(CD,pfname,1024)<>0) then
    begin
     s:=UpperCase(string(pfname));
     if Pos('DROPEFFECT',s)<>0 then
      begin
       Hand:=GetClipboardData(CD);
       if (Hand<>NULL) then
        begin
         Count:=DragQueryFile(Hand,$FFFFFFFF,nil,0);
         if Count=1 then
          begin
           Item:=CBDInfo.Items.Add();
           Item.Caption:='Copy';
          end else
          begin
           Item:=CBDInfo.Items.Add();
           Item.Caption:='Move';
          end;
        end;
       CD:=0;
      end;
    end;
  until (CD=0);
  Hand:=GetClipboardData(CF_HDROP);
  if (Hand<>NULL) then
   begin
    Count:=DragQueryFile(Hand,$FFFFFFFF,nil,0);
    if Count>0 then
     repeat
      dec(Count);
      DragQueryFile(Hand,Count,pfname,1024);
      Item:=CBDInfo.Items.Add();
      Item.Caption:=string(pfname);
     until (Count=0);
   end;
  CloseClipboard();
 end;
end;


Еще раз повторяю: "В ClipBoard-е файлы не хранятся"

Удачи.

Автор: Illusion Dolphin 7.6.2004, 18:30
Girder: Огромное тебе СПАСИБО!!! 8) Это как раз то, что надо!
Только можешь подсказать, как из программы вырезать файл?
У меня есть функция для копирования файлов, но я никак не могу её перевести для вырезки 8(... Из msdn я не понял толком, как это сделать sad.gif. Помоги, а???

Фот функция для копирования:

procedure CopyFilesToClipboard(FileList: string);
var
DropFiles: PDropFiles;
hGlobal: THandle;
iLen: Integer;
begin
iLen := Length(FileList) + 2;
FileList := FileList + #0#0;
hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,
SizeOf(TDropFiles) + iLen);
if (hGlobal = 0) then raise Exception.Create('Could not allocate memory.');
begin
DropFiles := GlobalLock(hGlobal);
DropFiles^.pFiles := SizeOf(TDropFiles);
Move(FileList[1], (PChar(DropFiles) + SizeOf(TDropFiles))^, iLen);
GlobalUnlock(hGlobal);
Clipboard.SetAsHandle(CF_HDROP, hGlobal);
end;
end;

Автор: Girder 8.6.2004, 10:43
А ты что с COM не работал? baaa.gif

Хитрость номер 2(Explorer поймет, а вот хитрость номер 1 не много надо изменить):
Код

uses ... ShlObj;

//FCM=true - копирование
//FCM=false - перемещение
procedure TForm1.Copy_Move(FCM:Boolean;File_List:TStrings);
{type
PDROPFILES = ^TDROPFILES;
TDROPFILES = record
 pFiles:DWORD;
 pt:TPOINT;
 fNC:BOOL;
 fWide:BOOL;
end;}
var hGlobal,shGlobal:THandle;
   DropFiles:PDropFiles;
   REff:Cardinal;
   dwEffect:^Word;
   rSize,i:Integer;
   c:PChar;
begin
i:=File_List.Count;
if (i=0)or(OpenClipboard(Self.Handle)=false) then exit;
try
 EmptyClipboard();
 rSize:=sizeof(TDropFiles);
 repeat
  dec(i);
  rSize:=rSize+Length(trim(File_List.Strings[i]))+1;
 until (i=0);
 inc(rSize);
 hGlobal:=GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,rSize);
 if hGlobal<>0 then
  begin
   DropFiles:=GlobalLock(hGlobal);
   DropFiles.pFiles:=sizeof(TDropFiles);
//    DropFiles.pt:=;
   DropFiles.fNC:=false;
   DropFiles.fWide:=False;
   i:=File_List.Count;
   c:=PChar(DropFiles);
   c:=c+DropFiles.pFiles;
   repeat
    dec(i);
    StrCopy(c,PChar(trim(File_List.Strings[i])));
    c:=c+Length(trim(File_List.Strings[i]))+1;
   until (i=0);
   GlobalUnlock(hGlobal);
   shGlobal:=SetClipboardData(CF_HDROP,hGlobal);
   if (shGlobal<>0)and(FCM=false) then
    begin
     hGlobal:=GlobalAlloc(GMEM_MOVEABLE,sizeof(dwEffect));
     if hGlobal<>0 then
      begin
       dwEffect:=GlobalLock(hGlobal);
       dwEffect^:=2;//DROPEFFECT_MOVE;
       GlobalUnlock(hGlobal);
       REff:=RegisterClipboardFormat(PChar('Preferred DropEffect'));//'CFSTR_PREFERREDDROPEFFECT'));
       SetClipboardData(REff,hGlobal)
      end;
    end;
  end;
finally
 CloseClipboard();
end;
end;


А по хорошему надо юзать COM. Вот тебе некоторые ссылки(там есть готовый компоненты):
http://www.unitoops.com/uoole/examples/index.htm#Delphi
http://www.unitoops.com/default.htm
http://podgoretsky.com/ftp/Docs/Delphi/D3/D3ProgLib/ch_04.htm
http://www.undu.com/Articles/990317b.html
http://www.undu.com/Articles/990901g.html

Удачи.

Автор: Girder 8.6.2004, 11:20
Ладно, не буду мучать тебя, вот что надо изменить в хитрости номер 1:

Было:
Код

begin
...
    if Pos('DROPEFFECT',s)<>0 then
     begin
      Hand:=GetClipboardData(CD);
      if (Hand<>NULL) then
       begin
        Count:=DragQueryFile(Hand,$FFFFFFFF,nil,0);
        if Count=1 then
         begin
          Item:=CBDInfo.Items.Add();
          Item.Caption:='Copy';
         end else
         begin
          Item:=CBDInfo.Items.Add();
          Item.Caption:='Move';
         end;
       end;
      CD:=0;
     end;
...
end;


заменить на:
Код

...
var ...
     dwEffect:^Word;
begin
...
     if Pos('DROPEFFECT',s)<>0 then
      begin
       Hand:=GetClipboardData(CD);
       if (Hand<>NULL) then
        begin
         dwEffect:=GlobalLock(Hand);
         if dwEffect^=2 then
          begin
           Item:=CBDInfo.Items.Add();
           Item.Caption:='Move';
          end else
          begin
           Item:=CBDInfo.Items.Add();
           Item.Caption:='Copy';
          end;
         GlobalUnlock(Hand);
        end;
       CD:=0;
      end;
...
end;


Удачи.

Автор: Illusion Dolphin 8.6.2004, 14:38
Girder: СПАСИБО-СПАСИБО!!!! smile.gif smile.gif smile.gif
Да, я не работал ещё толком с этой технологией, я только вот пытаюсь кое-что освоить... Очень благодарен!!!!!!

Автор: Mephisto 7.6.2007, 10:25
Доброго фсем дня...
Хочу подключить свою трубу под линузом (Mandriva 2006). Труба Nokia 2610, кабель CA-45. Из-под винды асилил только подключится при помощи MobiMB v3.4, ничего более не кушало ее. USB кабло определяется как Prolific USB-to-Serial Comm Port. Теперь собсна вопросец... Как ентот мегадевайс подключить под линузом? GPlus ниасилил трубу ни под линузом, ни под виндами... :/

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)