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

請問如何讓TMemo不是被focus時,仍能顯示游標??

尚未結案
YuHeng
一般會員


發表:8
回覆:13
積分:4
註冊:2003-02-26

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-01-14 15:26:30 IP:61.219.xxx.xxx 未訂閱
當TMemo不是被Focus時,其游標會消失, 如此就不會知道其所在的位置, 如何當Focus on 其他元件時,在TMemo的游標不會被隱藏... 試了幾個方法,都不理想.... 1.在Memo的OnExit內加上 if(!Memo1->SelLength) { Memo1->SelSelength = 1; } 把Memo1->HideSelection 設為 false; 如此雖可標示位置,但意思表達不是很清楚, 會讓user會有要對該字元要做處理的聯想... 2.把其他元件的OnClick內都加上 Memo1->SetFocus(); 強迫Focus回Memo1. 但此方法對TEdit,就不可使用.. 請問有沒方法可達成我的需求.... 感謝大家的熱心先!!
ENIX007
高階會員


發表:28
回覆:274
積分:185
註冊:2003-11-27

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-01-15 08:59:19 IP:210.243.xxx.xxx 未訂閱
YuHeng您好 小弟之前也遇過和您類似的問題,當時得到的結論是基本上除了HideSelection 屬性外,只有Focus在Memo上才有可能顯示游標 除非製作假象,如mieng兄所述方法 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=41179 另外,如果您能接受使用SetFocus()方法的話,TEdit倒是可以寫在DbClick() 事件中... 給您一些參考 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
------
程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
m8815010
版主


發表:99
回覆:372
積分:289
註冊:2003-11-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-01-16 08:58:07 IP:61.63.xxx.xxx 未訂閱
YuHeng你好:                        其時我覺得你的第一個方法就很不錯了,只是      你可覺得不夠漂亮吧!但是我覺得第二個方法是不行      的,因為這跟本是把focus切回去吧了,與你的題目      原意完全違反。              這邊我有一個大致功能的方式,應該與ENIX007      兄所提mieng兄的作法不同,精神就是玩message、hook      這樣的事而已。 圖例:            圖例說明:上例可以看到當測試區的TMemo元件focus被初換到其它3個元件時, 它的游標還是在的,而下方可以檢測focus是否真正切換。 使用者也可以測試在其它3個元件(Button1、Button2、RichEdit1) 在被setfocus時是否能正常運作,列如切到RichEdit時就要能key data進去(而Memo1的游標仍然在),這也是YuHeng兄方法二為什麼 不行的理由。 範例程式: ~~~ TForm1 *Form1; int i=0; ~~~ //-------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { ShowMessage("我被按了!"); SendMessage(Memo1->Handle,WM_KILLFOCUS,0,0); SendMessage(Memo1->Handle,WM_SETFOCUS,0,0); } //--------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { i++; Form1->Caption="我被按了 : "+IntToStr(i)+" 次"; SendMessage(Memo1->Handle,WM_KILLFOCUS,0,0); SendMessage(Memo1->Handle,WM_SETFOCUS,0,0); } //--------------------------------------------------------- void __fastcall TForm1::RichEdit1Enter(TObject *Sender) { SendMessage(Memo1->Handle,WM_SETFOCUS,0,0); } //--------------------------------------------------------- void __fastcall TForm1::Memo1Click(TObject *Sender) SendMessage(Memo1->Handle,WM_KILLFOCUS,0,0); Button1->SetFocus(); Memo1->SetFocus(); } //--------------------------------------------------------- void __fastcall TForm1::Memo2MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { AnsiString s ="Button1 --->"; Memo2->Lines->Add(s+(int)Button1->Focused()); s="Memo1 --->"; Memo2->Lines->Add(s+(int)Memo1->Focused()); s="RichEdit1--->"; Memo2->Lines->Add(s+(int)RichEdit1->Focused()); s="Button2 --->"; Memo2->Lines->Add(s+(int)Button2->Focused()); Memo2->Lines->Add("------------------------"); } //---------------------------------------------------------- *注意事項* 1. 這個例子只是用onclick、onenter等當成setfocus的事件用,正當 應該找setfocus、或losefocus這樣的事件用,如果沒有就要自已攔 WM_SETFOCUS、WM_KILLFOCUS自已做了。 *2. 上述結果就是如果你用tab鍵來切換focus,就可能不能很正常的運作。 3. RichEdit的加入,是一個明顯的測試,證明當focus切到RichEdit時, 我們就能input data在RichEdit內,而Memo1游在仍在。 4. 上述的例子精神講好聽一點就是代替OS送一個message告訴Memo1它已 經被setfocus了,所以它在收到message後會執行對應的function,生 成游標,但是OS本身並沒有被騙,所以真正的focus仍在RichEdit。 *5. 上述OS沒有被騙的結果就是RichEdit在setfocus時是沒有游標的。 *6. 綜合上述,使用者可以改良程式以達自已需求,另外,顯然的,我們 應該可以欺騙OS,做到同時多個游標。這點可以再研究。
ENIX007
高階會員


發表:28
回覆:274
積分:185
註冊:2003-11-27

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-01-16 09:41:42 IP:210.243.xxx.xxx 未訂閱
哇~~< > 真的可以耶,好厲害< > 當時討論相關問題時,小弟也有研究WM_KILLFOCUS和WM_SETFOCUS這二個 message,但是無論如何做不出這種效果... 太感謝m8815010大大了,這個範例程式碼小弟不客氣收下囉 感謝您~~ 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
------
程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~
YuHeng
一般會員


發表:8
回覆:13
積分:4
註冊:2003-02-26

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-01-17 00:11:02 IP:61.56.xxx.xxx 未訂閱
引言: YuHeng你好: 其時我覺得你的第一個方法就很不錯了,只是 你可覺得不夠漂亮吧!但是我覺得第二個方法是不行 的,因為這跟本是把focus切回去吧了,與你的題目 原意完全違反。 這邊我有一個大致功能的方式,應該與ENIX007 兄所提mieng兄的作法不同,精神就是玩message、hook 這樣的事而已。 圖例: 圖例說明:上例可以看到當測試區的TMemo元件focus被初換到其它3個元件時, 它的游標還是在的,而下方可以檢測focus是否真正切換。 使用者也可以測試在其它3個元件(Button1、Button2、RichEdit1) 在被setfocus時是否能正常運作,列如切到RichEdit時就要能key data進去(而Memo1的游標仍然在),這也是YuHeng兄方法二為什麼 不行的理由。 範例程式: ~~~ TForm1 *Form1; int i=0; ~~~ //-------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { ShowMessage("我被按了!"); SendMessage(Memo1->Handle,WM_KILLFOCUS,0,0); SendMessage(Memo1->Handle,WM_SETFOCUS,0,0); } //--------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { i++; Form1->Caption="我被按了 : "+IntToStr(i)+" 次"; SendMessage(Memo1->Handle,WM_KILLFOCUS,0,0); SendMessage(Memo1->Handle,WM_SETFOCUS,0,0); } //--------------------------------------------------------- void __fastcall TForm1::RichEdit1Enter(TObject *Sender) { SendMessage(Memo1->Handle,WM_SETFOCUS,0,0); } //--------------------------------------------------------- void __fastcall TForm1::Memo1Click(TObject *Sender) SendMessage(Memo1->Handle,WM_KILLFOCUS,0,0); Button1->SetFocus(); Memo1->SetFocus(); } //--------------------------------------------------------- void __fastcall TForm1::Memo2MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { AnsiString s ="Button1 --->"; Memo2->Lines->Add(s+(int)Button1->Focused()); s="Memo1 --->"; Memo2->Lines->Add(s+(int)Memo1->Focused()); s="RichEdit1--->"; Memo2->Lines->Add(s+(int)RichEdit1->Focused()); s="Button2 --->"; Memo2->Lines->Add(s+(int)Button2->Focused()); Memo2->Lines->Add("------------------------"); } //---------------------------------------------------------- *注意事項* 1. 這個例子只是用onclick、onenter等當成setfocus的事件用,正當 應該找setfocus、或losefocus這樣的事件用,如果沒有就要自已攔 WM_SETFOCUS、WM_KILLFOCUS自已做了。 *2. 上述結果就是如果你用tab鍵來切換focus,就可能不能很正常的運作。 3. RichEdit的加入,是一個明顯的測試,證明當focus切到RichEdit時, 我們就能input data在RichEdit內,而Memo1游在仍在。 4. 上述的例子精神講好聽一點就是代替OS送一個message告訴Memo1它已 經被setfocus了,所以它在收到message後會執行對應的function,生 成游標,但是OS本身並沒有被騙,所以真正的focus仍在RichEdit。 *5. 上述OS沒有被騙的結果就是RichEdit在setfocus時是沒有游標的。 *6. 綜合上述,使用者可以改良程式以達自已需求,另外,顯然的,我們 應該可以欺騙OS,做到同時多個游標。這點可以再研究。
真是太感謝m8815010跟ENIX007了..... 因為功力太淺,都沒想過此方法.... 剛剛測了一下,衍生了另一個問題.... 就是此時游標都會在Memo上.. 相對Edit上反而沒有游標.. 這幾天也努力找解答,目前的了解是,因Caret由Windows handle, 所以Caret會顯示在focus的物件上..目前覺得最佳解決的方法 應該是讓Memo有一個獨立的Caret.如此就不會受系統所控制.. 初步的想法是,create一個 memo的caret,然後去攔截message, 當focus的時候,把該caret殺到,如果沒被focus的時候,就產生... 因對這部分完全沒接觸過,所以還在嘗試中.....
m8815010
版主


發表:99
回覆:372
積分:289
註冊:2003-11-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-01-17 13:59:19 IP:61.63.xxx.xxx 未訂閱
引言: 哇~~< > 真的可以耶,好厲害< > 當時討論相關問題時,小弟也有研究WM_KILLFOCUS和WM_SETFOCUS這二個 message,但是無論如何做不出這種效果... 太感謝m8815010大大了,這個範例程式碼小弟不客氣收下囉 感謝您~~ 程式迷人之處,在於邏輯思考,然而卻也是惱人之處~~ 哈哈,>< face="Verdana, Arial, Helvetica">
m8815010
版主


發表:99
回覆:372
積分:289
註冊:2003-11-13

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-01-17 15:43:59 IP:61.63.xxx.xxx 未訂閱
引言: YuHeng兄你好,你說的沒錯,RichEdit1並沒有游標出來,正如我在*注意事項* 中特別強調的: *5. 上述OS沒有被騙的結果就是RichEdit在setfocus時是沒有游標的。 正因為OS沒有被騙,所以OS它default只容許一個AP有一個游標,故當Memo1 有游標時,RichEdit1是沒有的。下面再稍做細部說明: 首先,YuHeng兄你後來說的方法,下列例子可能可以參考,不知你有沒有試過:
//-----------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if (!CreateCaret(Memo1->Handle,NULL,0,19)) {
     ShowMessage("Fail!");
     return;
 }
 if (!ShowCaret(Memo1->Handle))
     ShowMessage("Showing Fail!");
}
//-----------------------------------------------------------
void __fastcall TForm1::RichEdit1Enter(TObject *Sender)
{
 if (!CreateCaret(Memo1->Handle,NULL,0,19)) {
     ShowMessage("Fail!");
     return;
 }
 ShowCaret(Memo1->Handle);
 Sleep(2000);<----可看出游標確實有設給Memo1,只是又跳回給RichEdit1了!
}
//------------------------------------------------------------
如同你說的,在focus被切為其它子元件時,先做一個游標給Memo1,再讓 它show出,這個在focus切到Button1中是可行的(下圖中focus為Button1, Memo1的游標仍在),但在focus切到RichEdit1時,仍是只有RichEdit1有游標! 圖例: 這是因為當focus切為Button1時,這個Window(Application)依照我們的程式碼 create一個游標給Memo1,而因為Buuton1(focus況態中)並沒有需要用游標,所 以OS並不需要搶回這個游標給Button1(應該是說先把Memo1的destroy,再建一個新的給Button1),而RichEdit1則反之。故仍不行成功! 下面的圖例是Win API的說明,但最重要的是說明OS對游標的Default管理原則! 講了這麼多,遶了一圈,我仍覺得還是老話一句:既然OS只允許一個視窗有一個游標(for default),那麼今天你要讓多個子元件都有游標,那就要騙它,也就是作system hook什麼之類的動作了。 哈哈,那為什麼我沒有做出來呢?因為我也沒實作過(今天還要上班勒!),所以>< face="Verdana, Arial, Helvetica">
YuHeng
一般會員


發表:8
回覆:13
積分:4
註冊:2003-02-26

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-01-19 15:20:41 IP:61.56.xxx.xxx 未訂閱
這幾天想了一個方法可以達到我的需求, 我需求主要是要讓user在編輯時,如再使用其他元件時, 可以知道自己在TMemo內所在的位置, 因此開始時會想要有兩個Caret,可是受到系統限制,此功能要達成, 可能非我能力所及,因此又重新思考一下.... 如果我不是focus在TMemo時能在caret所在的文字標示'|'或畫個底線, 應該就能達成我的需求.... 可是TMemo又沒又Canvas物件,如要加上Canvas物件,工程可能太浩大... 找了版上相關的討論,看到有人推薦TSynEdit,研究了一下,可以達成我的需求... 目前我使用的方法如下:    //--------------------------------------------------------------------------- #include  #include #pragma hdrstop #include "mMemoFocus.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "CSPIN" #pragma link "SynEdit" #pragma resource "*.dfm" struct { bool Showed; int X,Y,Len; } myCaret; void ShowMyCaret(TSynEdit *EDIT); void HideMyCaret(TSynEdit *EDIT); TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::SynEdit1Exit(TObject *Sender) { ShowMyCaret(SynEdit1); } //--------------------------------------------------------------------------- void __fastcall TForm1::SynEdit1Enter(TObject *Sender) { HideMyCaret(SynEdit1); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { myCaret.Showed = false; } //--------------------------------------------------------------------------- void ShowMyCaret(TSynEdit *EDIT) { if(myCaret.Showed) { HideMyCaret(EDIT); } myCaret.Showed = true; myCaret.X = EDIT->CaretXPix(); myCaret.Y = EDIT->CaretYPix() + EDIT->Canvas->TextHeight("H") + 2; myCaret.Len = EDIT->CharWidth; // save canvas pen info TPenMode tmpPenMode = EDIT->Canvas->Pen->Mode; TPenStyle tmpPenStyle = EDIT->Canvas->Pen->Style; int tmpWidth = EDIT->Canvas->Pen->Width; // set canvas pen EDIT->Canvas->Pen->Mode = pmNot; EDIT->Canvas->Pen->Style = psSolid; EDIT->Canvas->Pen->Width = 2; // draw my caret EDIT->Canvas->MoveTo(myCaret.X,myCaret.Y); EDIT->Canvas->LineTo(myCaret.X+myCaret.Len,myCaret.Y); // restore canvas pen info EDIT->Canvas->Pen->Mode = tmpPenMode; EDIT->Canvas->Pen->Style = tmpPenStyle; EDIT->Canvas->Pen->Width = tmpWidth; } void HideMyCaret(TSynEdit *EDIT) { if(myCaret.Showed) { myCaret.Showed = false; // save canvas pen info TPenMode tmpPenMode = EDIT->Canvas->Pen->Mode; TPenStyle tmpPenStyle = EDIT->Canvas->Pen->Style; int tmpWidth = EDIT->Canvas->Pen->Width; // set canvas pen EDIT->Canvas->Pen->Mode = pmNot; EDIT->Canvas->Pen->Style = psSolid; EDIT->Canvas->Pen->Width = 2; // draw my caret EDIT->Canvas->MoveTo(myCaret.X,myCaret.Y); EDIT->Canvas->LineTo(myCaret.X+myCaret.Len,myCaret.Y); // restore canvas pen info EDIT->Canvas->Pen->Mode = tmpPenMode; EDIT->Canvas->Pen->Style = tmpPenStyle; EDIT->Canvas->Pen->Width = tmpWidth; } } 執行結果
YuHeng
一般會員


發表:8
回覆:13
積分:4
註冊:2003-02-26

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-01-19 15:25:50 IP:61.56.xxx.xxx 未訂閱
感謝ENIX007 & m8815010在這個問題給予相當多的協助.... 因m兄給了較多的思考方向,因此將此問題給分給了m兄...
系統時間:2024-06-27 0:24:21
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!