Как я могу сохранить все свойства TControlCanvas и восстановить их позже?
Я пытаюсь написать собственный метод рисования ячейки для TDBGridEh
, Проблема в том, что когда я меняю свойства пера, кисти,... картина становится грязной. Это связано с тем, что элемент управления выполняет дополнительное рисование после вызова события. Поэтому я должен сохранить все реквизиты и затем сбросить их, когда моя собственная картина закончится.
Я пытался создать свой собственный TControlCanvas
и назначить ему единицу сетки, но я получаю исключение времени выполнения с сообщением:
Невозможно назначить TControlCanvas TControlCanvas
, что указывает на AssignTo
метод не реализован для TControlCanvas
ни для его предков. Итак, мои вопросы:
Зачем
TControlCanvas
не имеетAssignTo
метод? В чем проблема?Как я могу сохранить и восстановить все свойства TControlCanvas? И под этим я подразумеваю что-то более удобное, чем создание
TPen
,TBrush
,TFont
, так далее..
2 ответа
Не уверен, что это соответствует вашим ожиданиям, но есть TPenRecall
, TBrushRecall
а также TFontRecall
сохранить и восстановить настройки этих трех свойств полуавтоматическим способом.
Обработка довольно проста: создайте экземпляр этих классов с соответствующими свойствами в качестве параметра и делайте все, что вы хотите с помощью Pen, Brush и Font. В конце освободите те экземпляры, которые восстановят настройки.
В сочетании с TObjectList
и некоторая внутренняя ссылка, подсчитывающая усилия, необходимые для сохранения и восстановления этих свойств холста, может быть уменьшена до одного слоя.
type
TCanvasSaver = class(TInterfacedObject)
private
FStorage: TObjectList<TRecall>;
public
constructor Create(ACanvas: TCanvas);
destructor Destroy; override;
class function SaveCanvas(ACanvas: TCanvas): IInterface;
end;
constructor TCanvasSaver.Create(ACanvas: TCanvas);
begin
inherited Create;
FStorage := TObjectList<TRecall>.Create(True);
FStorage.Add(TFontRecall.Create(ACanvas.Font));
FStorage.Add(TBrushRecall.Create(ACanvas.Brush));
FStorage.Add(TPenRecall.Create(ACanvas.Pen));
end;
destructor TCanvasSaver.Destroy;
begin
FStorage.Free;
inherited;
end;
class function TCanvasSaver.SaveCanvas(ACanvas: TCanvas): IInterface;
begin
Result := Self.Create(ACanvas);
end;
Использование:
procedure TForm274.DoYourDrawing(ACanvas: TCanvas);
begin
TCanvasSaver.SaveCanvas(ACanvas);
{ Change Pen, Brush and Font of ACanvas and do whatever you need to do.
Make sure that ACanvas is still valid and the same instance as at the entry of this method. }
end;
В то время как TCanvas
на самом деле не инкапсулирует эти функции API, можно использовать SaveDC
а также RestoreDC
делать то, что вам нужно. Из MSDN:
Функция SaveDC сохраняет текущее состояние указанного контекста устройства (DC), копируя данные, описывающие выбранные объекты и графические режимы (такие как растровое изображение, кисть, палитра, шрифт, перо, область, режим рисования и режим отображения) в контекст стек.
[...]
Функция RestoreDC восстанавливает контекст устройства (DC) до указанного состояния. DC восстанавливается путем извлечения информации о состоянии из стека, созданного предыдущими вызовами функции SaveDC.
Возможный пример кода:
uses
Winapi.Windows;
...
var
SavedDC: Integer;
begin
SavedDC := SaveDC(Canvas.Handle);
try
// Painting code
finally
RestoreDC(Canvas.Handle, SavedDC);
end;
end;
Редактировать:
Я понял, что одно это, скорее всего, не будет ответом. Это будет обрабатывать контекст устройства на стороне Windows, которая представлена TCanvas
/TControlCanvas
объект на стороне VCL Delphi. Но это не изменит ни одного из TFont
, TBrush
или же TPen
объекты, которые содержит VCL. Из тестов это выглядит так, например, всякий раз, когда Delphi использует Canvas Brush.GetHandle
(FillRect
, FrameRect
), это все еще измененная кисть.
Так что лучше всего использовать SaveDC
а также RestoreDC
в сочетании с хранением и восстановлением Pen
, Font
а также Brush
как в ответе Уве Раабе.