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

當拖曳超過 MDIForm 範圍時,重新定義位置

尚未結案
BGman
初階會員


發表:28
回覆:85
積分:42
註冊:2003-01-10

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-03-04 11:13:10 IP:211.22.xxx.xxx 未訂閱
因為我安裝了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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-03-04 13:52:22 IP:203.75.xxx.xxx 未訂閱
你最好用以下方法 在 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

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-03-04 14:38:31 IP:211.22.xxx.xxx 未訂閱
你的方法我試了一下行不通! 因為,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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-03-04 15:09:11 IP:203.75.xxx.xxx 未訂閱
沒有人叫你寫在 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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-03-04 15:15:12 IP:203.75.xxx.xxx 未訂閱
我想你可能不太懂 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

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-03-04 15:44:00 IP:211.22.xxx.xxx 未訂閱
Sorry! 我可能講的不清楚,我試了你講的方法.. 但是因為安裝了SkinEngine 元件, 雖然寫了SavePos(...)這段碼,可是都沒有跑進去 然後只看到程式跑到這一行 END_MESSAGE_MAP(TForm) 我猜測事件可能被SkinEngine 這個元件攔截走了, 於是我就先用其他方式,測你所說的方法,只是下面這行... rcTemp = (LPRECT)Message.LParam; 我不知道寫在 MouseUp 要如何實做,如果攔截不到Message 時
jessechan
版主


發表:109
回覆:394
積分:254
註冊:2002-04-05

發送簡訊給我
#7 引用回覆 回覆 發表時間:2003-03-05 00:13:15 IP:61.228.xxx.xxx 未訂閱
有關這一行, rcTemp = (LPRECT)Message.LParam; 必須要跟隨 WM_MOVING 時 LParam 所傳回的值才是一個 RECT 的指標, 所以如果您作在 mouseup 是一定沒有作用的, 我沒有用過 SkinEngin, 所以不知道它是否會攔掉 WM_MOVING, 請問要在那裡下載這個東東, 我這兩天要出差, 可以的話, 我用週六日來測一下好不好. Jesse Chan
------
Jesse Chan
BGman
初階會員


發表:28
回覆:85
積分:42
註冊:2003-01-10

發送簡訊給我
#8 引用回覆 回覆 發表時間:2003-03-05 15:22:06 IP:211.22.xxx.xxx 未訂閱
不好意思 jessechan 兄,假日還要麻煩你! KD的首頁 http://www.ksdev.com/index.html KD的下載 http://www.ksdev.com/download.html
BGman
初階會員


發表:28
回覆:85
積分:42
註冊:2003-01-10

發送簡訊給我
#9 引用回覆 回覆 發表時間:2003-03-07 16:14:52 IP:211.22.xxx.xxx 未訂閱
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

發送簡訊給我
#10 引用回覆 回覆 發表時間:2003-03-10 03:10:43 IP:218.164.xxx.xxx 未訂閱
真是不好意思, 我最近比較忙, 一直在出差, 到現在才回覆, 我直接寫了一個 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

發送簡訊給我
#11 引用回覆 回覆 發表時間:2003-03-10 11:02:27 IP:211.22.xxx.xxx 未訂閱
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

發送簡訊給我
#12 引用回覆 回覆 發表時間:2003-03-10 13:32:34 IP:210.208.xxx.xxx 未訂閱
你可以不要用我的 project 檔, 自己 new 一個新的專案, 第一個 form 設成 MDIForm, 再 new 一個 form 設成 MDIChild, 然後用 Ultra Editor 編輯 unit1.cpp, unit1.h, unit2.cpp, unit2.h, 然後把我的 code 貼在你的 form 上面就可以了啊. Jesse Chan
------
Jesse Chan
BGman
初階會員


發表:28
回覆:85
積分:42
註冊:2003-01-10

發送簡訊給我
#13 引用回覆 回覆 發表時間:2003-03-10 14:36:25 IP:211.22.xxx.xxx 未訂閱
搞定了,已經可以拜讀你的 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

發送簡訊給我
#14 引用回覆 回覆 發表時間:2003-03-10 22:35:17 IP:218.164.xxx.xxx 未訂閱
引言: 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

發送簡訊給我
#15 引用回覆 回覆 發表時間:2003-03-11 09:52:59 IP:211.22.xxx.xxx 未訂閱
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

發送簡訊給我
#16 引用回覆 回覆 發表時間:2003-03-11 11:58:25 IP:218.164.xxx.xxx 未訂閱
引言:
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();
是一樣的.
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 Chan
------
Jesse Chan
BGman
初階會員


發表:28
回覆:85
積分:42
註冊:2003-01-10

發送簡訊給我
#17 引用回覆 回覆 發表時間:2003-03-11 13:33:54 IP:211.22.xxx.xxx 未訂閱
抱歉,小弟仍有不解...請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

發送簡訊給我
#18 引用回覆 回覆 發表時間:2003-03-12 16:03:19 IP:203.75.xxx.xxx 未訂閱
引言: 抱歉,小弟仍有不解...請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
系統時間:2024-05-03 14:14:15
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!