全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1043
推到 Plurk!
推到 Facebook!

Canvas属性中SetCanvas处理的疑问

尚未結案
fangwy
中階會員


發表:99
回覆:139
積分:62
註冊:2003-09-10

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-12-06 12:35:11 IP:218.5.xxx.xxx 未訂閱
我设计的class部分代码如下: property Canvas: TCanvas read GetCanvas write SetCanvas; function TBASPrinter.GetCanvas: TCanvas; begin if FCanvas = nil then begin FCanvas := TCanvas.Create; FCanvas.Font := CurrencyPrinter.Canvas.Font; end; Result := FCanvas; end; procedure TBASPrinter.SetCanvas(Value: TCanvas); begin if FCanvas = nil then FCanvas := TCanvas.Create; FCanvas := Value; SetLength(PrinterCanvas, FLines.Count - 1); if PrinterCanvas[FLines.Count - 1] = nil then PrinterCanvas[FLines.Count - 1] := TCanvas.Create; PrinterCanvas[FLines.Count - 1] := FCanvas; end; 我发现 SetLength(PrinterCanvas, FLines.Count - 1); if PrinterCanvas[FLines.Count - 1] = nil then PrinterCanvas[FLines.Count - 1] := TCanvas.Create; PrinterCanvas[FLines.Count - 1] := FCanvas; 这一段好象根本没执行到,PrinterCanvas在使用时根本没被创建和赋值.想在这段上设断点跟踪,发现根本没法跟踪(运行起来,断点的颜色不再是红色).但是FCanvas 执行时明明已变成了设置的新值. 请教各位大大,SetXXXX个procedure的原理,及如何运用. 另外说明一下:FLines这个变量对应的属性在运行时正确.
aquarius
資深會員


發表:3
回覆:347
積分:330
註冊:2003-05-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-12-06 18:47:01 IP:211.23.xxx.xxx 未訂閱
PrinterCanvas 的定義是什麼? string or dynamic-array variable?    看你的程式, 應該只是想把 Canvas 記在一個 List 中. 建議使用 TList     
 
lst : TList ;
procedure TBASPrinter.SetCanvas(Value: TCanvas);
begin
  if FCanvas = nil then
    FCanvas := TCanvas.Create;
  FCanvas := Value;
  if lst=nil then
    lst:=TList.create ;      if lst.count        當然你實際上的 CODE 還可以另有變化, 就看你是要怎麼用的.        ...Aquarius
        
------
水瓶男的blog: http://791909.blogspot.com
fangwy
中階會員


發表:99
回覆:139
積分:62
註冊:2003-09-10

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-12-07 09:32:17 IP:218.5.xxx.xxx 未訂閱
aquarius: PrinterCanvas定义如下 PrinterCanvas: array of TCanvas; //打印格式; 其作用是记录运用中设置的Canvas 如下应用的例子: var Tcr: TTCRPrinter; begin try Tcr := TTCRPrinter.Create(pBill); except on E: Exception do begin Label3.Caption := E.Message; Abort; end; end; Tcr.Canvas.Font.Name := '宋体'; Tcr.Canvas.Font.Size := 11; Tcr.Lines.Add('0,0,第一行'); Tcr.Lines.Add('5,5,第二行'); Tcr.Lines.Add('10,10,第三行'); Tcr.Lines.Add('15,15,第四行'); Tcr.Lines.Add('20,20,第五行'); Tcr.Canvas.Font.Name := '黑体'; Tcr.Canvas.Font.Size := 12; Tcr.Lines.Add('25,25,第六行'); Tcr.Lines.Add('30,30,第七行'); Tcr.Lines.Add('35,35,第八行'); Tcr.Canvas.Font.Name := '楷体'; Tcr.Canvas.Font.Size := 14; Tcr.Lines.Add('40,40,第九行'); Tcr.Lines.Add('45,45,第十行'); Tcr.Lines.Add('L,45,第十一行'); Tcr.Lines.Add('C,45,第十二行'); Tcr.Lines.Add('R,45,第十三行'); Tcr.Print(); Label3.Caption := Tcr.Error; end; Tcr.Lines(TString型)是Print()打印的数据,使用PrinterCanvas的目的是记录三次设置的Canvas,并在打印时正确的使用到指定的行. 發表人 - fangwy 於 2004/12/07 09:36:08 發表人 - fangwy 於 2004/12/07 09:41:49
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-12-07 11:07:49 IP:220.130.xxx.xxx 未訂閱
FCanvas: array of TCanvas;    property Canvas[LineNo: Integer]: TCanvas read GetCanvas;    TBASPrinter.Create;
begin
  ...
  FCanvas := nil;
end;    TBASPrinter.Destroy;
var
  I: Integer;
begin
  for I := 0 to Length(FCanvas)-1 do
    if Assigned(FCanvas[I]) then
      FCanvas[I].Free;
  FCanvas := nil;
end;    TBASPrinter.GetCanvas(LineNo: Integer): TCanvas;
begin
  Result := nil;
  if(LineNo>-1)and(LineNo(The HDC of Printer's Canvas)
    end;
    Result := FCanvas[LineNo];    
  end;
end;    
fangwy
中階會員


發表:99
回覆:139
積分:62
註冊:2003-09-10

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-12-07 13:37:21 IP:218.5.xxx.xxx 未訂閱
谢谢JOW 您的方法给我提供了一个新的思路,但有一点不明: LineNo是怎么累加的.
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-12-07 16:00:35 IP:220.130.xxx.xxx 未訂閱
LineNo 並不用來累加,它只是用來作為索引用的, 用來透過property Canvas 的 GetMethod指向一個物件, 也就是說FLines中的每一個Item(string)可以有 其相對應的TCanvas.    
 
procedure TBASPrinter.SetCanvas(Value: TCanvas);
begin
  if FCanvas = nil then
    FCanvas := TCanvas.Create;FCanvas指向產生的物件
  FCanvas := Value;           FCanvas又指定為傳入物件
                              如此將產生記憶體遺漏,有物件沒有被釋放
  SetLength(PrinterCanvas, FLines.Count - 1);
  if PrinterCanvas[FLines.Count - 1] = nil then
  PrinterCanvas[FLines.Count-1] := TCanvas.Create;<---同上
  PrinterCanvas[FLines.Count-1] := FCanvas;       <---同上
end;    [blue]        A, B: TPersistent;
    A := TPersistent.Create;    可視為 (1) TPersistent.Create ---> 產生一個TPersistent
       (2) 物件指標 A 指向新產出的物件        B := A;  //B 與 A  指向同一物件    最後必須保留 A 或 B 來釋放物件      A := nil;
  B.Free;    或       B := nil;
   A.Free;    ==>property Canvas 透過 GetCanvas(LineNo: Integer): TCanvas; 取得一個TCanvas 物件指標.
==>FCanvas: array of TCanvas; 用來指向產出的TCanvas,提供做為被索引的目標,最後也用來釋放所有自行產生的所有TCanvas.
   
fangwy
中階會員


發表:99
回覆:139
積分:62
註冊:2003-09-10

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-12-08 10:40:34 IP:218.5.xxx.xxx 未訂閱
谢谢jow.不过我试了一下,这种做法不符合我的要求,因为每次设定Canvas时都必须指定对应的LineNo,而我想达到的效果是用户只要设置Canvas,至于如何记录使打印时与行匹配,由程序处理.就如我的例子: Tcr.Canvas.Font.Name := '宋体'; Tcr.Canvas.Font.Size := 11; Tcr.Lines.Add('0,0,第一行'); Tcr.Lines.Add('5,5,第二行'); Tcr.Lines.Add('10,10,第三行'); Tcr.Lines.Add('15,15,第四行'); Tcr.Lines.Add('20,20,第五行'); Tcr.Canvas.Font.Name := '黑体'; Tcr.Canvas.Font.Size := 12; Tcr.Lines.Add('25,25,第六行'); Tcr.Lines.Add('30,30,第七行'); Tcr.Lines.Add('35,35,第八行'); Tcr.Canvas.Font.Name := '楷体'; Tcr.Canvas.Font.Size := 14; Tcr.Lines.Add('40,40,第九行'); Tcr.Lines.Add('45,45,第十行'); Tcr.Lines.Add('L,45,第十一行'); Tcr.Lines.Add('C,45,第十二行'); Tcr.Lines.Add('R,45,第十三行'); Tcr.Print(); 对用户而言只需要在以不同字体打印的行前设置一下Canvas就行,而不必关心新设置的Canvas对应的是哪个LineNo.这样比较方便. 不知我是否完全理解jow兄的做法.
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-12-08 15:52:30 IP:220.130.xxx.xxx 未訂閱
sorry,我想我弄錯了你的需求,不過你的程式碼好像不是你說的這樣喔!    
以下是你的程式碼
function TBASPrinter.GetCanvas: TCanvas;
begin
  if FCanvas = nil then
  begin
    FCanvas := TCanvas.Create;
    FCanvas.Font := CurrencyPrinter.Canvas.Font;
  end;
  Result := FCanvas;
end;    procedure TBASPrinter.SetCanvas(Value: TCanvas);
begin
  if FCanvas = nil then
    FCanvas := TCanvas.Create;
  FCanvas := Value;      SetLength(PrinterCanvas, FLines.Count - 1);
  if PrinterCanvas[FLines.Count - 1] = nil then
    PrinterCanvas[FLines.Count - 1] := TCanvas.Create;
  PrinterCanvas[FLines.Count - 1] := FCanvas;
這段程式碼好像是為FLines的每一行,至少是為FLines.Count-1行,各配置一個TCanvas 吧
end;
 
我想我要說的是你在所寫的Class中對於TCanvas的產生指定的做法上,可能會產生記憶體遺漏的問題.還有就是指定TCanvas做為動作目標點的HDC的問題. 如果你的需求只是Keep由用戶端指定一個TCanvas的話,我認為你的Class裡只需要保留一個TCanvas的物件指標,而不需要去Create它,至於TCanvas 的生成和釋放的動作應由用戶端負責. 個人看法,謹供參考.
fangwy
中階會員


發表:99
回覆:139
積分:62
註冊:2003-09-10

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-12-13 09:21:24 IP:218.5.xxx.xxx 未訂閱
谢谢jow兄的耐心解答,我第一次贴的代码有问题,所以达不到想要的效果,仅管有些class的原理我还不很明白,但try了几种方法,我已实现了我的设计.就是每增加一行就增加一个PrinterCanvas元素,如果有新的Canvas设置就在新增加的PrinterCanvas元素中记录.在开始打印时,每一行打印前都检查对应的printerCanvas元素是否为空,如果不为空则使用.在Destroy中统一将创建的PrinterCanvas一次性释放. 也要谢谢aquarius兄. 發表人 - fangwy 於 2004/12/13 09:25:10
系統時間:2024-05-17 12:42:05
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!