by jingzhongrong 在預設狀态下,ListView控件的編輯功能是通過提供一個類似Edit控件的欄來實作的。但是如果你想讓界面更加友好或者希望使用其他類型的控件來編輯資料,以提高操作的便利性。如下圖所示,我們利用一個ComboBox控件來讓使用者以選擇的方式來編輯資料。
在上述圖檔中,使用ComboBox控件進行選擇,選中的項目可以直接對ListView中的“插件狀态”欄進行修改。其中還涉及對ComboBox控件和ListView控件的自繪,不屬于此文所要描述的範圍,略過這部分的代碼以及實作。如果需要了解有關控件自繪的資訊,可以自行到網上搜尋。此文的編譯環境是C++Builder 2007。 下面具體說明實作的方法。首先添加ListView控件以及ComboBox控件到程式中,并設定ComboBox控件的Visible屬性預設為false。 1、每當使用者單擊ListView控件時,我們應該擷取滑鼠此時單擊的位置,并根據位置計算出所在行以及所在的列(如上圖,ComboBox出現在第二列中,隻有當滑鼠單擊的位置在ListView第二列中才會出現ComboBox讓使用者進行選擇)。 判斷使用者單擊的行及列使用如下代碼:
// 在ListView 控件的OnMouseUp 事件中添加如下代碼 TListView *listview = (TListView*)Sender; TListItem *lv = listview->GetItemAt(X,Y); if(lv) // 如果選中一項 { TPoint p(X,Y); TRect ClickedItem = lv->DisplayRect(drBounds); // 擷取選擇的項目的邊框 TRect rct(ClickedItem); int CellLeft = rct.Left, CellIndex = 0; // 下面計算滑鼠單擊的位置處在哪一列中 for(int x = 0; x < listview->Columns->Count; x++) { rct.Left = CellLeft; rct.Right = CellLeft + listview->Column[x]->Width; if(PtInRect(rct,p)) // 滑鼠單擊位置在x+1 列中 { CellIndex = x + 1; break; } CellLeft += listview->Column[x]->Width; } // 檢查滑鼠點選位置是否位于" 插件狀态" 一列中(對應上圖實作) if(CellIndex != 2) return; else // 處于“插件狀态”列中 { … // 暫時省略此處代碼 } } |
2、此時我們已經判斷得出滑鼠單擊的位置是否應該顯示出ComboBox控件。下面我們繼續進行判斷,此時我們應該考慮到這個列可能處于完全不可見的狀态或者部分可見的狀态,我們應該調整ComboBox的位置以及大小之後才能顯示出來。 上述步驟中變量ClickedItem便是用于儲存ComboBox應該的大小以及位置。我們根據下面的代碼對ClickedItem進行修正。
// 檢查資料行是否已經完全滾動至左側之外 if((ClickedItem.Left + listview->Column[0]->Width + listview->Column[1]->Width) < 0) return; // 單元格在左側之外無法看到不做處理 // // 檢查資料行是否部分被滾動至左側之外 //By jingzhongrong else if(ClickedItem.Left + listview->Column[0]->Width < 0) { // 檢查此資料行是否已延伸至ListView 的右側之外 if((ClickedItem.Left + listview->Column[1]->Width + listview->Column[0]->Width) > listview->Width) { // 将資料行(ComboBox )的寬度設定成ListView 的寬度 ClickedItem.Left = 0; ClickedItem.Right = ClickedItem.Left + listview->Width; } else { // 單元格的右側位于視圖之中 ClickedItem.Right = ClickedItem.Left + listview->Column[0]->Width + listview->Column[1]->Width; ClickedItem.Left = 0; } } // 檢查資料行是否已經完全滾動至右側之外 else if(ClickedItem.Left + listview->Column[0]->Width > listview->Width) return; // 單元格在右側之外無法看到不做處理 // 資料行被部分滾動至右側之外 else if(listview->Column[1]->Width + listview->Column[0]->Width > listview->Width) { ClickedItem.Left += listview->Column[0]->Width; ClickedItem.Right = listview->Width - ClickedItem.Left; } else { ClickedItem.Left = listview->Column[0]->Width; ClickedItem.Right = listview->Column[1]->Width; } // 進行調整 ClickedItem.Left += listview->Left; ClickedItem.Top += 25; //Columns Height ClickedItem.Right += ClickedItem.Left; |
3、此時的ClickedItem已經儲存ComboBox應該出現的位置,我們下面顯示出ComboBox來。
this->ComboBox1->Top = ClickedItem.Top; this->ComboBox1->Left = ClickedItem.Left; this->ComboBox1->Width = ClickedItem.Width(); // 對ComboBox 顯示的文本進行設定 //ComboBox 應在初始化時添加選擇項并将其Style 屬性設定為csDropDownList 用來限制 // 使用者的選擇 if(lv->SubItems->Strings[0] == " 啟用") this->ComboBox1->ItemIndex = 0; else this->ComboBox1->ItemIndex = 1; //By jingzhongrong this->ComboBox1->Visible = true; this->ComboBox1->BringToFront(); this->ComboBox1->SetFocus(); |
4、至此,我們已經将ComboBox控件顯示出來。下面我們處理ComboBox進行選擇。在ComboBox控件的OnChange事件中添加如下代碼。
AnsiString str = this->ListView1->Selected->SubItems->Strings[0]; this->ListView1->Selected->SubItems->Strings[0] = ComboBox1->Text; ComboBox1->Visible = false; // 判斷ComboBox 選擇前後是否有更改過 if(str != ComboBox1->Text && ComboBox1->Text == " 啟用") { this->LoadPlugin(…); // 加載插件 } else if(str != ComboBox1->Text && ComboBox1->Text == " 禁用") { this->LoadPlugin(…); // 解除安裝插件 } |
5、繼續處理ComboBox控件,在OnExit事件中添加代碼,隐藏ComboBox控件。
AnsiString str = this->ListView1->Selected->SubItems->Strings[0]; if(str == "") { ComboBox1->Visible = false; } else { this->ListView1->Selected->SubItems->Strings[0] = ComboBox1->Text; ComboBox1->Visible = false; if(str != ComboBox1->Text && ComboBox1->Text == " 啟用") { this->LoadPlugin(); //load } else if(str != ComboBox1->Text && ComboBox1->Text == " 禁用") { this->LoadPlugin(); //unload } } this->ListView1->SetFocus(); |
6、OnKeyPress事件對Esc鍵以及Enter鍵進行處理
switch(Key) { case VK_ESCAPE: // 其他處理,此處省略 //… this->ComboBox1->Visible = false; this->ListView1->SetFocus(); break; case VK_RETURN: this->ComboBox1->Visible = false; this->ListView1->SetFocus(); break; } |
7、在最後,我們應該對WM_VSCROLL和WM_HSCROLL兩個消息進行處理。這兩個消息會在使用者垂直或者水準滾動ListView控件時引發。因為我們的ComboBox實際上并非ListView控件的一部分,是以,ComboBox控件并不會随着ListView控件的滾動而滾動。是以我們在這兩個消息引發時将ComboBox控件隐藏起來。我們可以有幾種方法來實作。可以繼承TListView控件,然後對WndProc進行重載,然後在WndProc函數中過濾掉這兩個消息。 下面我采用的是另外一種方法,需要在窗體OnCreate事件中加入以下代碼:
OldListViewWindowProc = ListView1->WindowProc; ListView1->WindowProc = MyListViewWindowProc; |
相應的在頭檔案中增加以下代碼:
TWndMethod OldListViewWindowProc; void __fastcall MyListViewWindowProc(TMessage &Message); |
下面是MyListViewWindowProc函數的實作
if(Message.Msg == WM_VSCROLL || Message.Msg == WM_HSCROLL) { ListView1->SetFocus(); } OldListViewWindowProc(Message); // 調用預設的處理函數處理其他消息 |
通過上述步驟,可以基本上可以實作使用ComboBox控件對ListView控件的項進行編輯。 By jingzhongrong 2007-9-19