最近為了某些事,自己動手做了簡單的 GUI, 我以前從來沒有碰過 MFC 的,學生時候也只用 BCB 拉過簡單的 GUI。由於以前沒碰過,所以連些最簡單的小東西我也可能不知道藏在哪邊,自己找不到時就要問 GUI team 的同事。
不過現在碰到一個小問題,很基本的小問題,竟然問了半天都沒有好的答案。我只是要在 multi line 的 CEdit 後面加一行字串,不論是 google 還是問人,都只能得到爛爛的方法,沒辦法像 CListBox 或 BCB 的 TMemo 一樣,用一個 AddString( ) 就解決,所幸最後還是找到了堪用的解法(不想看過程的人請直接跳到最後面)。
那為何不用 CListBox? 因為 CListBox 不能選取/copy/paste。
第一版:
就是先 GetWindowText( ) 到 buffer中,把字串字自往 buffer 後面加上去,再 SetWindowText(buffer) 回去。真是爛到不行的點子,也是最多人提出的解決方案。我明明只是要加字串到尾端,竟然還要先讀出全部的舊字串再寫回,又麻煩又影響效率,還得考慮配置 buffer 的相關問題。
第二版:預先配置一個 buffer, 把要 append 的字串先加入 buffer, 再把整個 buffer 透過 SetWindowText( ) 寫入 CEdit。這個方法其實跟第一個方法一樣,換湯不換藥,只是把工作換個地方做而已,而且從軟體工程的角度來看,其實更糟,因為這個 buffer 必需配置在 function 以外的地方,可能是某個 global 變數或是某個 class member, 若要放在這個 Append function 中,就得做成 static,那在 multi thread 時又會出問題!
第三版:網路上找到的方法,我把它包成 function:
第四版:自己亂試試出來的
第五版:不會被游標干擾的版本
不過當使用者選取了某個範圍後,只要我一加新字串進去,他的選取範圍就會不見,這實在有點惱人,所以就有下一版的出現,這個改進還蠻理所當然的。
第六版:不會干擾游標的版本
CEdit 的 Append 改版到此暫時告一段落,不過若我發現還有改善空間還是會再改進的。
心得:MFC 果然是爛東西。
第二版:預先配置一個 buffer, 把要 append 的字串先加入 buffer, 再把整個 buffer 透過 SetWindowText( ) 寫入 CEdit。這個方法其實跟第一個方法一樣,換湯不換藥,只是把工作換個地方做而已,而且從軟體工程的角度來看,其實更糟,因為這個 buffer 必需配置在 function 以外的地方,可能是某個 global 變數或是某個 class member, 若要放在這個 Append function 中,就得做成 static,那在 multi thread 時又會出問題!
第三版:網路上找到的方法,我把它包成 function:
inline void AppendStringToEdit(const string &str, CEdit &edit)道理很簡單,就是先選取該 edit 中最後的部分,再將它取代,而這個被選取的部分其實是空的,因此造成 append 的效果。這雖然不太直接,但看來應該可行,可惜事與願違,它會把我要加的字串加在第一行的尾端,而非最後一行。
{
int length = edit.GetWindowTextLength();
edit.SetSel(length, length);
edit.ReplaceSel(str.c_str());
}
第四版:自己亂試試出來的
inline void AppendStringToEdit(const string &str, CEdit &edit)這個是第三版的改良版,會選取游標所在之處,而預設情況下,游標會在文字的最尾端,所以可以達到我想要的效果,這版終於做到我要的效果了!! 多數人應該到此就會打住了吧但我還是不滿意,因為只要使用者有動到游標(例如他想選取一部分 copy 起來),插入的位置就不在尾端,於是文字就亂掉了,因此有下一版的產生。
{
edit.SetSel(-1, -1);
edit.ReplaceSel(str.c_str());
}
第五版:不會被游標干擾的版本
inline void AppendStringToEdit(const string &str, CEdit &edit)這版會先取出最後一行( GetLineCount( ) -1 )所在的位置,然後選取該行的行末,再做取代工作,這樣就不會被使用者的游標給干擾了,太好了 :)
{
int nBegin = edit.LineIndex(edit.GetLineCount() - 1);
int nEnd = nBegin + edit.LineLength(nBegin);
edit.SetSel(nEnd, nEnd);
edit.ReplaceSel(str.c_str());
}
不過當使用者選取了某個範圍後,只要我一加新字串進去,他的選取範圍就會不見,這實在有點惱人,所以就有下一版的出現,這個改進還蠻理所當然的。
第六版:不會干擾游標的版本
inline void AppendStringToEdit(const string &str, CEdit &edit)這版只多做一件事,就是把原先的選取範圍存下來,做完上一版事情後,再把原先的選取範圍給選回去. 就是先 GetSel( ),做完事後再 SetSel( )。這樣看起來舒服、自然多了。
{
int nOrigBegin, nOrigEnd;
edit.GetSel(nOrigBegin, nOrigEnd);
int nBegin = edit.LineIndex(edit.GetLineCount() - 1);
int nEnd = nBegin + edit.LineLength(nBegin);
edit.SetSel(nEnd, nEnd);
edit.ReplaceSel(str.c_str());
edit.SetSel(nOrigBegin, nOrigEnd);
}
CEdit 的 Append 改版到此暫時告一段落,不過若我發現還有改善空間還是會再改進的。
心得:MFC 果然是爛東西。