我使用的wxLua版本信息為wxLua 2.8.7.0 built with wxWidgets 2.8.8
,也就是LuaForWindows_v5.1.4-40.exe這個安裝包里自帶的wxLua。我不知道其他wxWidgets版本里wxListCtrl怎樣,但我使用的版本里wxListCtrl是不支持編輯里面的子item的。在我使用的report模式下,子item也就是特定某一行一列的item。
google了一下,發現悲劇地需要自己實現,主要就是自己顯示一個wxTextCtrl:
--
-- file: wxListCtrlTextEdit.lua
-- author: Kevin Lynx
-- date: 08.06.2012
--
local EditList = {}
-- get the column by an abs point
function EditList:getColumn(x)
local cols = self.listctrl:GetColumnCount()
local cx = 0
for i = 0, cols - 1 do
local w = self.listctrl:GetColumnWidth(i)
if x <= cx + w then return i end
cx = cx + w
end
return -1
end
-- when a mouse down, show a text edit control
function EditList:onLeftDown(evt)
if self.editor:IsShown() then
self:closeEditor()
end
local p = evt:GetPoint()
local row = evt:GetIndex()
local col = self:getColumn(p.x)
local rect = wx.wxListCtrlEx.GetSubItemRect(self.listctrl, row, col)
rect:SetHeight(rect:GetHeight() + 5) -- adjust
self.editor:SetSize(rect)
self.editor:Show()
self.editor:SetValue(wx.wxListCtrlEx.GetItemText(self.listctrl, row, col))
self.editor:SetFocus()
self.col = col
self.row = row
end
function EditList:closeEditor()
if not self.editor:IsShown() then return end
self.editor:Hide()
self.listctrl:SetItem(self.row, self.col, self.editor:GetValue())
end
function EditList:initialize()
self.editor = wx.wxTextCtrl(self.listctrl, wx.wxID_ANY, "", wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxTE_PROCESS_ENTER + wx.wxTE_RICH2)
self.editor:Connect(wx.wxEVT_COMMAND_TEXT_ENTER, function () self:closeEditor() end)
-- not work actually
self.editor:Connect(wx.wxEVT_COMMAND_KILL_FOCUS, function () self:closeEditor() end)
self.editor:Hide()
end
function wx.wxListCtrlTextEdit(listctrl)
local o = {
listctrl = listctrl,
editor = nil,
}
local editlist = newObject(o, EditList)
editlist:initialize()
listctrl:Connect(wx.wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, function (evt) editlist:onLeftDown(evt) end)
listctrl:Connect(wx.wxEVT_COMMAND_LIST_ITEM_FOCUSED, function () editlist:closeEditor() end)
return listctrl
end
其原理就是獲取到當前鼠標點擊所在的子item位置,然后在此位置顯示一個wxEditCtrl即可。以上代碼需要依賴我之前寫的Lua里實現簡單的類-對象中的代碼,同時依賴以下針對wxListCtrl的擴展接口:
--
-- file: wxListCtrlExtend.lua
-- author: Kevin Lynx
-- date: 08.07.2012
-- brief: extend some util functions to wx.wxListCtrl
--
wx.wxListCtrlEx = {}
function wx.wxListCtrlEx.GetSubItemRect(listctrl, item, col)
local rect = wx.wxRect()
listctrl:GetItemRect(item, rect)
local x = 0
local w = 0
for i = 0, col do
w = listctrl:GetColumnWidth(i)
x = x + w
end
return wx.wxRect(x - w, rect:GetY(), w, rect:GetHeight())
end
function wx.wxListCtrlEx.GetItemText(listctrl, item, col)
local info = wx.wxListItem()
info:SetId(item)
info:SetColumn(col)
info:SetMask(wx.wxLIST_MASK_TEXT)
listctrl:GetItem(info)
return info:GetText()
end
在我看到的wxWidgets官方文檔里,其實wxListCtrl已經有GetSubItemRect
接口,并且在另一些示例代碼里,也看到了GetItemText
接口,但是,我使用的版本里沒有,所以只好自己寫。基于以上,要使用這個可以支持編輯子item的wxListCtrl,可以:
list = wx.wxListCtrlTextEdit(wx.wxListCtrl(dialog, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxLC_REPORT))
也就是通過wx.wxListCtrlTextEdit這個函數做下處理,這個函數返回的是本身的wxListCtrl。當然更好的方式是使用繼承之類的方式,開發一種新的控件,但在Lua中,針對usedata類型的擴展貌似只能這樣了。
最好吐槽下,這個控件擴展其實很惡心。本來我打算當編輯控件失去焦點后就隱藏它,但是往編輯控件上注冊KILL_FOCUS事件始終不起作用;我又打算弄個ESC鍵盤事件去手動取消,但顯然wxTextCtrl是不支持鍵盤事件的。好吧,湊合用了。