Текущий архив: 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.51 MB
Время: 0.029 c