當拖曳超過 MDIForm 範圍時,重新定義位置 |
尚未結案
|
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
因為我安裝了SkinEngine 元件,所以當MDIChild 超過MainForm時
不會有 Scroll Bar,於是我的需求是:在 MouseUp 中
當使用者將MDIChild 拖曳至不合法範圍時,我就重新定義位置
第一次:
if (MDIChild Left < 0 || MDIChild Top < 0 || MDIChild Left >= MainForm->ClientWidth || MDIChild Top >= MainForm->ClientHeight -100) MDIChild->Position = poDefaultPosOnly;可是,每次重新定義位置,MDIChild 的x,y軸位置都會 20, 效果如同New 一個MDIChild 第二次: 在MouseDown 先儲存座標 TPoint MDIChildPos = MDIChild ->ClientOrigin; 可是還是不理想,於是又試了BoundsRect 還是不行 請問我應該用哪一種 Type 來儲存Form 的座標比較好? |
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
你最好用以下方法
在 MDIChild 的 header 中的 public: 部份作以下宣告 void __fastcall SavePos(TMessage &Message);
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_MOVING,TMessage,SavePos);
END_MESSAGE_MAP(TForm); 如此你就可以攔截到 WM_MOVING 的訊息, 每次 user 在拖拉 MDIChild 時都會去呼叫 SavePos, 所以你就把你的座標檢查也放在 SavePos 中, 這時 MDIChild 的 Top 及 Left 都是未拖拉之前的值, 可供你作檢查, 我發現你的檢查式也寫錯了, 記得要改, 另外如果要知道目前視窗被拖到什麼地方請用 RECT * rcTemp;
rcTemp = (LPRECT)Message.LParam; 我想這樣該沒什麼問題了吧 Jesse Chan
------
Jesse Chan |
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
你的方法我試了一下行不通!
因為,FormMouseUp 是發生在 MDIChild 不能寫在 MainForm
抱歉我API不是很熟,是否可以請教一下
下面紅字這段我要什麼函式得到Rect,並且是以MainForm同步的座標
MDIChile->Left = 0 的座標,在MainForm可能是20,20
void __fastcall TMDIChild::FormMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { rcTemp = (LPRECT)Message.LParam; ShowMessage(rcTemp->left); if ( Left < 30 ) Left = rcTemp->left } |
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
沒有人叫你寫在 MouseUp 中啊.
RECT * rcTemp;
rcTemp = (LPRECT)Message.LParam;
是寫在 MDIChild 的 SavePos 中的, 因為你現在要攔截的 message 是 WM_MOVING, 在視窗被拖動時會收到這個訊息, 請參考 Windows SDK 的 help, 傳入的 LParam 是一個 RECT 型態的的位址, 所以宣告一個 RECT 的指標, 然後將 LParam 強迫轉型成 RECT 的指標, 這樣就可以隨時得知視窗被拖動的位置, 不過在你的 case 中, 這個功能並不需要, 我只是用到 WM_MOVING 所以附代一提. Jesse Chan
------
Jesse Chan |
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
我想你可能不太懂
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_MOVING,TMessage,SavePos);
END_MESSAGE_MAP(TForm);
的意義, 它的目的是要攔截視窗的訊息, 以上個例子而言, 就是說每當視窗收到 WM_MOVING 的訊息時(換到說法就是每當視窗被拖動的時候), 就會去呼叫 SavePos 這個函數,
SavePos 是一個使用者自訂的函數, 其原型宣告為
void __fastcall SavePos(TMessage &Message);
有關相關的用法如果還有不明的地方, 請參考 Help 有還算詳細的說明, 如果還是不懂再上來問. Jesse Chan
------
Jesse Chan |
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
|
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
|
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
不好意思 jessechan 兄,假日還要麻煩你!
KD的首頁
http://www.ksdev.com/index.html
KD的下載
http://www.ksdev.com/download.html
|
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
jessechan 兄你好!
小弟按照你的做法,先在一個沒有安裝SkinEngin的專案執行,仍然有些不解!
1.你所說的 攔截WM_MOVING 觸發 SavePos(TMessage &Message);
我應該如何判斷需要儲存呢?
void __fastcall TForm1::SavePos(TMessage &Message) { if (Message.LParam > 0) rcTemp = (LPRECT)Message.LParam; }2.然後應該在哪個事件,判斷位置不合法,再回復至儲存的座標呢? OnMouseUp , OnDragDrop ... 都不理想 |
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
真是不好意思, 我最近比較忙, 一直在出差, 到現在才回覆, 我直接寫了一個 sample, 放在 http://delphi.ktop.com.tw/loadfile.php?TOPICID=8427225&CC=188475 我想你應該可從這裡知道怎做, 可以的話我就不 download SkinEngine, 因為還要重新看文件, 而且也要付費, 如果還有問題, 請再貼上來, 我這兩天住的飯店可以上網, 比較方便. Jesse Chan
------
Jesse Chan |
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
jessechan 兄,我下載之後有一些問題不能執行!
難道跟我的BCB 版本是 5.0 ,有關嗎?
開啟執行檔時,出現錯誤訊息,無法動態連結CC3260MT.DLL
開啟專案時,出現找不到 很多 bpi ,我將你的 bpr 以UltraEdit 打開
看到你的專案用了數十個 bpi ,所以我把他覆寫成,希望可以成功 幾乎抑制了所有的錯誤訊息,但是還是功虧一簣,因為找不到
CorIde50.bpi CorIde50.bpl , 是不是一定要裝 BCB6 可以?
還是可以麻煩你,載幫我重新編一下專案檔,將 PACKAGES 調整至最少
1.Borland Standar Conponents 2.Delphi 1.0 Compatibility Conponents
感激不盡!
|
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
|
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
搞定了,已經可以拜讀你的 Sample Code,再次感謝jessechan 兄!
雖然只有短短幾行程式碼,可是確潛藏了深奧的原理!功力可見一般!
小弟資質駑鈍,是否能請你解釋一下CheckPos()...
BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_MOVING,TMessage,SavePos); VCL_MESSAGE_HANDLER(WM_MOVE,TMessage,CheckPos); END_MESSAGE_MAP(TForm); 請問是否含有先執行SavePos,再執行CheckPos意思? void __fastcall TForm2::CheckPos(TMessage &Message) { int nX, nY; AnsiString asTemp; nX = Message.LParamLo; nY = Message.LParamHi; if ((nX < 0) || (nY < 0) || ((nX Width) > Form1->ClientWidth) || ((nY Height) > Form1->ClientHeight)) { Left = nOldX; Top = nOldY; } } void __fastcall TForm2::SavePos(TMessage &Message) { RECT * rcTemp; rcTemp = (LPRECT)Message.LParam; nOldX = Form2->Left; nOldY = Form2->Top; }請問一下: 1. rcTemp 是用來做什麼的?跟 nOldX 的值有關嗎? 2. 你是如何做到控管座標小於零不會儲存? |
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
引言: BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_MOVING,TMessage,SavePos); VCL_MESSAGE_HANDLER(WM_MOVE,TMessage,CheckPos); END_MESSAGE_MAP(TForm); 請問是否含有先執行SavePos,再執行CheckPos意思? 1. rcTemp 是用來做什麼的?跟 nOldX 的值有關嗎? 2. 你是如何做到控管座標小於零不會儲存?[/blue]1. 那幾個 macro 只是指定系統如果收到特定的 window message 時要去呼叫的 call back function, 和前後順序沒有太大的關係, 就如同 nI = 0; nJ = 0; 和 nJ = 0; nI = 0; 是一樣的. 2. rcTemp 在這個 sample 中並沒有作用, 只是如果你要在視窗移動時隨時拮取當時的座標可以從 rcTemp 中得知. 3. 對不起, 這個 sample 是臨時寫出來的, 所以有一個 bug, 我當時沒考慮 Form2 的 Caption 及 border 的大小, 所以你會發現有負的座標出現, 要解決這個問題可以先宣告一個公用變數 TPoint ptTemp; 然後在 Form2 OnCreate 時加上 RECT rcTemp; Left = 0; Right = 0; GetWindowRect(Form2->Handle,&(rcTemp)); ptTemp.x = rcTemp.left; ptTemp.y = rcTemp.top; ptTemp = ScreenToClient(ptTemp); ptTemp.x *= (-1); ptTemp.y *= (-1); 如此可由 ptTemp 得知 border 及 Caption 的大小, 最後把檢查 range 的那行改成 if ((nX < ptTemp.x) || (nY < ptTemp.y) || ((nX Width) > Form1->ClientWidth) || ((nY Height) > Form1->ClientHeight)) { Left = nOldX; Top = nOldY; } 就大功告成了, 在 MDI 起始時座標一定是正的, 所以透過以上方式處理, 可確保不會有負的情形出現. Jesse Chan
------
Jesse Chan |
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_MOVING,TMessage,SavePos); VCL_MESSAGE_HANDLER(WM_MOVE,TMessage,CheckPos); END_MESSAGE_MAP(TForm); jessechan 兄,你的意思是我們不能預測哪一個Method 先發生嗎? 如果想要控制執行順序,就必須設旗標來控制嗎?例如 bool bSaveFlag; void __fastcall SavePos(TMessage &Message) { if bSaveFlag do something ...; } jessechan 兄,你誤會我的意思了!你寫的程式很完美! 並沒有負數的 Bug ,我試了數十次都非常完美! 只要一超過 MDIForm 範圍就可以回到原來的位置。 我的意思是如果當MDIChild 超出範圍時位標變成負數時, 如果先執行 SavePos() 再執行 CheckPos() 會不符程式需求。 可是我看不到有任何程式碼,在做這項檢查。所以才想請教你是如何控制的。 因為你說 nI = 0; SavePos(); nJ = 0; CheckPos(); 和 nJ = 0; CheckPos(); nI = 0; SavePos(); 是一樣的. |
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
引言:Sorry, 您也誤會我的意思了, 我只是說 BEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_MOVING,TMessage,SavePos); VCL_MESSAGE_HANDLER(WM_MOVE,TMessage,CheckPos); END_MESSAGE_MAP(TForm); 這個 macro 中, 兩個 VCL_MESSAGE_HANDLE 的順序不會影響程式執行, 事實上以事件發生的順序而言, 一定是 mouse 先 moving 然後才有 move 的事件產生, 所以不會有你擔心的狀況出現. 我的程式真的有 bug, 你把 MDIChild 試著移到左上角一點點的位置, 稍稍蓋住 Caption 及 border, 或是只蓋住一半的 Caption, 就可以發現有負值出現, 請依我寫的方法作修正. Jesse ChanBEGIN_MESSAGE_MAP VCL_MESSAGE_HANDLER(WM_MOVING,TMessage,SavePos); VCL_MESSAGE_HANDLER(WM_MOVE,TMessage,CheckPos); END_MESSAGE_MAP(TForm); jessechan 兄,你的意思是我們不能預測哪一個Method 先發生嗎? 如果想要控制執行順序,就必須設旗標來控制嗎?例如 bool bSaveFlag; void __fastcall SavePos(TMessage &Message) { if bSaveFlag do something ...; } jessechan 兄,你誤會我的意思了!你寫的程式很完美! 並沒有負數的 Bug ,我試了數十次都非常完美! 只要一超過 MDIForm 範圍就可以回到原來的位置。 我的意思是如果當MDIChild 超出範圍時位標變成負數時, 如果先執行 SavePos() 再執行 CheckPos() 會不符程式需求。 可是我看不到有任何程式碼,在做這項檢查。所以才想請教你是如何控制的。 因為你說 nI = 0; SavePos(); nJ = 0; CheckPos(); 和 nJ = 0; CheckPos(); nI = 0; SavePos(); 是一樣的.
------
Jesse Chan |
BGman
初階會員 發表:28 回覆:85 積分:42 註冊:2003-01-10 發送簡訊給我 |
抱歉,小弟仍有不解...請jessechan兄指教
RECT rcTemp;
Left = 0; 請問是Form2->Left 還是rcTemp.left;
Right = 0; 不明?我猜作用應該是歸零動作
GetWindowRect(Form2->Handle,&(rcTemp)); 得到Form2的邊界
ptTemp.x = rcTemp.left;
ptTemp.y = rcTemp.top;
ptTemp = ScreenToClient(ptTemp); 轉換成相對於Client的座標
ptTemp.x *= (-1); 請問為何要乘上-1
ptTemp.y *= (-1);
小弟感激不盡!
|
jessechan
版主 發表:109 回覆:394 積分:254 註冊:2002-04-05 發送簡訊給我 |
引言: 抱歉,小弟仍有不解...請jessechan兄指教 RECT rcTemp; Left = 0; 請問是Form2->Left 還是rcTemp.left; Right = 0; 不明?我猜作用應該是歸零動作 GetWindowRect(Form2->Handle,&(rcTemp)); 得到Form2的邊界 ptTemp.x = rcTemp.left; ptTemp.y = rcTemp.top; ptTemp = ScreenToClient(ptTemp); 轉換成相對於Client的座標 ptTemp.x *= (-1); 請問為何要乘上-1 ptTemp.y *= (-1); 小弟感激不盡! >>< face="Verdana, Arial, Helvetica"> 1. Form2 的. 2. 的確是要歸零, 之後的程式才能取得正確的邊界及標題. 3. 用那個方法取得的其實是座標值, 因為有之前的歸零動作, 所以可以拿來當作是邊界及標題的高度, 但是座標值是負的, 所以 * (-1), 把它變正的. Jesse Chan
------
Jesse Chan |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |