Как скопировать форму как изображение в буфер обмена - PullRequest
10 голосов
/ 07 июля 2010

Мне нужно скопировать форму (Delphi 2007) в буфер обмена как изображение, чтобы вставить то, что пользователь может видеть в текстовый документ. Часть буфера обмена на самом деле не проблема. Вопрос в том, как получить растровое изображение для формы.

Поиск обнаружил несколько вариантов.

  • Вызов GetFormImage
  • Используйте функцию PrintWindow API , которая является частью GDI +
  • Отправка сообщения WM_PRINT
  • Скопируйте Canvas для текущей формы, используя Canvas.CopyRect
  • Я также нашел компонент с именем TExcellentFormPrinter , решение которого работает лучше, чем любой из этих параметров, но я не знаю, какой метод он использует.

Все эти опции имеют разные проблемы. Большая часть информации, которую я нахожу, кажется устаревшей. Я не могу показаться хорошим источником, который сравнивает различные варианты с достаточным количеством деталей, чтобы я мог сделать выбор. Любой совет, с каким вариантом идти.

Я попробовал это в своей форме, и все они, кажется, работают хорошо, я просто пытаюсь избежать проблем в будущем. Любой совет, с каким решением идти?

Обновление: какие потенциальные проблемы с GetFormImage?
Андреас спросил, в чем проблема с GetFormImage. Надеюсь, больше ничего, это часть того, на что я пытаюсь получить ответ. Что меня беспокоит, так это то, что многие из моих результатов поиска предлагают творческие альтернативы использованию GetFormImage. Я надеялся, что ответы немного прояснят ситуацию.

Я был бы очень рад получить ответ, получивший много голосов: «У GetFormImage были некоторые проблемы, но сейчас нет причин не использовать его. : -)

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

1) Большие проблемы связаны с конкретной поддержкой, которая требуется от элементов управления в вашей форме. В списке Delphi 4 Исправления и известные проблемы есть эта запись (обратите внимание, что она указана как «Отложено до следующего»). Я не смог найти запись QC, которая показала, что это решено:

Область: vcl \ core vcl классы

Ссылочный номер: 1088 (Опубликовано: 16.12.98)
Статус: отложено до следующего
Rel Дата Сообщено: 8/6/98 Серьезность: Обычно встречающийся тип: Basic
Проблема сбоя функциональности:

Проблема в том, что с GetFormImage большинство элементов управления окнами вложений, таких как комбинированные списки и т. Д., Отображаются пустыми.

2) Я также использую элементы управления DevExpress. Когда-то их элементы управления (исправленные в конце 2006 года) не поддерживали сообщения PaintTo , которые использовались GetFormImage. Это исправлено в используемой версии DevExpress, но это вызывает у меня другие проблемы. Какова вероятность того, что другие элементы управления, которые я использую, могут работать некорректно?

3) Вот более свежая (2010) запись о группах Embarcadero . У пользователя возникли проблемы с использованием GetFormImage, когда часть графика, которую он отображал на экране, не появилась в конечном изображении. Им также нужно было включить заголовок формы (чего я не делаю), и они использовали подход Canvas.CopyRect , изложенный в этом посте .

4) Вот цитата со страницы TExcellentImagePrinter. У меня не было бы проблем с покупкой их продукта, если это необходимо. Там компонент выглядит так, как будто он последний раз обновлялся в 2002 году (хотя есть пробная версия Delphi 2007). Я не могу сказать, действительно ли мне нужно идти в этом направлении или нет.

Вы можете попробовать использовать GetFormImage или Form.Print. Попробуйте сбросить ComboBox вниз в форме, затем вызовите GetFormImage или Form.Print. Если , вы получите распечатка, вы видите текст в Поле со списком? Нет? Никто не делаетеще! Это только маленький пример проблемы, с которыми вы столкнетесь, когда печать бланков VCL.

Вы также можете попробовать использовать Borland's TI-3155 "Лучший способ напечатать форма ". Я написал TI, когда я работал в Borland как мера остановки разрыва. В то время как он напечатает текст со списком, это потерпит неудачу на многих принтерах, это не может распечатать всю форму, если ваш пользователь имеет изменил размер формы и не может распечатать формы, которые скрыты от глаз или находится частично за пределами экрана. код в основном создает скриншот, и надежно распечатать изображение, вы вероятно, хотел бы взглянуть на наш продукт TExcellentImagePrinter! Зачем? Проще говоря, это может потребовать пара тысяч строк низкого уровня графический код для печати растровых изображений хорошо под виндой.

1 Ответ

10 голосов
/ 07 июля 2010

Я не знаю, в чем проблема с GetFormImage, но вариант, который вы не пробовали (по крайней мере, явно):

procedure TForm1.FormClick(Sender: TObject);
var
  bm: TBitmap;
begin

  bm := TBitmap.Create;
  try
    bm.SetSize(ClientWidth, ClientHeight);
    BitBlt(bm.Canvas.Handle, 0, 0, ClientWidth, ClientHeight, Canvas.Handle, 0, 0, SRCCOPY);
    Clipboard.Assign(bm);
  finally
    bm.Free;
  end;

end;

Почти во всех случаях я ожидаю, что это приведет ктот же результат, что и

bm := GetFormImage;
try
  Clipboard.Assign(bm);
finally
  bm.Free;
end;

.(Кроме того, в процедуре Canvas.CopyRect используется StretchBlt, который, как я ожидаю, даст тот же результат, что и BitBlt, если не применяется растяжение.)

Метод 2

Вы всегда можете использоватьЭкран печати:

procedure TForm1.FormClick(Sender: TObject);
begin
  keybd_event(VK_SNAPSHOT, 1, 0, 0);
end;

Это также захватит границу и строку заголовка.Если вы хотите получить только клиентскую область, вы можете обрезать изображение:

procedure TForm1.FormClick(Sender: TObject);
var
  bm, bm2: TBitmap;
  DX, DY: integer;
begin
  Clipboard.Clear;
  keybd_event(VK_SNAPSHOT, 1, 0, 0);
  repeat
    Application.ProcessMessages;
  until Clipboard.HasFormat(CF_BITMAP);
  bm := TBitmap.Create;
  try
    bm.Assign(Clipboard);
    bm2 := TBitmap.Create;
    try
      bm2.SetSize(ClientWidth, ClientHeight);
      DX := (Width - ClientWidth) div 2;
      DY := GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME );
      BitBlt(bm2.Canvas.Handle, 0, 0, ClientWidth, ClientHeight, bm.Canvas.Handle, DX, DY, SRCCOPY);
      Clipboard.Assign(bm2);
    finally
      bm2.Free;
    end;
  finally
    bm.Free;
  end;
end;
...