線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1205
推到 Plurk!
推到 Facebook!

請問:結束 MDI Child 時,按「x」和「self.close」,有什麼不同?

答題得分者是:borland_delphi70
jaya
初階會員


發表:9
回覆:70
積分:30
註冊:2002-05-22

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-11-28 05:23:12 IP:220.135.xxx.xxx 未訂閱
遇到了一個怪怪的問題 在 MDI Form 裡,動態開啟了一個子表單(MDI Child)。 表單裡放了一個SpeedButton,功能就是結束表單:self.close; 開啟、操作都沒有問題。可是在結束子表單時就很奇怪了。 如果是按子表單右上的「X」的話,就可以正常結束。 但是按下SpeedButton就會出現錯誤。「Access Violation with message at address ....)。 更怪的是,同一張子表單,再重開一次,再按一次SpeedButton,也可以正常結束。 也就是,只有程式執行後,第一次開啟這個子表單,而且是用SpeedButton結束的,才會有問題,其餘狀況都是ok的。 該子表單是動態建立的,結束時也有 freeandnil()。 請問有人遇過這種狀況嗎?
jeffreck
高階會員


發表:247
回覆:340
積分:197
註冊:2003-01-23

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-11-28 09:41:23 IP:61.218.xxx.xxx 未訂閱
可否把程式碼,貼出來看看,大家較好查原因?
jaya
初階會員


發表:9
回覆:70
積分:30
註冊:2002-05-22

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-11-28 11:19:44 IP:220.135.xxx.xxx 未訂閱
謝謝 jeffreck 的回覆。 因為這是專案裡的一部份,是繼承共用Form之後才發生的。 但是,並不是每個繼承的Form都會發生,大部份是沒問題的。 只有一、二個子表單會發生這種狀況。 至於把這段程式碼獨立出來,因為是繼承的關係, 只貼出有問題的 Form 也無法現出問題的全貌。 只好以敘述問題的方式提出。
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-11-28 11:34:49 IP:61.229.xxx.xxx 未訂閱
to jaya: 依你所述,很明顯的,是有變數,指標或物件提早被釋放的關係,才會出現錯誤訊息.我想,可能你的mdi child提早釋放了共用的form所需用的物件吧.建議你從SpeedButton裡去Debug應該可以找到原因.
jaya
初階會員


發表:9
回覆:70
積分:30
註冊:2002-05-22

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-11-28 13:44:22 IP:220.135.xxx.xxx 未訂閱
謝謝 change.jian 的回覆。    從「Access Violation」的錯誤訊息來看,應該是您說的原因。 但是我查不出來  因為問題是發生在「開啟表單-立即結束」的狀況下,在移除無關的程式碼之後, 該子表單的程式碼如下。 被繼承的單元中,與開始、結束有關的程式碼也附在最後面。 ( class="code"> unit ufmDiagRoom; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Udbform, DB, DBCtrls, Buttons, ExtCtrls, StdCtrls, Mask, ADODB; type TfmDiagRoom = class(TDbForm) dtDiagRoom: TADOTable; dtDiagRoomsn: TAutoIncField; dtDiagRoomDiag_RoomID: TStringField; dtDiagRoomDiag_RoomName: TStringField; dtDiagRoomenable: TBooleanField; Label1: TLabel; DBEdit1: TDBEdit; Label2: TLabel; DBEdit2: TDBEdit; Label3: TLabel; DBCheckBox1: TDBCheckBox; dtUser: TADOQuery; dsUser: TDataSource; DBLookupComboBox1: TDBLookupComboBox; dtDiagRoomDiag_DrID: TWideStringField; dtDiagRoomDiag_DrName: TWideStringField; dtUserUserid: TWideStringField; dtUserusername: TWideStringField; dtUseruserename: TWideStringField; dtUserpassword: TWideStringField; dtUseractive: TIntegerField; dtUserqua: TIntegerField; Label4: TLabel; DBEdit3: TDBEdit; dtDiagRoomDiag_FormName: TWideStringField; Label5: TLabel; dtProgram: TADOQuery; dsProgram: TDataSource; DBLookupComboBox2: TDBLookupComboBox; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure bpostClick(Sender: TObject); private { Private declarations } public { Public declarations } procedure opendb;override; end; var fmDiagRoom: TfmDiagRoom; implementation uses global, UDM, UPub; {$R *.dfm} procedure TfmDiagRoom.opendb; begin inherited; dtDiagRoom.Open; dtUser.Open; end; procedure TfmDiagRoom.FormClose(Sender: TObject; var Action: TCloseAction); begin inherited; freeandnil(fmDiagRoom); end; procedure TfmDiagRoom.bpostClick(Sender: TObject); begin dtDiagRoom.FieldByName('Diag_DrName').AsString := dtUser.FieldByName('UserName').AsString; inherited; end; end. 被繼承的單元裡的相關程式碼:
 
procedure TDbForm.FormCreate(Sender: TObject);
begin
    opendb;
end;    procedure TDbForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
       if ds1.dataset.State <> dsbrowse then begin
         if messagedlg('資料尚未儲存,確定要離開?',mtConfirmation,
            [mbYes, mbNo], 0) <> mrYes then
         begin
            canclose:=false;
         end;
       end;
end;    procedure TDbForm.bexitClick(Sender: TObject);
begin
   self.Close;
end;
jeffreck
高階會員


發表:247
回覆:340
積分:197
註冊:2003-01-23

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-11-28 16:25:05 IP:61.218.xxx.xxx 未訂閱
不知道會不會是以下的問題,試試看   freeandnil(fmDiagRoom); 改為   freeandnil(self);    參考看看,如果不是別打我
jaya
初階會員


發表:9
回覆:70
積分:30
註冊:2002-05-22

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-11-28 22:32:05 IP:220.135.xxx.xxx 未訂閱
引言: 不知道會不會是以下的問題,試試看 freeandnil(fmDiagRoom); 改為 freeandnil(self); 參考看看,如果不是別打我 < face="Verdana, Arial, Helvetica"> 謝謝 ~ 結果沒變
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-11-28 22:44:30 IP:218.170.xxx.xxx 未訂閱
這有可能的情況是 祖先類別的form已經做了free的動作 在後代類別再一次free就會引發av錯誤了
jaya
初階會員


發表:9
回覆:70
積分:30
註冊:2002-05-22

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-11-30 00:29:54 IP:220.135.xxx.xxx 未訂閱
引言: 這有可能的情況是 祖先類別的form已經做了free的動作 在後代類別再一次free就會引發av錯誤了
謝謝提醒~ 可是,只有這個Form會有問題,其他Form都是ok的。 而我是每個Form都有做FreeAndNil 的動作。
borland_delphi70
中階會員


發表:8
回覆:50
積分:51
註冊:2002-12-06

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-12-09 00:17:17 IP:220.132.xxx.xxx 未訂閱
function TCustomForm.CloseQuery: Boolean; var I: Integer; begin if FormStyle = fsMDIForm then begin Result := False; for I := 0 to MDIChildCount - 1 do if not MDIChildren[I].CloseQuery then Exit; end; Result := True; if Assigned(FOnCloseQuery) then FOnCloseQuery(Self, Result); end; 在 CloseQuery 中對 MDIChild 的處理作業是從 0 到 N 所以自行在 MDIChild 的 CloseQuery 中自行 Free 會導致 Loop I 不正確,進而引發錯誤,而且不固定是哪個 MDIChild 關閉時會錯誤,一般而言在關到第 3 或第 4 個 MDIChild 時會 Access Violation
borland_delphi70
中階會員


發表:8
回覆:50
積分:51
註冊:2002-12-06

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-12-09 18:21:55 IP:220.130.xxx.xxx 未訂閱
使用 if FormStyle=fsMDIChild then Release; 即可解決此問題
jaya
初階會員


發表:9
回覆:70
積分:30
註冊:2002-05-22

發送簡訊給我
#12 引用回覆 回覆 發表時間:2004-12-10 00:29:15 IP:220.135.xxx.xxx 未訂閱
引言: 使用 if FormStyle=fsMDIChild then Release; 即可解決此問題
我用這行取代原先的「freeandnil();」,就沒問題了。 真是太棒了~ 也謝謝各位的熱心幫忙 ,謝謝~
系統時間:2024-06-28 8:35:42
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!