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

ComBoBox動態清單

答題得分者是:herbert2
superrakce
一般會員


發表:23
回覆:35
積分:11
註冊:2006-10-09

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-05-30 09:41:14 IP:114.33.xxx.xxx 訂閱
我想作的功能是,使用者輸入文字後,會去資料庫搜尋類似的記錄,填到combobox 的選項裡,以供選擇,加快資料輸入的效率
但是每載入完一次清單,游標就會跑到text 的最前面,造成每次輸入都要將游標移到最後面
經測試是ComboBox1.Items.Clear;影響
有什麼解決方案嗎?
[code delphi]
procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char);
var j:integer;
// i 為全域變數
ComboBox1.Items.Clear;
for j:=i to i 5 do
ComboBox1.Items.Add(inttostr(j));
i:=i 5;
ComboBox1.DroppedDown := true;

end;
[/code]
原來只有這行就可以解決
ComboBox1.SelStart := length(combobox1.Text);
編輯記錄
superrakce 重新編輯於 2011-05-29 19:50:06, 註解 無‧
superrakce 重新編輯於 2011-05-29 20:01:57, 註解 無‧
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-05-31 19:23:35 IP:220.128.xxx.xxx 未訂閱
Hello, 我不建議這樣做,因為每按一個鍵去讀資料庫一次,會是惡夢一場。
正確的做法是,改用 TEDit 或 TDBEdit,輸入文字後之後,按 Function Key(例如 F4,F5,F8,F9),或滑鼠點兩下,跳出一個查詢視窗,排序好,並用 Locate() 自動指符合的第一筆,開頭文字相同的會排在一起,按確定,或按兩下 DBGrid 就送回。
===================引 用 superrakce 文 章===================
我想作的功能是,使用者輸入文字後,會去資料庫搜尋類似的記錄,填到combobox 的選項裡,以供選擇,加快資料輸入的效率
但是每載入完一次清單,游標就會跑到text 的最前面,造成每次輸入都要將游標移到最後面
經測試是ComboBox1.Items.Clear;影響
有什麼解決方案嗎?
[code delphi]
procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char);
var j:integer;
// i 為全域變數
ComboBox1.Items.Clear;
for j:=i to i 5 do
ComboBox1.Items.Add(inttostr(j));
i:=i 5;
ComboBox1.DroppedDown := true;

end;
[/code]
原來只有這行就可以解決
ComboBox1.SelStart := length(combobox1.Text);
herbert2
尊榮會員


發表:58
回覆:632
積分:878
註冊:2004-04-16

發送簡訊給我
#3 引用回覆 回覆 發表時間:2011-06-01 09:18:29 IP:202.39.xxx.xxx 訂閱
這是我的解決方法(仿 DOS 時代的流程) ,供您參考。

編輯記錄
herbert2 重新編輯於 2011-05-31 19:20:59, 註解 無‧
herbert2 重新編輯於 2011-05-31 19:22:39, 註解 無‧
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#4 引用回覆 回覆 發表時間:2011-06-01 11:49:03 IP:220.128.xxx.xxx 未訂閱
我說的,就是 Hertbert2 大大的做法,是業界標準做法,可見 Hertbert2 在這一行也待久了。
編輯記錄
cancer 重新編輯於 2011-05-31 21:49:44, 註解 無‧
Victor4022
中階會員


發表:0
回覆:76
積分:90
註冊:2011-02-20

發送簡訊給我
#5 引用回覆 回覆 發表時間:2011-06-02 23:12:44 IP:122.126.xxx.xxx 訂閱
您好, 如果資料量是維持最新/ 或常用 n 筆 (例如 10 筆), 也可以用下面方法:

1. 將 ComboBox.Style := csSimple;
2. 初始化時, 將 top n 筆資料放入 ComboBox1.Items
3. 由於 Style 已設成 csSimple, 試打幾個字看看, 比對上的會自動帶入
4. 視您的需求, 將使用者目前輸入的資料
4.1 如果資料不存在, Insert 至第 1 筆
4.2 如果資料存在, 則不異動資料庫

當然, 不一定要限用最新 n 筆情形, 您可以任意變化資料內容的新舊順序,
我的使用經驗通常只保留"最後被使用的 top 10"

superrakce
一般會員


發表:23
回覆:35
積分:11
註冊:2006-10-09

發送簡訊給我
#6 引用回覆 回覆 發表時間:2011-06-03 10:30:11 IP:114.33.xxx.xxx 訂閱
「最後被使用的 top 10]」  <-這東西是記錄在資料庫裡嗎?(新增一個資料表記專門記錄這東西)
還是其它方法?
短短一行幾個字,感覺很奧妙

===================引 用 Victor4022 文 章===================
您好, 如果資料量是維持最新/ 或常用n 筆 (例如 10 筆), 也可以用下面方法:

1. 將 ComboBox.Style := csSimple;
2. 初始化時, 將 top n 筆資料放入 ComboBox1.Items
3. 由於 Style 已設成 csSimple, 試打幾個字看看, 比對上的會自動帶入
4. 視您的需求, 將使用者目前輸入的資料
4.1 如果資料不存在, Insert 至第 1 筆
4.2 如果資料存在,則不異動資料庫

當然, 不一定要限用最新 n 筆情形, 您可以任意變化資料內容的新舊順序,
我的使用經驗通常只保留"最後被使用的 top 10"

Victor4022
中階會員


發表:0
回覆:76
積分:90
註冊:2011-02-20

發送簡訊給我
#7 引用回覆 回覆 發表時間:2011-06-08 22:26:15 IP:122.126.xxx.xxx 訂閱
抱歉,小弟未說明清楚!
這邊指的是任意的常用資料,例如:

假設某公司使用的帳號系統(ex: Windows AD)內含有5000 個 account 與 5000 個 group 分散在 5000個 OU內,
這種大 site 類型的 AD Tree 展開會很驚人, MIS 想在 AD Tree 裡面尋找指定的account 可能會非常費時,
此時,如果我們提供的 Application 有提供"搜尋使用者"功能,就可以進行底下的設計:

設計A. 每次進入搜尋使用者對話框時,自動載入前次最新查詢 10 次的使用者關鍵字清單。
設計B. 每次離開該對話框時,將本次搜尋的關鍵字加入清單,並將清單儲存起來。

記錄的方式不外乎:
1. 寫入資料庫
2. 本地端寫入至 .ini內或自訂的檔案格式內(例如 %temp%\search_history.ini)

在設計A 與 設計B 的查詢對話框場景,就適合放入 ComboBox 讓使用者 keyin 或挑選(例如最多 10 筆)。

雖然上述假設資料庫內已知有 5000 筆使用者帳號,
但如果您想要,也可以將其加入 ComboBox 內,如果考量處理效能,
不確定您是透過何種 VCL 進行資料庫存取,小弟習慣是使用 TADOQuery,
小弟的使用經驗是不要直接使用 TADOQuery.FieldByName(field name).AsXXX 之類的方式從 TADOQuery 讀出資料,
會建議使用 TADOQuery.Recordest 進行資料操作,7萬筆的資料處理速度是 12 秒 vs 0.5秒的差距。

小弟工作上開發的產品,使用者通常是管理者/MIS 或文管人員,一般企業組織內部使用產品的人也佔少數,
在沒效能瓶頸與 Database engine throughput 壓力下,通常一次載入數百筆或數千筆資料到 ComboBox 並不算奢侈,
除非您的產品是兩岸三地用有頻寬考量。

希望這麼解說有比較清楚,但可能也不適合您的需求,僅供您參考:)




===================引 用 superrakce 文 章===================
「最後被使用的 top 10]」 <-這東西是記錄在資料庫裡嗎?(新增一個資料表記專門記錄這東西)
還是其它方法?
短短一行幾個字,感覺很奧妙

cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#8 引用回覆 回覆 發表時間:2011-06-16 09:11:08 IP:220.128.xxx.xxx 未訂閱
Victor 大,請教一下,不直接用 FieldByName(...).As..,改用 RecordSet 的話,效率的提昇是指資料讀取還是迴圈處理?看起來應該不是資料讀取,迴圈處理的速度提昇比較有可能。用 RecordSet 怎麼取出特定欄位內容?
一直都有一個未解問題,客戶要求在 DBGrid 打資料時,離開某個欄位 OnCellExit 後,馬上要檢查有沒有重複輸入相同的內容,有的話要馬上 ShowMessage() 提示,例如打到第十筆,OnCellExit 中用迴圈,從第一筆開始比對到第九筆,看有沒有跟第十筆有重複內容,因為 DataSet 還沒有存至資料庫,不能用 select 指令來檢查,這個時候只能 DataSet.DisableControls, 迴圈檢查,DataSet.EnableControls,但我覺得打字的過程中移動 DataSet 的 Record 指標不是一種好的寫作方式,如果能有另一種內部迴圈處理可以不用動到 Record 指標,那是最好不過的,而速度一定會比較快。
Victor4022
中階會員


發表:0
回覆:76
積分:90
註冊:2011-02-20

發送簡訊給我
#9 引用回覆 回覆 發表時間:2011-06-17 07:31:24 IP:122.126.xxx.xxx 訂閱
您好:)

其實操作 RecordSet 跟操作 TADOxxx.FieldByName一樣, VCL 實作中最後也是呼叫 OLE COM 裡面的 interface,
雖然 FieldByName(...) As... 雖然方便使用, 但是資料量一大, 欄位數一多, 效能就變的比較糟糕,
因為 FieldByName 至少要以下動作:
1. 將輸入的 Field Name 從所有 TFields 中由第一筆找出最後一筆 -> 假設我們的 T-SQL query 出來 100 個欄位, 使用 FieldByName(...) As... 的欄位剛好又是第100筆的話, DataSet 假設有1000筆資料, 那麼這段 FieldByName(最後一個欄位).As.... 會被執行 1000 * 100次.

2. FieldByName(...) As... 是操作 OleVariant 進行轉型, 同樣以上為例, 1000 筆資料就轉型 1000 次(視資料型別而定) .

由於 T-SQL query 能經由設計師控制, 回傳資料型別也能自己控制, 所以後期手上維護的產品, 大概都是秉持這方向 (操作 RecordSet, 自己將 Variant 轉型適當資料並取出使用), 效能比使用 VCL 封裝好的存取方式快很多

不過, 您提到的DBGrid.OnCellExit 要檢查當前 DataSet 有無重覆, 小弟想到2作法:
1. 如您所說的, 先DisableControls 再迴圈檢查 -> 此處目前已知的有2種處理方式, FieldByName(..) As... 或直接操作 Recordest
2. 使用一 TStringList, 設定 Sorted 為 True, 每當DBGrid.OnCellExit 就先使用 TStringList.Find 進行 Binary search, 若:
a. 使用者輸入資料不在 TStringList 內則將該字串 Add 進去(此時由於 Sorted property 為 True 會自動排序)
b. 存在則 ShowMessage();

最後, 小弟不知道是否有內部迴圈可以處理您的問題, 但是如果資料未 commit 又想檢查 DataSet 內的資料, 可以考慮上面作法之外, 另外一個就是一次存取 2個 DataSet, 一個是與 DBGrid 連結用, 另一個專門檢查用, 這樣就不用管 DBGrid 目前使用者操作狀態, 也不用檢查完後再跳回使用者輸入的該筆位置. 副作用是浪費一塊記憶體 :P

希望對您有幫忙:)

===================引 用 cancer 文 章===================
Victor 大,請教一下,不直接用 FieldByName(...).As..,改用 RecordSet 的話,效率的提昇是指資料讀取還是迴圈處理?看起來應該不是資料讀取,迴圈處理的速度提昇比較有可能。用 RecordSet 怎麼取出特定欄位內容?
一直都有一個未解問題,客戶要求在 DBGrid 打資料時,離開某個欄位 OnCellExit 後,馬上要檢查有沒有重複輸入相同的內容,有的話要馬上 ShowMessage() 提示,例如打到第十筆,OnCellExit 中用迴圈,從第一筆開始比對到第九筆,看有沒有跟第十筆有重複內容,因為 DataSet 還沒有存至資料庫,不能用 select 指令來檢查,這個時候只能 DataSet.DisableControls, 迴圈檢查,DataSet.EnableControls,但我覺得打字的過程中移動 DataSet 的 Record 指標不是一種好的寫作方式,如果能有另一種內部迴圈處理可以不用動到 Record 指標,那是最好不過的,而速度一定會比較快。
系統時間:2017-12-16 17:21:59
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!