如何讓 DBGrid 內的欄位在新增模式時可修改在編輯模式時變唯讀 |
尚未結案
|
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
因為資料有連動關連性被其他功能參考,例如採購單會被採購驗收入庫單參考
原本的寫法就是在採購單明細用 BeforEdit 來檢查已有驗收入庫就禁止編輯 不過因為使用者需要編輯沒有關連性的欄位,例如備註資料 所以要改成可編輯但將關連性欄位設為唯讀狀態的操作模式 表頭資料因為都是用 TDBEdit 的元件,所以在 DataSet 狀態變化實直接設定元件為 Read Only 就可以,程式如下 [code delphi] procedure TF6B040.dsMStateChange(Sender: TObject); begin //編輯模式料號不可異動 if dsM.DataSet.State = dsInsert then begin DBEditPart_num.Color := clWindow; DBEditPart_num.ReadOnly := False; end else begin DBEditPart_num.Color := clAqua; DBEditPart_num.ReadOnly := True; end; end; [/code] 但是明細是用 DBGrid 的就不確定如何處理了 請教各位站友有什麼好方法可分享的嗎?
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/ |
老大仔
尊榮會員 發表:78 回覆:837 積分:1088 註冊:2006-07-06 發送簡訊給我 |
|
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
看到您提議使用 Columns[0] 來處理
但是我想大家使用 DBGrid 都不會刻意鎖定欄位不可調整順序 因為使用者會調整欄位順序 所以我先用設定 Columns[0].color 來測試 如果使用者將別的欄位搬到第一欄就破功了 ===================引 用 老大仔 文 章=================== 不知道是否有誤解大大的意思 我猜想~是不是照本宣科就可以了呢? [code delphi] if dsDetail.State = 'dsInsert' then begin DBGrid.Columns[0].ReadOnly := True; end else if dsDetail.State = 'dsEdit' then begin DBGrid.Columns[0].ReadOnly := False; end; [/code]
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/ |
老大仔
尊榮會員 發表:78 回覆:837 積分:1088 註冊:2006-07-06 發送簡訊給我 |
那~
方法一: 將管控Enable的Code寫成一個Procedure 然後在 DataSource的StateChange事件 和 DBGrid的ColumnMoved事件中去呼叫那段Procedure 該Procedure大概長這樣 for i := 0 to DBGrid.Columns.Count - 1 do begin if DBGrid.Columns[i].FieldName = 'xxx' then DBGrid.Columns[i].ReadOnly := True else DBGrid.Columns[i].ReadOnly := False; end; 當然~詳細控制內容大大您需自行調整~ 方法二: 除了原先的管控外 直接在DBGrid的ColumnMoved事件中再增加如下: if Column.FieldName = 'xxx' then Column.ReadOnly := True else Column.ReadOnly := False; 不知以上方法是否能有效管控? ===================引 用 bestlong 文 章=================== 看到您提議使用 Columns[0] 來處理 但是我想大家使用 DBGrid 都不會刻意鎖定欄位不可調整順序 因為使用者會調整欄位順序 所以我先用設定 Columns[0].color 來測試 如果使用者將別的欄位搬到第一欄就破功了
編輯記錄
老大仔 重新編輯於 2013-07-11 12:23:54, 註解 無‧
|
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
目前在 StateChange 處理,程式碼如下:
[code delphi] procedure TF6B040.dsDStateChange(Sender: TObject); var i: Integer; begin //dsD is TDataSource if dsD.DataSet.State = dsInsert then begin for i := 0 to DBGrid.Columns.Count - 1 do begin if DBGrid.Columns[i].FieldName = 'Mkod_num' then DBGrid.Columns[i].ReadOnly := False; if DBGrid.Columns[i].FieldName = 'Part_num' then DBGrid.Columns[i].ReadOnly := False; end; end; if dsD.DataSet.State = dsEdit then begin for i := 0 to DBGrid.Columns.Count - 1 do begin if DBGrid.Columns[i].FieldName = 'Mkod_num' then DBGrid.Columns[i].ReadOnly := True; if DBGrid.Columns[i].FieldName = 'Part_num' then DBGrid.Columns[i].ReadOnly := True; end; end; end; [/code] 不過還是碰到一些麻煩就是 使用者會直接在 DBGrid 的欄位輸入資料 在沒有管控時就是直接進入編輯模式 而在有控管時 DBGrid 還是會先出現編輯輸入框,但該欄位已經被切換唯讀 此時的輸入框也沒有原本欄位內的資料 然後不管是有輸入資料或直接跳下一欄時都是出現 Field '工令編號' cannot be modified 的錯誤訊息 工令編號對應的就是欄位 Mkod_num 如果是點選編輯按鈕再進入要編輯欄位整個操作流程就太麻煩了,因為每一筆都要按 一整個不順又麻煩,絕對被使用者罵翻
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/
編輯記錄
bestlong 重新編輯於 2013-07-12 15:51:45, 註解 將程式碼內 dsM 改正為 dsD (連接明細資料表)‧
|
herbert2
尊榮會員 發表:58 回覆:640 積分:894 註冊:2004-04-16 發送簡訊給我 |
可否將 dsDetail 的 OnAfterInsert 與 OnAfterEdit 都指向 dsDetail.AfterEdit,
並於 dsDetail.AfterEdit 用迴圈檢視全部的 dsDetail.Fields, 當 dsDetail.Fields.Field[i].FieldName = 'Mkod_num' 時, 若 dsDetail.State = 'dsInsert' 則 dsDetail.Fields.Field[i].ReadOnly := False; 若 dsDetail.State = 'dsEdit' 則 dsDetail.Fields.Field[i].ReadOnly := True; 如此便不耽心 DBGrid.Coulmn[i] 被 User 移動的問題了. [code delphi] procedure TF6B040.dsMAfterEdit(Sender: TObject); var i: Integer; begin for i := 0 to dsM.FieldCount - 1 do begin if dsM.Fields.Field[i].FieldName = 'Mkod_num' then begin if dsM.DataSet.State = dsInsert then dsM.Fields.Field[i].ReadOnly := False; if dsM.DataSet.State = dsEdit then dsM.Fields.Field[i].ReadOnly := True; end; if dsM.Fields.Field[i].FieldName = 'Part_num' then begin if dsM.DataSet.State = dsInsert then dsM.Fields.Field[i].ReadOnly := False; if dsM.DataSet.State = dsEdit then dsM.Fields.Field[i].ReadOnly := True; end; end; end; [/code] |
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
關於使用者移動欄位的問題
將 DBGrid.Columns[i] 若是直接對 DataSet.Field[0] 設定也是要改成掃描全部欄位用 DataSet.Field[i] 這裡的 DataSet 可以是 TTable 或 TQuery 這樣就可解決移動欄位的問題,程式碼變多而且要小心欄位名稱與大小寫是否有對應到 使用者在 DBGrid 上都是用鍵盤方向鍵來移動焦點 需要修改時就會直接輸入新值 這時就會碰上出現編輯框但該欄位已被程式設定唯讀 所以送出編輯就會有錯誤 Field 'XXXX' cannot be modified 產生 這個狀況我在 DataSource 的 StateChange 事件內處理管制切換 或者是 TQuery or TTAble 的 BeforeInsert and BeforeEdit 事件內處理管制切換 都是一樣 所以我還無法確認要用什麼順序與事件時機才能不改變使用者的操作習慣 目前思考或許應該還需要 DBGrid.OnEnter 或 DataSource.OnDataChange 或 DataSet.AfterScroll 這幾個事件來配合 這個配方真希望能快點探索出來 不然就只能改變架構直接鎖住資料,另寫異動功能來處理了 ===================引 用 herbert2 文 章=================== 可否將 dsDetail 的 OnAfterInsert 與 OnAfterEdit 都指向 dsDetail.AfterEdit, 並於 dsDetail.AfterEdit 用迴圈檢視全部的 dsDetail.Fields, 當 dsDetail.Fields.Field[i].FieldName = 'Mkod_num' 時, 若 dsDetail.State = 'dsInsert' 則 dsDetail.Fields.Field[i].ReadOnly := False; 若 dsDetail.State = 'dsEdit' 則 dsDetail.Fields.Field[i].ReadOnly := True; 如此便不耽心 DBGrid.Coulmn[i] 被 User 移動的問題了. [code delphi] procedure TF6B040.dsMAfterEdit(Sender: TObject); var i: Integer; begin for i := 0 to dsM.FieldCount - 1 do begin if dsM.Fields.Field[i].FieldName = 'Mkod_num' then begin if dsM.DataSet.State = dsInsert then dsM.Fields.Field[i].ReadOnly := False; if dsM.DataSet.State = dsEdit then dsM.Fields.Field[i].ReadOnly := True; end; if dsM.Fields.Field[i].FieldName = 'Part_num' then begin if dsM.DataSet.State = dsInsert then dsM.Fields.Field[i].ReadOnly := False; if dsM.DataSet.State = dsEdit then dsM.Fields.Field[i].ReadOnly := True; end; end; end; [/code]
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/ |
老大仔
尊榮會員 發表:78 回覆:837 積分:1088 註冊:2006-07-06 發送簡訊給我 |
請問dsM是Dataset?還是DataSource?
是Master的?還是Detail的? ===================引 用 bestlong 文 章=================== 關於使用者移動欄位的問題 將 DBGrid.Columns[i] 若是直接對 DataSet.Field[0] 設定也是要改成掃描全部欄位用 DataSet.Field[i] 這裡的 DataSet 可以是 TTable 或 TQuery 這樣就可解決移動欄位的問題,程式碼變多而且要小心欄位名稱與大小寫是否有對應到 使用者在 DBGrid 上都是用鍵盤方向鍵來移動焦點 需要修改時就會直接輸入新值 這時就會碰上出現編輯框但該欄位已被程式設定唯讀 所以送出編輯就會有錯誤 Field 'XXXX' cannot be modified 產生 這個狀況我在 DataSource 的 StateChange 事件內處理管制切換 或者是 TQuery or TTAble 的 BeforeInsert and BeforeEdit 事件內處理管制切換 都是一樣 所以我還無法確認要用什麼順序與事件時機才能不改變使用者的操作習慣 目前思考或許應該還需要 DBGrid.OnEnter 或 DataSource.OnDataChange 或 DataSet.AfterScroll 這幾個事件來配合 這個配方真希望能快點探索出來 不然就只能改變架構直接鎖住資料,另寫異動功能來處理了
編輯記錄
老大仔 重新編輯於 2013-07-12 12:41:37, 註解 無‧
|
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
我有將回覆修正並補充了
發問那一篇的程式碼內 dsM 是 DataSource 元件連接 tbM (主檔) 是控管表頭的欄位,都是用 TDBEdit 元件來顯示資料 所以可以在主檔的 DataSource 元件直接控管 TDBEdit 元件的唯讀屬性 因為要新增或編輯都是要先按下按鈕後才能異動 明細檔是用 DBGrid 來顯示,雖然也有專用的增、刪、改按鈕 不過可以直接輸入就進入新增或編輯模式 這已經是使用者長年的操作習慣 所以明細檔的 DataSource 名稱是 dsD 整個元件關係如下: tbM > dsM > TDBEdit tbD > dsD > DBGrid ===================引 用 老大仔 文 章=================== 請問dsM是Dataset?還是DataSource? 是Master的?還是Detail的?
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/ |
老大仔
尊榮會員 發表:78 回覆:837 積分:1088 註冊:2006-07-06 發送簡訊給我 |
那假如照大大這麼說的話
是否能在進入新增/編輯模式時再加入一次的判斷呢? ===================引 用 bestlong 文 章=================== 我有將回覆修正並補充了 發問那一篇的程式碼內 dsM 是 DataSource 元件連接 tbM (主檔) 是控管表頭的欄位,都是用 TDBEdit 元件來顯示資料 所以可以在主檔的 DataSource 元件直接控管 TDBEdit 元件的唯讀屬性 因為要新增或編輯都是要先按下按鈕後才能異動 明細檔是用 DBGrid 來顯示,雖然也有專用的增、刪、改按鈕 不過可以直接輸入就進入新增或編輯模式 這已經是使用者長年的操作習慣 所以明細檔的 DataSource 名稱是 dsD 整個元件關係如下: tbM > dsM > TDBEdit tbD > dsD > DBGrid ===================引 用 老大仔 文 章=================== 請問dsM是Dataset?還是DataSource? 是Master的?還是Detail的? |
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
我了解您的想法
正如我前面在 #7 有提到 整個元件關係如下: tbM > dsM > TDBEdit tbD > dsD > DBGrid ===================引 用 老大仔 文 章=================== 請問dsM是Dataset?還是DataSource? 是Master的?還是Detail的?
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/ |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
因為站務大大問的是有沒有好方法, 而不是問如何在dbgrid 上解決輸人的問題, 所以就問的方式來說
這個問題, 其實我遇過太多了, 要在dbgrid 控制輸入, 的確不是一件容易的事, 而要如樓上各位樓主所言, 可能還在 after, before 之間打轉, 不免一個控制不好, 該 readonly 的, 結果可以modify, 或反過來, 這真的是吃力不討好, 所以我後來都不再用 dbgrid 來編輯, 雖然是很直覺化的操作, 但卻是最不人性的設計, 因此我寧可拿dbgrid 做read, 另外開 dbedit 來修正, 要不然用 dbctrl 元件加 dbedit 進行也是可以的, 如果是要問後者的方式, 我現在的做法, 都放棄dbgrid 的模式, 改用 stringgrid, 一樣可以達到 dbgrid 的效果, 而 stringgird 要好控制多了, 至於資料的回寫, 透過自己在底層寫控制回去資料庫就好了, 不用去考慮什麼 after, before 的問題 以上提供意見~~ ===================引 用 bestlong 文 章=================== 因為資料有連動關連性被其他功能參考,例如採購單會被採購驗收入庫單參考 原本的寫法就是在採購單明細用 BeforEdit 來檢查已有驗收入庫就禁止編輯 不過因為使用者需要編輯沒有關連性的欄位,例如備註資料 所以要改成可編輯但將關連性欄位設為唯讀狀態的操作模式 表頭資料因為都是用 TDBEdit 的元件,所以在 DataSet 狀態變化實直接設定元件為 Read Only 就可以,程式如下 [code delphi] procedure TF6B040.dsMStateChange(Sender: TObject); begin //編輯模式料號不可異動 if dsM.DataSet.State = dsInsert then begin DBEditPart_num.Color := clWindow; DBEditPart_num.ReadOnly := False; end else begin DBEditPart_num.Color := clAqua; DBEditPart_num.ReadOnly := True; end; end; [/code] 但是明細是用 DBGrid 的就不確定如何處理了 請教各位站友有什麼好方法可分享的嗎? |
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
我也推與pd一樣的做法!! 除非是研究,否則使用dbgrid要來複雜控制恐不是一件愉快且助益大的做法。
喔,我送出內容後才發現… 標題「 如何讓 DBGrid 內的欄位在新增模式時可修改在編輯模式時變唯讀」sorry,maybe我還是離題了… ===================引 用 P.D. 文 章=================== 如果是要問後者的方式, 我現在的做法, 都放棄dbgrid 的模式, 改用 stringgrid, 一樣可以達到 dbgrid 的效果, 而 stringgird 要好控制多了, 至於資料的回寫, 透過自己在底層寫控制回去資料庫就好了, 不用去考慮什麼 after, before 的問題 以上提供意見~~
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2013-07-21 01:33:24, 註解 sorry,maybe我還是離題了…‧
|
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
感謝大家參與討論
因為大環境的趨勢就是訂單少量多樣、製造分批 造成使用者新增與修改的操作量很大 為了持續增加防呆防錯的功能 以及試著尋找簡化使用者操作流程的方向 關於 DBGrid 與 DataSource 以及 DataSet 三個元件之間的事件糾葛,真的令人苦惱 而 P.D. 所言改用 StringGrid 來處理也給出一個不同的選擇方向 我試一下發現也是很考驗功力,樣樣要自己來喔 填滿資料 排序資料 增刪改查 欄位隱藏(外键與資料版本) 欄位搬移 顏色管理 匯入匯出
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/ |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
如果要用delphi標準stringgrid 真的會需要一點功力, 因為提供的事件太少了,
我現在都是用 tms , 所提到的功能幾乎都有開發出來了, 不妨考慮一下, 不過 tms 一旦掛進來, 程式byte會擴增一倍以上, 所以在意 k數大小, 不建議使用 ===================引 用 bestlong 文 章=================== 感謝大家參與討論 因為大環境的趨勢就是訂單少量多樣、製造分批 造成使用者新增與修改的操作量很大 為了持續增加防呆防錯的功能 以及試著尋找簡化使用者操作流程的方向 關於 DBGrid 與 DataSource 以及 DataSet 三個元件之間的事件糾葛,真的令人苦惱 而 P.D. 所言改用 StringGrid 來處理也給出一個不同的選擇方向 我試一下發現也是很考驗功力,樣樣要自己來喔 填滿資料 排序資料 增刪改查 欄位隱藏(外键與資料版本) 欄位搬移 顏色管理 匯入匯出 |
Mickey
版主 發表:77 回覆:1882 積分:1390 註冊:2002-12-11 發送簡訊給我 |
大家好 :
若是我, 會考慮 override TDBGrid 的 function CanEditAcceptKey(Key: Char): Boolean; override; function CanEditModify: Boolean; override; 但壞處是...必須改為 RunTime Create TxxDBGrid. 以下是屏蔽計算欄位的可編輯性, 參考: TxxDBGrid=class(TDBGrid) protected function CanEditAcceptKey(Key: Char): Boolean; override; function CanEditModify: Boolean; override; ..... end; implementation {TxxDBGrid} function TxxDBGrid.CanEditAcceptKey(Key: Char): Boolean; begin if Assigned(SelectedField) and (SelectedField.FieldKind in [fkCalculated, fkInternalCalc]) then Result := False else Result := inherited CanEditAcceptKey(Key); end; function TxxDBGrid.CanEditModify: Boolean; begin if Assigned(SelectedField) and (SelectedField.FieldKind in [fkCalculated, fkInternalCalc]) then Result := False else Result := inherited CanEditModify; end;
編輯記錄
Mickey 重新編輯於 2013-10-21 09:35:05, 註解 無‧
|
hagar
版主 發表:143 回覆:4056 積分:4445 註冊:2002-04-14 發送簡訊給我 |
試試直接設定 TField 的 ReadOnly 屬性:
[code delphi] procedure TForm1.DataSource1.StateChange(Sender: TObject); begin if DataSource1.State = dsInsert then begin DataSource1.DataSet.FieldByName('field1').ReadOnly := False; DataSource1.DataSet.FieldByName('field2').ReadOnly := False; DataSource1.DataSet.FieldByName('field3').ReadOnly := False; // ... end else begin DataSource1.DataSet.FieldByName('field1').ReadOnly := True; DataSource1.DataSet.FieldByName('field2').ReadOnly := True; DataSource1.DataSet.FieldByName('field3').ReadOnly := True; // ... end end; [/code] |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |