1 / 1 / 0
Регистрация: 23.02.2014
Сообщений: 22
1

Работа с полями Variant

28.02.2015, 23:59. Показов 1943. Ответов 12
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Доброй ночи. Такой вопрос. Есть поле в Excel типа Variant, в нем находится изображение.
Как выгрузить из Excel данные я знаю. Как выгрузить картинку из поля книги Excel в делфи и куда его можно выгрузить? В OleContainer или Image. И как? Или можно через BitMap как-то сделать это(загрузить в BitMap и уже отсюда выгрузить в Image)?
0
28.02.2015, 23:59
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
28.02.2015, 23:59
Ответы с готовыми решениями:

Тип variant
Здравствуйте,уважаемые форумчане.У меня возник вопрос, как задать переменную у которой тип будет variant, вариантами значений которой будут...

Тип variant
подскажите пожалуйста сайт или книгу где можно очень подробно узнать о типе variant желательно с примерами и с пояснениями?

invalid variant operation
Компилятор выводит ошибку "invalid variant operation" и указывает на строку Word.Documents.Open(FileName:='D:\Новая папка...

12
 Аватар для Mawrat
13108 / 5889 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
01.03.2015, 00:40 2
Лучший ответ Сообщение было отмечено shulga как решение

Решение

Пример: Импорт изображения из *.xls в StringGrid
1
1 / 1 / 0
Регистрация: 23.02.2014
Сообщений: 22
03.03.2015, 10:25  [ТС] 3
Теперь другая проблема. Программа вставляет сначала одну картинку во все поля, затем следующую. В итоге последняя картинка из коллекции объектов во всех полях. Т.Е. идет прорисовка каждой картинки в соответствующей ячейке, а по факту одно изобр. во всех ячейках.
Прилагаю код
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
procedure TfmMain.N2Click(Sender: TObject);
const
  msoPicture = 13; //
  xlBitmap = 2; // Bitmap.
var
  j:integer;
  Cb : TClipboard;
  Bm : TBitmap;
  exSh, exShape, exShapes : OleVariant;
begin
    for j := 1 to exShapes.Count do
      begin
        exShape := exShapes.Item(j); 
        exShape.CopyPicture(Format:=xlBitmap); 
        if Cb.HasFormat(CF_BITMAP) then 
        begin
          Bm.Assign(Cb); 
          //Bm.LoadFromClipboardFormat(cf_BitMap,ClipBoard.GetAsHandle(cf_Bitmap),0);
          Image1.Picture.Bitmap:= Bm;
          StringGrid1.Objects[8,j]:=Image1.Picture.Bitmap;
           StringGrid1.ColWidths[8]:=Image1.Picture.Bitmap.Width;
            StringGrid1.RowHeights[j]:=Image1.Picture.Bitmap.Height;
        end
      end;
end;
 
procedure TfmMain.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
 fmMain.StringGrid1.Canvas.Draw(Rect.Left, Rect.Top, TBitmap(fmMain.StringGrid1.Objects[ACol, ARow]));
end;
Добавлено через 12 минут
Т.е. что получается, вышеуказанный код не прорисовывает картинку в StringGrid, а связывает её с источником, в данном случае с Буфером. И когда меняется содержимое буфера - меняется содержимое StringGrid. Так что ли? Получается мне необходимо все же сохранять изобр. В отдельные файлы и оттуда загружать их в стринггрид? Из буфера выгружать в StringGrid поочередно не выйдет?
0
 Аватар для Mawrat
13108 / 5889 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
03.03.2015, 15:55 4
Лучший ответ Сообщение было отмечено shulga как решение

Решение

Вот пример.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
uses
  ComObj, Clipbrd;
 
//Уничтожение прикреплённых объектов, очистка экземпляра TStringGrid.
procedure SgClear(aSg : TStringGrid);
var
  Row, Col : Integer;
begin
  for Col := 0 to aSg.ColCount - 1 do
  begin
    for Row := 0 to aSg.RowCount - 1 do
      aSg.Objects[Col, Row].Free;
    aSg.Cols[Col].Clear;
  end;
  aSg.RowCount := aSg.FixedRows + 1;
end;
 
//Очистка и подготовка таблицы.
procedure SgInit(aSg : TStringGrid);
var
  Row : Integer;
begin
  SgClear(aSg);
 
  aSg.Cells[0, 0] := 'Номер';
  aSg.Cells[1, 0] := 'Название';
  aSg.Cells[2, 0] := 'Изображение';
 
  aSg.ColWidths[0] := 50;
  aSg.ColWidths[1] := 120;
  aSg.ColWidths[2] := 100;
 
  for Row := 0 to aSg.RowCount - 1 do
    aSg.RowHeights[Row] := aSg.DefaultRowHeight;
end;
 
//Загрузка изображений с листа книги MS Excel в экземпляр TStringGrid.
procedure TForm1.Button1Click(Sender: TObject);
const
  //Константы MS Office/MS Excel.
  //msoPicture = 13; //Тип фигуры - изображение.
  xlBitmap = 2; //Тип изображения - Bitmap.
var
  exApp, exBook, exSh, exShape, exShapes : OleVariant;
  Od : TOpenDialog;
  Cb : TClipboard;
  Bm : TBitmap;
  Sg : TStringGrid;
  i, Row : Integer;
begin
  //Диалог выбора файла.
  Od := OpenDialog1; //OpenDialog1 уже должен быть на форме.
  if Od.InitialDir = '' then
    Od.InitialDir := ExtractFilePath(ParamStr(0)); //Путь к папке, в которой лежит исполняемый файл программы.
  if not Od.Execute then
    Exit;
  if not FileExists(Od.FileName) then
  begin
    MessageBox(Handle, 'Файл с заданным именем не найден! Действие отменено.',
      'Внимание!', MB_OK + MB_ICONWARNING + MB_APPLMODAL);
    Exit;
  end;
 
  //Запуск экземпляра Excel и получение ссылки на интерфейс корневого объекта (Excel.Application).
  exApp := CreateOleObject('Excel.Application');
  exApp.Visible := True; //Делаем видимым окно MS Excel.
  exBook := exApp.Workbooks.Open(FileName:=Od.FileName); //Открываем раб. книгу и получаем ссылку на её интерфейс.
  exSh := exBook.Worksheets[1]; //Ссылка на интерфейс первого рабочего листа в книге.
 
  Sg := StringGrid1;
  SgInit(Sg); //Очистка и подготовка StringGrid.
  Cb := Clipboard; //Объект, представляющий буфер обмена Windows.
  Row := Sg.FixedRows;
  exShapes := exSh.Shapes; //Ссылка на коллекцию фигур, связанных с листом.
  //Перебираем элементы коллекции фигур и обрабатываем их.
  for i := 1 to exShapes.Count do
  begin
    if Row = Sg.RowCount then //Если требуется, добавляем новую строку в StringGrid.
      Sg.RowCount := Sg.RowCount + 1;
    exShape := exShapes.Item(i); //Берём очередную фигуру из коллекции.
    Sg.Cells[0, Row] := IntToStr(i); //Номер изображения.
    Sg.Cells[1, Row] := exShape.Name; //Название изображения.
    exShape.CopyPicture(Format:=xlBitmap); //Копируем в буфер обмена изображение в формате Bitmap.
    if Cb.HasFormat(CF_BITMAP) then //Если буфер содержит данные в формате CF_BITMAP.
    begin
      Bm := TBitmap.Create; //Создаём экземпляр TBitmap.
      Bm.Assign(Cb); //Забираем изображение из буфера обмена.
      Sg.Objects[2, Row] := Bm; //Прикрепляем экземпляр TBitmap к ячейке.
    end
    else
      Sg.Cells[2, Row] := 'Формат <> CF_BITMAP';
    Inc(Row); //Индекс следующей строки.
  end;
end;
 
//Прорисовка ячеек.
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  Sg : TStringGrid;
  Bm : TBitmap;
begin
  Sg := Sender as TStringGrid;
  Bm := Sg.Objects[ACol, ARow] as TBitmap;
  if (Bm = nil) or (Bm.Height = 0) then
    Exit;
 
  if Bm.Height > 0 then
  begin
    //+4 = 2 + 2 - запас для полей.
    if Sg.RowHeights[ARow] < Bm.Height + 4 then
      Sg.RowHeights[ARow] := Bm.Height + 4;
    if Sg.ColWidths[ACol] < Bm.Width + 4 then
      Sg.ColWidths[ACol] := Bm.Width + 4;
    //+2 - задание величины полей.
    Sg.Canvas.Draw(Rect.Left + 2, Rect.Top + 2, Bm);
  end;
end;
 
//После создания формы.
procedure TForm1.FormCreate(Sender: TObject);
begin
  SgInit(StringGrid1);
end;
 
//Перед закрытием формы.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  try
    SgClear(StringGrid1);
  except
    on e : Exception do
      MessageBox(Handle, PChar('При закрытии формы произошли ошибки!'#13#10 + e.Message),
        'Внимание!', MB_OK + MB_ICONERROR + MB_APPLMODAL);
  end;
end;
Миниатюры
Работа с полями Variant  
Вложения
Тип файла: 7z ExcelShapesToStringGrid-01.7z (226.1 Кб, 4 просмотров)
1
1 / 1 / 0
Регистрация: 23.02.2014
Сообщений: 22
04.03.2015, 00:16  [ТС] 5
Еще раз спасибо большое! Надо было строку
Delphi
1
Bm := TBitmap.Create; //Создаём экземпляр TBitmap.
поместить в цикл, чего у меня не было сделано.

Добавлено через 1 час 56 минут
Снова возник вопрос. А как скопировать в буфер уже содержимое ячейки, содержащей рисунок?

Добавлено через 2 часа 21 минуту
Листинг целой программы не нужен. Только код копирования из ячейки StringGrid в буфер или в Bitmap. Не нашел через поиск.
0
 Аватар для Mawrat
13108 / 5889 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
04.03.2015, 12:19 6
Цитата Сообщение от shulga Посмотреть сообщение
Снова возник вопрос. А как скопировать в буфер уже содержимое ячейки, содержащей рисунок?
На листе Excel рисунок (объект Excel.Shape) привязывается к той ячейке, на которую накладывается его верхний левый угол. Поэтому, получив ссылку на интерфейс объекта Excel.Shape, надо по координатам его верхнего левого угла определить координаты ячейки:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Определение номера строки, на которой расположена верхняя грань объекта.
function GetRowNum(const aExSheet, aExObj : OleVariant) : Integer;
var
  Height, Y : Extended;
begin
  Result := 0; //Номер очередной строки на листе MS Excel.
  Height := 0; //Вертикальная координата нижней грани очередной строки на листе. Выражена в пунктах (Points).
  Y := aExObj.Top; //Вертикальная координата верхней грани объекта. Выражена в пунктах (Points).
  //Ищем первую строку на листе, у которой нижняя грань расположена ниже верхней грани объекта.
  repeat
    Result := Result + 1;
    Height := Height + aExSheet.Rows[Result].Height;
  until Height > Y;
end;
 
//Определение номера столбца, на котором расположена левая грань объекта.
function GetColNum(const aExSheet, aExObj : OleVariant) : Integer;
var
  Width, X : Extended;
begin
  Result := 0; //Номер очередного столбца на листе MS Excel.
  Width := 0; //Горизонтальная координата правой грани очередного столбца на листе. Выражена в пунктах (Points).
  X := aExObj.Left; //Горизонтальная координата левой грани объекта. Выражена в пунктах (Points).
  //Ищем первый столбец на листе, у которой правая грань расположена правее левой грани объекта.
  repeat
    Result := Result + 1;
    Width := Width + aExSheet.Columns[Result].Width;
  until Width > X;
end;
Пример использования:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
var
  exSheet, exCell : OleVariant;
  Row, Col : Integer;
  S : String;
...
begin
...
  //Координаты ячейки, на которой лежит верхний левый угол фигуры.
  Row := GetRowNum(exSheet, exShape);
  Col := GetColNum(exSheet, exShape);
  //Получаем текст ячейки.
  S := exSheet.Cells[Row, Col].Text;
0
1 / 1 / 0
Регистрация: 23.02.2014
Сообщений: 22
04.03.2015, 21:09  [ТС] 7
Цитата Сообщение от Mawrat Посмотреть сообщение
На листе Excel рисунок (объект Excel.Shape) привязывается к той ячейке, на которую накладывается его верхний левый угол. Поэтому, получив ссылку на интерфейс объекта Excel.Shape, надо по координатам его верхнего левого угла определить координаты ячейки:
Нее...может я не точно написал. Из ячейки StringGrida выгрузить в буфер. Не из Excel выгружать в буфер, а из StringGrid.Cell[i,j] в буфер.

Добавлено через 1 час 1 минуту
Выгрузить изображение из ячейки StringGrida в буфер.

Добавлено через 3 минуты
Пробовал вот так
Delphi
1
2
3
4
5
Bmp := TBitmap.Create; //Îáúåêò, ïðåäñòàâëÿþùèé èçîáðàæåíèå.
Bmp.Canvas.CopyRect(Canvas.ClipRect,StringGrid1.Canvas,StringGrid1.CellRect(j,i));
Cb.Assign(Bmp);
Excel.workbooks[1].worksheets[1].Cells[1,1].Select;
Excel.workbooks[1].worksheets[1].PastSpecial('CF_BITMAP');
Но ругается на PastSpecial: "exception class EOleError with message Methd 'PastSpecial'not supported by automation object"

Добавлено через 3 часа 13 минут
Даже так надо, выгрузить изображение из ячейки StringGrida в буфер и из буфера в Excel поместить

Добавлено через 23 минуты
Три дня уже вожусь с этой задачей... Подскажите хотя бы где почитать.

Добавлено через 12 минут
Вставку картинки в Excel сделал с помощью
Delphi
1
2
3
Clipboard.Assign(Bitmap);
Excel.workbooks[1].worksheets[1].Cells[i+2,2].Select;
Excel.workbooks[1].worksheets[1].Paste;
Но до сих пор остается вопрос как скопировать в BitMap картинку из StringGrid
0
 Аватар для Mawrat
13108 / 5889 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
04.03.2015, 21:48 8
Цитата Сообщение от shulga Посмотреть сообщение
Но до сих пор остается вопрос как скопировать в BitMap картинку из StringGrid
А там картинки (экземпляры TBitmap) прикреплены прямо к ячейкам - под видом объектов TStringGrid.Objects[Col, Row]. Вот эти объекты надо брать и в буфер обмена записывать.

Т. е., вот так. Например, пускай надо в буфер обмена скопировать картинку из первой нефиксированной строки:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uses
  Clipbrd;
 
procedure TForm1.Button2Click(Sender: TObject);
var
  Bm : TBitmap;
  Sg : TStringGrid;
begin
  Sg := StringGrid1;
  Bm := Sg.Objects[2, Sg.FixedRows] as TBitmap;
  if Assigned(Bm) then
  begin
    Clipboard.Assign(Bm);
    ShowMessage('Изображение помещено в буфер обмена.');
  end
  else
    ShowMessage('Изображение отсутствует.');
end;
1
1 / 1 / 0
Регистрация: 23.02.2014
Сообщений: 22
04.03.2015, 21:50  [ТС] 9
Mawrat, где же ты раньше был уже разобрался с этим вопросом я. Тему можно закрыть
1
1 / 1 / 0
Регистрация: 23.02.2014
Сообщений: 22
27.03.2015, 09:39  [ТС] 10
Товарищи форумчане, а как ускорить весь этот процесс? Если у меня 100 картинок в excel, пусть они небольшие (где 32*32 или 48*48). При загрузке из Excel мы получаем массив изображений, за одно обращение, а как ускорить весь этот процесс при сохранении изображений в Excel. Как сделать так, чтобы не обращаться каждый раз к эксель для сохранения очередной картинки? Как их вставить в диапазон?
0
 Аватар для Mawrat
13108 / 5889 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
27.03.2015, 15:27 11
Цитата Сообщение от shulga Посмотреть сообщение
При загрузке из Excel мы получаем массив изображений, за одно обращение
Из Excel картинки всё же по очереди передаются - во время перебора элементов коллекции Shapes, одна за другой через буфер обмена Windows.
Как я понял, передача в Excel по такой же схеме реализована:
Цитата Сообщение от shulga Посмотреть сообщение
Delphi
1
2
3
Clipboard.Assign(Bitmap);
Excel.workbooks[1].worksheets[1].Cells[i+2,2].Select;
Excel.workbooks[1].worksheets[1].Paste;
Если надо передать 100 небольших изображений - это, вроде, быстро должно выполниться...
0
1 / 1 / 0
Регистрация: 23.02.2014
Сообщений: 22
27.03.2015, 15:52  [ТС] 12
Mawrat, да, уже разобрался. Получается мы всего лишь получаем ссылку на коллекцию изображений и по-прежнему работаем с Excel через эту ссылку.
Цитата Сообщение от Mawrat Посмотреть сообщение
Если надо передать 100 небольших изображений - это, вроде, быстро должно выполниться...
Ну как сказать... секунд 15 проходит. А если записей 1000 и того больше, около 2 минут
Пробовал миновать выгрузку в стринггрид и использовать TObjectList - результат тот же.
Есть ли возможность ускорить этот процесс?
0
 Аватар для Mawrat
13108 / 5889 / 1707
Регистрация: 19.09.2009
Сообщений: 8,808
27.03.2015, 17:56 13
Цитата Сообщение от shulga Посмотреть сообщение
Пробовал миновать выгрузку в стринггрид и использовать TObjectList - результат тот же.
Основные затраты времени идут на выполнение методов MS Excel, COM взаимодействие и работу с буфером обмена.
Цитата Сообщение от shulga Посмотреть сообщение
Есть ли возможность ускорить этот процесс?
Надо предпринять меры для ускорения обработки в самом MS Excel. Очень много времени тратится на перерисовку окна MS Excel. Если окно MS Excel сделать невидимым или отключить его перерисовку, то в некоторых случаях обработка ускоряется в сотни раз. Также можно отключить обработку событий.
Delphi
1
2
3
4
5
6
7
8
9
10
  exApp.ScreenUpdating := False; //Отключение перерисовки окна MS Excel.
  exApp.EnableEvents := False;   //Отключение обработки событий.
  try
    {...}
    { Работа с MS Excel }
    {...}
  finally
    exApp.ScreenUpdating := True;
    exApp.EnableEvents := True;
  end;
Или так:
Delphi
1
2
3
4
5
6
7
8
9
10
  exApp.Visible := False;      //Скрываем окно MS Excel.
  exApp.EnableEvents := False; //Отключение обработки событий.
  try
    {...}
    { Работа с MS Excel }
    {...}
  finally
    exApp.Visible := True;
    exApp.EnableEvents := True;
  end;
0
27.03.2015, 17:56
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
27.03.2015, 17:56
Помогаю со студенческими работами здесь

Ошибка Invalid variant type
Код procedure TForm1.Button1Click(Sender: TObject); var DERMATOLOGY_TABLE : array of array of variant; begin ...

В чем отличие Variant от OLEVariant?
В чем отличие Variant от OLEVariant? Добавлено через 10 минут ну кроме того что olevariant специально для com интерфейса ...

Not convert variant null to double
Доброго времени суток! На событии ShowForm edtnWorkCostValue.Value := (dsOrderSum.FieldByName('WORK_COST').AsVariant); ...

Ошибка Record Array Of Variant
Здравствуйте уважаемые форумчане. Есть задание переписать процедуру, осуществляющую БПФ из С++ в Делфи. Но возникла проблема при...

Динамический массив of variant, почему ошибка?
ребята привет,объясни пожалуйста почему так нельзя делать function myfyn(b:byte):variant; begin if b=5 then result:=true; end; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему

Редактор формул (кликните на картинку в правом углу, чтобы закрыть)
Опции темы

Новые блоги и статьи
Микросервис с нуля на Go с Kafka
stackoverflow 12.02.2025
Когда я впервые столкнулся с необходимостью разделить монолитное приложение на микросервисы, передо мной встал вопрос выбора правильных технологий и подходов. После долгих экспериментов с различными. . .
Микросервис с нуля на C# с RabbitMQ
stackoverflow 12.02.2025
Переход от монолитной архитектуры к микросервисной - это не просто модное веяние, а закономерный этап эволюции программных систем. В отличие от монолита, где все компоненты тесно связаны между собой. . .
Docker для начинающих
stackoverflow 12.02.2025
В современном мире разработки программного обеспечения все чаще возникает необходимость быстро и надежно разворачивать приложения в различных средах. Разработчики постоянно сталкиваются с проблемой. . .
Создание бота для Телеграм на C#
stackoverflow 12.02.2025
В современном мире корпоративных коммуникаций Telegram-боты становятся незаменимым средством автоматизации бизнес-процессов и взаимодействия с сотрудниками. Как создать такого бота, который сможет. . .
Операторы сравнения (== и ===) в JavaScript
hw_wired 12.02.2025
JavaScript предоставляет два основных оператора сравнения - оператор нестрогого равенства (==) и оператор строгого равенства (===). На первый взгляд они могут показаться очень похожими, но их. . .
Определение адреса, откуда репозиторий Git был клонирован
hw_wired 12.02.2025
Система контроля версий Git хранит всю информацию о репозитории в специальной директории . git, включая данные об удаленных источниках. Эта информация необходима для синхронизации изменений между. . .
Объединение нескольких коммитов Git в один
hw_wired 12.02.2025
Представьте, что вы работаете над новой функциональностью и создали десяток небольших коммитов: исправление опечатки, форматирование кода, добавление комментариев, реализация основной логики. Каждый. . .
Как добавить локальную ветку в удалённый репозиторий Git
hw_wired 12.02.2025
Локальная ветка в Git - это изолированная линия разработки, существующая только на вашем компьютере. Представьте себе дерево с множеством веток - каждая ветка может расти в своем направлении, не. . .
Статическое отражение в C++
stackoverflow 12.02.2025
Статическое отражение представляет собой мощный механизм, позволяющий программам анализировать и манипулировать своей собственной структурой во время компиляции. Эта возможность открывает. . .
C++ в 21 веке - Бьярне Страуструп
stackoverflow 12.02.2025
В современном мире разработки программного обеспечения C++ продолжает оставаться одним из ключевых языков программирования, несмотря на свой солидный возраст - более 45 лет с момента создания. За это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru