TListView元件裡OnEdited相關問題 |
尚未結案
|
隆妹
一般會員 ![]() ![]() 發表:6 回覆:12 積分:8 註冊:2003-10-02 發送簡訊給我 |
|
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
隆妹你好:
你的問題乍看很簡單,但是實作後發現還真的
有你說的問題,且滿有趣的,值得思索原委。
不幸的,目前我只能用替代方案可以解決你所
要的功能要求,並對於這個問題做一些初步的分析
,希望有興趣的人可以繼續想下去。
-------------------問題所在-----------------------
*我想你的問題可能是這樣子產成的,那如果不是的話也就
可以不必再看下去了。 根據描述,你是要在使用者input任一個ListView Item的
caption之後,判斷這個caption是否是重覆或是為空字串
。所以我想你的判斷碼應該寫在這個事件下:
void __fastcall TForm1::ListView1Edited
(TObject *Sender, TListItem *Item, AnsiString &S)
{
if (S是重覆或空的字串)
Item->EditCaption();
}
但是Item->EditCaption()這一行卻無法使它順利回到edit的
狀態,對吧!
-------------------問題所在----------------------- -------------------問題分析-----------------------
首先測試Item->EditCaption()是否可以正常運作,假設放
在一個button click事件內發現可以正常運作,可以回到
edit狀態。ex:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
//一般寫法
if (!ListView1->Items->Item[0]->EditCaption())
ShowMessage("無法回到edit狀態!");
//SDK寫法
ListView1->SetFocus();
if (!SendMessage(ListView1->Handle,LVM_EDITLABEL,0,0))
ShowMessage("無法回到edit狀態!");
}
但是,在原本事件中卻是不work的,不論那一種寫法都是return
false的。ex:
void __fastcall TForm1::ListView1Edited
(TObject *Sender, TListItem *Item, AnsiString &S)
{
if (!ListView1->Items->Item[0]->EditCaption())
ShowMessage("無法回到edit狀態!");
ListView1->SetFocus();
if (!SendMessage(ListView1->Handle,LVM_EDITLABEL,0,0))
ShowMessage("無法回到edit狀態!");
}
所以證明Item->EditCaption()這一行在直接加入又不動手腳的
情況下是無法work的。 在BCB中void __fastcall TForm1::ListView1Editing事件觸發時
會有產生一個edit control,然後Item進入可編輯模式,當
void __fastcall TForm1::ListView1Edited觸發時,表示編輯完
畢,而當void __fastcall TForm1::ListView1Edited事件結束時
,這個edit control會被取消,表示編輯完畢,也就是說在
void __fastcall TForm1::ListView1Edited事件中雖然有
Item->EditCaption()這樣的程式碼將Item設為可編輯模式,但是當
整個事件結束後,由於edit control被取消,導至Item自動恢復不
可編輯模式。 由於void __fastcall TForm1::ListView1Editing事件
由LVN_BEGINLABELEDIT觸發
void __fastcall TForm1::ListView1Edited事件
由LVN_ENDLABELEDIT觸發(應該是如此)
所以也可以試著去攔截ListView所在的Form之LVN_ENDLABELEDIT
訊息(注意它是包在WM_NOTIFY訊息內的)去試著將Item改為可編
輯模式,結果也是不行的(範例過多,不在此列出)。 -------------------問題分析----------------------- -------------------替代方案-----------------------
* 注意void __fastcall TForm1::ListView1Edited事件的
特性是有"新編輯"且完成後觸發
#include
|
隆妹
一般會員 ![]() ![]() 發表:6 回覆:12 積分:8 註冊:2003-10-02 發送簡訊給我 |
|
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
引言: 隆妹你好: 過了一個年都忘了這一個題目了!發現之前回覆的那一篇寫的沒條理,而 且程式碼又沒排列整齊,所以應該很難看的懂! 問題一:觀念還是同前篇回覆的! 就是在ListView1Edited()事件結束後,這個edit control(上篇中提到) 會被自動消除,而這個item也會恢復不可編輯模式(目前研究是這樣,可 能並不盡然)。所以如果有下列的程式碼:void __fastcall TForm1::ListView1Edited(TObject*Sender,TListItem *Item, AnsiString &S) { //其它程式碼 ListView1->Items->Item[0]->EditCaption(); //其它程式碼 }則當中的那一行是無用的,因為雖然有開啟編輯模式,但是事件結束後還 是被自動恢復不可編輯模式!做了等於白做。 所以就用一個做假的方法,就是一樣在ListView1Edited()事件中做item 輸入是否合理的判斷,只要不合理,就結束ListView1Edited()事件,並 開啟Timer1事件(用程式碼Timer1->Enabled=true),而Timer1事件中 就會將item再設為可編輯模式。目的完全就是為了要跳過〝被自動恢復不 可編輯模式〞這一段。 結論是只要在ListView1Edited()事件結束後再將item再設為可編輯模式 即可成功! 問題二: 你可以不用Timer去做,只要能實做上述論述的方法都行。有時 Timer感覺是一個簡單的Thread。 另外如果覺得Timer太慢,就可如你所說的把1000調成500,或是調成更 小10等等…感覺沒有由1秒變0.5秒應該是錯覺吧,要不然你調成5000試 試看,絕對讓你等5秒 |
aquarius
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:347 積分:330 註冊:2003-05-21 發送簡訊給我 |
用 TIMER 感覺沒那麼聰明, 試試用 MESSAGE 的方式, 我用 DELPHI 寫了一個範例, 希望你看得懂... ;)
unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls; type TForm1 = class(TForm) ListView1: TListView; procedure ListView1Edited(Sender: TObject; Item: TListItem; var S: String); private { Private declarations } procedure WMU(var msg:TMessage) ; message WM_USER; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.ListView1Edited(Sender: TObject; Item: TListItem; var S: String); begin if s='' then begin PostMessage(handle,WM_USER,0,0) ; abort ; end ; end; procedure TForm1.WMU(var msg: TMessage); begin ListView1.Selected.EditCaption ; end; end....Aquarius
------
水瓶男的blog: http://791909.blogspot.com |
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
引言: 用 TIMER 感覺沒那麼聰明, 試試用 MESSAGE 的方式, 我用 DELPHI 寫了一個範例, 希望你看得懂... ;) ...etc.aquarius兄你好: 看了你的範例,不是很了解delphi的語法,大致拿捏一下,寫成BCB的範例,如下: In Unit1.h ~~ class TForm1 : public TForm { ~~ void __fastcall FormHookWindowProc(TMessage &Message); TWndMethod FormParentWindowProc; ~~ In Unit1.cpp //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { FormParentWindowProc=Form1->WindowProc; Form1->WindowProc=FormHookWindowProc; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormHookWindowProc(TMessage &Message) { if (Message.Msg==WM_USER 123) { ListView1->Selected->EditCaption(); <-----行一 } FormParentWindowProc(Message); } //--------------------------------------------------------------------------- void __fastcall TForm1::ListView1Edited(TObject *Sender, TListItem *Item, AnsiString &S) { if (S=="") { PostMessage(Handle,WM_USER 123,0,0); return; <-----行二 } } //---------------------------------------------------------------------------結果是可行的,有達到問題的效果 |
aquarius
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:347 積分:330 註冊:2003-05-21 發送簡訊給我 |
請參考 PostMessage 的說明 The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window and then returns without waiting for the thread to process the message. Messages in a message queue are retrieved by calls to the GetMessage or PeekMessage function. PostMessage 之後並不會馬上被執行, 而是放到 Message Queue 中. 除非你在 OnEdited 中呼叫 Application-> ProcessMessages ; 否則在這個副程式中並不會去處理 Message Queue 的內容, 也就是說可以保證那個 Message 一定會在 OnEdited 之後才被執行. 當然你若是在 OnEdited 中叫用 ProcessMessages 那就另當別論. ...Aquarius
------
水瓶男的blog: http://791909.blogspot.com |
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
引言: The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window and then returns without waiting for the thread to process the message. Messages in a message queue are retrieved by calls to the GetMessage or PeekMessage function. PostMessage 之後並不會馬上被執行, 而是放到 Message Queue 中. 除非你在 OnEdited 中呼叫 Application-> ProcessMessages ; 否則在這個副程式中並不會去處理 Message Queue 的內容, 也就是說可以保證那個 Message 一定會在 OnEdited 之後才被執行.Aquarius兄你好 |
aquarius
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:347 積分:330 註冊:2003-05-21 發送簡訊給我 |
詳情請自行參考 Windows SDK programming.
關於 Message 的部份. 至於簡單的說明---
在沒有呼叫 GetMessage 或 PeekMessage , 系統並不會自動去處理 Message Queue 的內容. 什麼時候會處理呼叫到這兩個 FUNCTION 呢? 一是在呼叫 Application->ProcessMessages, 一是在系統 Idle 時(這種說法不大對, 但我一時想不到更好的表達方法). 所以只要在你的 Event 中沒叫用到會呼叫到會去用到處理Message的function, 就可以保證 Message Queue 中的內容不會被存取. 更簡單的說法就是, 你 PostMessage 完, 就跳出 Event 了, 當然不會有被插隊的可能. ...Aquarius
------
水瓶男的blog: http://791909.blogspot.com |
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
引言: 在沒有呼叫 GetMessage 或 PeekMessage , 系統並不會自動去處理 Message Queue 的內容. 什麼時候會處理呼叫到這兩個 FUNCTION 呢? 一是在呼叫 Application->ProcessMessages, 一是在系統 Idle 時(這種說法不大對, 但我一時想不到更好的表達方法). 所以只要在你的 Event 中沒叫用到會呼叫到會去用到處理Message的function, 就可以保證 Message Queue 中的內容不會被存取. 更簡單的說法就是, 你 PostMessage 完, 就跳出 Event 了, 當然不會有被插隊的可能.是啊是啊!aquarius兄你說到重點了,我就是要問這個答案〝一是在系統 Idle 時〞(雖然可能不是你最好的表達)。因為我們在Post出Message後並沒有手動從queue中取出執行,而這個Message最後還是被執行了,所以顯然OS有幫我們做這件事了,那OS什麼時候做就成了關鍵了。 因為之前我不認為OS是在Idle時做了這件事(Because it doesn't show in API reference),所以我覺得下列是可能的: //--------------------------------------------------------------------------- void __fastcall TForm1::ListView1Edited(TObject *Sender, TListItem *Item, AnsiString &S) { if (S=="") { PostMessage(Handle,WM_USER 123,0,0); <-------OS剛好在這time slice執行了queue內我們的那個Message return; } } //---------------------------------------------------------------------------那如果如你所說的OS在Idle時做這件事,那麼當然是在這個ListView1Edited事件後才有可能執行我們的Message了(by Def. of "Idle" of BCB:An application is idle when it is not processing code.) 嗯,快要結案了…可惜我不能結案< >< >< >< >< >< > |
aquarius
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:347 積分:330 註冊:2003-05-21 發送簡訊給我 |
請參考 TListView 的 SOURCE CODE. OnEdited 是在 LVN_ENDLABELEDIT 中被呼叫到, 這時的 Edit Mode 應該還沒被結束. 而 EditCaption 則是送一個訊息到 TListView 中. 表示轉換為 Edit 模式. 但在 OnEdited 時, 本來就還在 Edit 模式, 所以這個動作自動被略過. 使用 Timer 或 Message 去叫用 EditCaption 的目的就是要讓 TListView 先結束 Edit Mode, 然後再收到 EditCaption 時, 再重新將狀態設為 Edit Mode. ...Aquarius
------
水瓶男的blog: http://791909.blogspot.com |
隆妹
一般會員 ![]() ![]() 發表:6 回覆:12 積分:8 註冊:2003-10-02 發送簡訊給我 |
|
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
引言:請問 WM_USER 是不是不一定要加 123 呢? 而只要在 WM_USER through 0x7FFF 就可以? 真沒想到過完年回應那麼多 不過 aquarius 所提供的方法還不是很懂 看來得加油了 |
aquarius
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:347 積分:330 註冊:2003-05-21 發送簡訊給我 |
|
隆妹
一般會員 ![]() ![]() 發表:6 回覆:12 積分:8 註冊:2003-10-02 發送簡訊給我 |
|
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
引言: 謝謝2位的說明 PostMessage 之類的function 大致上以了解 但了好幾次的回覆 原來只要一行就可以了嗯,就是程式中內定對Message(all Messages of the Form)的處理function,前幾行是我們自已加上對這Messasge的additional處理程式碼,但最後還是要切回做一遍它本來該做的。 最簡單的測試,把這行那掉試試就知道有什麼問題了 |
aquarius
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:347 積分:330 註冊:2003-05-21 發送簡訊給我 |
|
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
引言: 這種問題就是去看看他的 Source Code 是怎麼寫的囉!! 換成這一行就可以了. SendMessage(TreeView1->Items->Item[0]->Handle,TVM_EDITLABEL,0,(LPARAM)TreeView1->Items->Item[0]->itemid); ...Aquarius耶,帥哦…可惡,被唬爛了,真是噁心< >< > |
隆妹
一般會員 ![]() ![]() 發表:6 回覆:12 積分:8 註冊:2003-10-02 發送簡訊給我 |
|
yangshengfa
一般會員 ![]() ![]() 發表:1 回覆:16 積分:3 註冊:2003-09-06 發送簡訊給我 |
|
aquarius
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:347 積分:330 註冊:2003-05-21 發送簡訊給我 |
|
m8815010
版主 ![]() ![]() ![]() ![]() ![]() 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
|
yl_huang
一般會員 ![]() ![]() 發表:6 回覆:6 積分:2 註冊:2004-11-24 發送簡訊給我 |
下列引言中, "行一" 一定比 "行二" 慢被執行的原因是否為:
ListView1Edited() 與 FormHookWindowProc() 皆被同一 thread 所執行, 也就是說,
thread A 呼叫 ListView1Edited() PostMessage() (給自己),
再於 FormHookWindowProc() 中處理此 Message.
引言://--------------------------------------------------------------------------- void __fastcall TForm1::FormHookWindowProc(TMessage &Message) { if (Message.Msg==WM_USER 123) { ListView1->Selected->EditCaption(); <-----行一 } FormParentWindowProc(Message); } //--------------------------------------------------------------------------- void __fastcall TForm1::ListView1Edited(TObject *Sender, TListItem *Item, AnsiString &S) { if (S=="") { PostMessage(Handle,WM_USER 123,0,0); return; <-----行二 } } //--------------------------------------------------------------------------- |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |