Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.08.22;
Скачать: CL | DM;

Вниз

Копирование данных через буфер из Excel в DBGrid...   Найти похожие ветки 

 
BoxTer   (2004-08-03 13:41) [0]

Вот возникла интересная ситуевина - требуется выполнить сабж: есть в экселе табличка, например - 3 столбца, 5 строчек. Скопировав ее Ctrl+C в буфер необходимо вставить эти данные в приложении в сетку DBGrid1 с таким же количеством строк и столбцов...

Заранее благодарен.


 
Sancho ©   (2004-08-03 13:50) [1]

Вообще ячейки (в буфере обмена) будут разделяться символом #9, а строки #13#10 (но это не точно т.к. копался я в этом давным-давно). Но это абсолютно не правильно, косяков не оберешься, то строчка выпадет, то ячейки объединятся особенно если ячеек много. Надо использовать OLE.


 
Digitman ©   (2004-08-03 13:53) [2]


> в сетку DBGrid1 с таким же количеством строк и столбцов


если DBGrid1 связан с НД, не допускающим редактирование данных/метаданных, то затея эта крива изначально


 
KSergey ©   (2004-08-03 14:08) [3]

> [2] Digitman ©   (03.08.04 13:53)

Я не пойму при чем тут все это говорить? В любом случае нет такой функциональности в стандартных компонентах. (или я ошибаюсь?)
Есть такая фигня. но это целая надстройка над DBGridEh.

Хотя сейчас глянул  наверное можно его отдельно выдрать при желании... Но жаба давит :)


 
KSergey ©   (2004-08-03 14:11) [4]

Все сделано как реакция на WM_PASTE грида. Откуда оно возьмется - решать вам. Или к другому месту это все прикрутить.

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

В один пост наверняка не влезет, разобью.

{******************************************************************************
* Вставка строк из клипборда
* Вставляет начиная с текущего столбца
* Вставляет при след. условиях:
*  -грид в режиме вставки
*  -GataSet и Grid допускают редактирование
******************************************************************************}

procedure TdoDBGrid.WMPaste(var Msg: TMessage);
var
 i: Integer;
 StrLst: TStringList;
 SavCursor: TCursor;

 // из модуля ClipView RXLib
 // использовалась для тестов
 function ClipboardFormatName(Format: Word): string;
 var
   Buffer: array[0..255] of Char;
 begin
   SetString(Result, Buffer, GetClipboardFormatName(Format, Buffer, 255));
   if Result = "" then
     case Format of
       CF_BITMAP: Result := "CF_BITMAP";
       CF_DIB: Result := "CF_DIB";
       CF_DIF: Result := "CF_DIF";
       CF_METAFILEPICT: Result := "CF_METAFILEPICT";
       CF_ENHMETAFILE: Result := "CF_ENHMETAFILE";
       CF_OEMTEXT: Result := "CF_OEMTEXT";
       CF_PALETTE: Result := "CF_PALETTE";
       CF_PENDATA: Result := "CF_PENDATA";
       CF_RIFF: Result := "CF_RIFF";
       CF_SYLK: Result := "CF_SYLK";
       CF_TEXT: Result := "CF_TEXT";
       CF_TIFF: Result := "CF_TIFF";
       CF_WAVE: Result := "CF_WAVE";
       CF_UNICODETEXT: Result := "CF_UNICODETEXT";
       CF_HDROP: Result := "CF_HDROP";
       CF_LOCALE: Result := "CF_LOCALE";
       CF_MAX: Result := "CF_MAX";
       CF_OWNERDISPLAY: Result := "CF_OWNERDISPLAY";
       CF_DSPTEXT: Result := "CF_OWNERDISPLAY";
       CF_DSPBITMAP: Result := "CF_OWNERDISPLAY";
       CF_DSPMETAFILEPICT: Result := "CF_OWNERDISPLAY";
       CF_DSPENHMETAFILE: Result := "CF_OWNERDISPLAY";
       CF_PRIVATEFIRST: Result := "CF_OWNERDISPLAY";
       CF_PRIVATELAST: Result := "CF_OWNERDISPLAY";
       CF_GDIOBJFIRST: Result := "CF_OWNERDISPLAY";
       CF_GDIOBJLAST: Result := "CF_OWNERDISPLAY";
     end;
 end;

 // просто список форматов данных в буфере обмена
 // использовалась для тестов
 function TextClipboardFornats: String;
 const
   YN: array [Boolean] of String = ("No", "Yes");
 var
   FormatNum, i: Integer;
 begin
   Result := "";
   for i := 0 to Clipboard.FormatCount-1 do
   begin
     FormatNum := Clipboard.Formats[i];
     Result := Result
       + IntToStr (FormatNum)
       + " (" + ClipboardFormatName(FormatNum) + ") - "
       + YN[Clipboard.HasFormat(FormatNum)] + {#13} " | ";
   end;
 end;


 
KSergey ©   (2004-08-03 14:12) [5]

 // проверка строки на пустоту
 function IsEmptyStr (const AStr: String): Boolean;
 begin
   Result := Length(AStr) < 1;
 end;

 // присваивает указанное значение полю указанного столбца
 // работа через строковые значения, т.к. из клипборда вынимается текстовая информация
 procedure PasteCol (const nCol: Integer; const AStr: String);
 begin
   if NOT IsEmptyStr(AStr) then
     Columns[nCol].Field.AsString := AStr;
 end;

 // собственно добавление строки в грид
 // AStr - строка для вставки, содержащая колонки, разделенные табуляцией
 procedure PasteRow (AStr: String);
 var
   nPT: Integer;  // позиция табуляции
   nCol: Integer; // колонка для вставки
   isAllow: Boolean;  // флажек для пользователя "разрешить вставку"
 begin
   if DataLink.DataSet.State <> dsInsert then  DataLink.DataSet.Append;  // для последующих строк за первой
   try
     // предоставить пользователю возможность прописать значения в какие-либо поля при вставке строки
     isAllow := TRUE;
     if Assigned(OnRowPaste) then  OnRowPaste(Self, isAllow);
     if isAllow then
     begin
       // теперь разбить на составляющие и вставить поколоночно
       nCol := Col;
       if dgIndicator in Options then  Dec(nCol);
       while NOT IsEmptyStr(AStr) do
       begin
         nPT := Pos (#9, AStr);
         if nPT < 1 then  nPT := Length(AStr)+1;
         PasteCol (nCol, Copy(AStr, 1, nPT-1));
         Inc(nCol);
         if nCol >= Columns.Count then  Break;  // в буфере обмена было больше полей, чем осталось в гриде от текущего столбца - выход
         AStr := Copy (AStr, nPT+1, Length(AStr)-nPT);  // выделить остаток строки
       end;
       DataLink.DataSet.Post;
     end
     else
       DataLink.DataSet.Cancel;  // пользователь не разрешил вставку
   except
     DataLink.DataSet.Cancel;  // при ошибках - обязательно отменить изменения
     raise;
   end;
 end;


 
GanibalLector ©   (2004-08-03 14:12) [6]

на realcoding.net поищи.Там такой вопрос подымался и весьма успешно разрешился!!!


 
KSergey ©   (2004-08-03 14:13) [7]

begin   // TdoDBGrid.WMPaste
{ TODO -cГрид: попробовать сделать так, чтобы при режиме "не редактирование" вставлялось значение текста из буфера в ячейку (с предварительным переводом в состояние редактирования); возможно, придется проверить формат данных, хотя, наверняка, если не вставка (т.е. не режим для вставки строк) - пихать все в текущую ячейку }
 if ReadOnly OR NOT Assigned(DataLink.DataSet) OR NOT DataLink.DataSet.Active OR NOT DataLink.DataSet.CanModify OR (DataLink.DataSet.State <> dsInsert) OR NOT (dgdAllowRowPaste in FOptionsDO) then
   Exit;  // если по каким-то условиям нельзя произвести вставку - немедленный выход
 // итак, DataSet есть, открыт и в режиме вставки (на новой строке), ставка в грид строк - разрешена
 StrLst := TStringList.Create;
 try
   StrLst.Text := Clipboard.AsText;
   if StrLst.Count > 0 then  // буфер не пуст
   begin
     SavCursor := Screen.Cursor;
     Screen.Cursor := crHourGlass;
     DataLink.DataSet.DisableControls;
     try
       for i := 0 to StrLst.Count-1 do
         if NOT IsEmptyStr(StrLst[i]) then  PasteRow (StrLst[i]);
     finally
       DataLink.DataSet.EnableControls;
       Screen.Cursor := SavCursor;
     end;
   end;
 finally
   StrLst.Free;
 end;
end;


 
KSergey ©   (2004-08-03 14:15) [8]

Работает код из [4][5][7] KSergey © так: надо перейти на новую строку в гриде (режим вставки), встать на столбец, начиная с которого будем вставлять - ну и вызвать эту ф-цию.
Возможно, условия для кого-то не приемлемы, ну подшаманить.


 
KSergey ©   (2004-08-03 14:17) [9]

Да, там еще обработчик сделан OnRowPaste
Ну это можно смело убрать.


 
BoxTer   (2004-08-04 07:45) [10]

2KSergey.
Бааальшое сенкс. Все заработало, придется маненько доделать для моей задачи - а так усе отлично!


 
KSergey ©   (2004-08-04 08:14) [11]

> GanibalLector ©   (03.08.04 14:12)
> на realcoding.net поищи.

Там поиска нет, или я не нашел?


 
Digitman ©   (2004-08-04 09:25) [12]


> KSergey ©   (03.08.04 14:08) [3]
> > [2] Digitman ©   (03.08.04 13:53)
>
> Я не пойму при чем тут все это говорить? В любом случае
> нет такой функциональности в стандартных компонентах. (или
> я ошибаюсь?)


я не о том, что функциональности такой нет, это само собой разумеется

я о том, что НД, отображаемый гридом, может иметь меньшее число полей, чем число копируемых полей

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


 
GanibalLector ©   (2004-08-04 09:37) [13]

2 KSergey
Ну дык в форуме...тема:Delphi


 
KSergey ©   (2004-08-04 10:13) [14]

> [12] Digitman ©   (04.08.04 09:25)
> что толку вставлять в грид что-то там, если вставляемые
> значения должны фактически быть зафиксированы в НД ? как
> фиксировать "лишние" вставляемые поля ? это вызывает много
> вопросов ...

Призаться, вижу 2 пути решения проблемы, без замудривания (речь идет о случае, когда каждая колонка грида соотв. полю DataSet, да еще и редактируемому; для простоты):

1.Послать пользователя "не совпадает вормат вставляемых и ..."
2.Что не уместилось - ну и фиг с ним. Пользователь сам должен понимать, что если некуда вставлять - то логично, что вставляться не будет; по-моему, это выглядит вполне естественно.

Впрочем, это уже все так, слова. Обсуджать тут нечего, надо смотреть на конкретную задачу.

Впрочем, ваше замечание натолкнуло меня на то, что есть в моем коде недоработка: если столбец не видим, то по идее в него и вставлять не надо, это нелогично для пользователя, он по идее ожидает вставку только в то, что видит... Доработать надо, однако.


 
KSergey ©   (2004-08-04 10:15) [15]

Да, вот еще кусочек, если интересно
Он у меня в другом месте оказался

 // проверка: содержится ли в буфере обмена формат, похожий на формат таблицы
 function TestClipBoardTable: Boolean;
 var
   s: String;
   nCF_XLTable: Integer;
   nPos, nLen: Integer;
 begin
   nCF_XLTable := RegisterClipboardFormat (PChar("XLTable"));
   Result := Clipboard.HasFormat(nCF_XLTable);  // если есть такой формат в буфере - там точно таблица
   if NOT Result AND Clipboard.HasFormat(CF_TEXT) then
   begin
     s := Clipboard.AsText;
     Result := Pos(#9, s) > 0;  // если присутствует табуляция - однозначно считаем, что в буфере - таблицы (табуляция - разделитель столбцов)
     if NOT Result then
     begin
       nPos := Pos(#13, s); // если присутствует #13
       Result := nPos > 0;  // и это не последний символ - подозрение на таблицу
       if Result then       // уточним:
       begin
         nLen := Length(s);
         if nPos = nLen-1 then       // если это предпоследний символ -
           Result := s[nLen] > " ";  // то следующий за ним должен быть буквой (а не #10, что вероятно)
       end;
     end;
   end
   else
     Result := FALSE;
 end;



Страницы: 1 вся ветка

Текущий архив: 2004.08.22;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.059 c
14-1091613462
zamkom
2004-08-04 13:57
2004.08.22
InstallShild


14-1091537366
}|{yk
2004-08-03 16:49
2004.08.22
По автоматизации Excel


3-1091037724
Wolfram
2004-07-28 22:02
2004.08.22
Ошибка конструкции JOIN


6-1087536809
leonidus
2004-06-18 09:33
2004.08.22
Щелчки в TWebBrowser`е


1-1091689868
tria
2004-08-05 11:11
2004.08.22
Как при закрытии приложения вызвать OnClose дочерних mdi-форм?