2012-02-05 34 views
1

我試圖構建一個原型應用程序,該應用程序由鏈接到圖表的數據表 組成,該圖表將與表 並排顯示,並隨數據更改而更新。如何在可編輯的ListCtrl和數據源之間同步數據?

對於我使用的ListCtrl派生的對象和表,因爲我想 能夠就地編輯的數據,我也繼承了 TextEditMixin類:

class EditableListCtrl(wx.ListCtrl, listmix.TextEditMixin): 
    def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition, 
      size=wx.DefaultSize, style=0): 
     wx.ListCtrl.__init__(self, parent, ID, pos, size, style) 
    listmix.TextEditMixin.__init__(self) 

我想讓我的後端數據與其顯示分開,所以我的 wx.Frame派生對象具有一個數據源對象,從中讀取數據以填充ListCtrl的數據源對象 。

self.list = EditableListCtrl(panel, style=wx.LC_REPORT) 
    self.list.InsertColumn(0, 'A', width=140) 
    self.list.InsertColumn(1, 'B', width=130) 

    for i in range(0, self.db.getNumRecords()): 
     item = self.db.getRecord(i) 
     index = self.list.InsertStringItem(sys.maxint, str(item[0])) 
     self.list.SetStringItem(index, 1, str(item[1])) 

因爲我現在基本上是有數據的兩個副本,我想提出 確保無論何時的ListCtrl是 由用戶編輯的數據源更新。

有沒有一個標準的方法來做到這一點?

我試圖綁定到EVT_LIST_ITEM_DESELECTED事件,但它 觸發TextEditMixin功能改變 的的ListCtrl數據之前 - 由回調 功能是舊數據從的ListCtrl檢索的數據。

回答

3

有兩種同步數據的方法。

1.使用虛擬的ListCtrl

當使用虛擬的ListCtrl,您不必手動添加數據。它 從您的數據源中提取數據。

要創建ListCtrl虛擬,請使用 wx.LC_VIRTUAL樣式標誌初始化ListCtrl。

對於虛擬的ListCtrl提取數據,你需要重寫 以下功能(很明顯,你需要先繼承的ListCtrl):

OnGetItemText(self, item, column) 
OnGetItemAttr(self, item) 
OnGetItemImage(self, item) 

首先這些手柄字符串數據。我沒有使用其他的 兩個。(如果你不使用它們,只是返回None-1分別。)

您還需要調用SetItemCount(item_count)告訴的ListCtrl 多少條記錄檢索。

要在用戶修改單元格時更新數據源,您需要 實施SetVirtualData(self, row, col, text)

有關更多信息,請參閱介紹"Advanced wxPython Nuts and Bolts" by Robin Dunn

2.使用一個普通的ListCtrl

子類的ListCtrl並重寫功能SetStringItem(self, row, col, text)。在您的新實現中,更新您的數據源。不要 忘記也呼叫基類SetStringItem()雖然!否則, ListCtrl外觀不會改變。

虛擬ListCtrl是一個更多的工作,但建議,因爲你不再結束兩個數據副本。

(感謝邁克·德里斯科爾指着我在正確的方向找到了這個信息!)

1

我不明白。你如何獲得兩份數據?一個在數據庫中,一個在顯示?情況總是如此。當涉及到這樣的事情時,我認爲我見過的常用方法是使用虛擬ListCtrl(參見wxPython演示)。

您還可以看看我是如何與MediaLocker做到了:

http://www.blog.pythonlibrary.org/2011/12/09/ann-medialocker-%E2%80%93-a-wxpython-app-to-track-your-media/

還是在我原來的應用程序,是爲MediaLocker的基礎:我使用

http://www.blog.pythonlibrary.org/2011/11/10/wxpython-and-sqlalchemy-an-intro-to-mvc-and-crud/

ObjectListView而不是ListCtrl,因爲我覺得它更易於使用。

+0

感謝您的答覆。我並不抱怨有兩份數據。我很驚訝沒有一個事件可以綁定到ListCtrl中的數據發生變化時激活。否則,能夠編輯它有什麼意義?我必須輪詢ListCtrl嗎?我會看看Virtual ListCtrl和ObjectListView,看看它們是否更好。 – MatthewD 2012-02-06 23:11:52

+0

我不知道StackOverflow允許用戶詢問和回答自己的問題,更不用說接受自己的答案。 – 2012-02-08 13:53:15

+0

它的確如此,但你沒有得到任何代表。 – MatthewD 2012-02-08 22:07:04

1

你正在尋找的事件是wx.EVT_LIST_END_LABEL_EDIT,我想。

2

有一種解決這種明顯異常的方法,您可以在其中編輯數據,但似乎無法訪問數據,例如執行數據庫更新。 需要將事件到的listctrl結合並然後訪問event.GetLabel不listCtrl.GetText
例如:

self.listCtrl.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnMixUpdate) 

然後:

def OnMixUpdate(self, event): 
    # Set the changed data via the event.GetLabel not listCtrl.GetText which remains unchanged until we change it 
    rowid = self.listCtrl.GetFocusedItem() 
    new_data = event.GetLabel() 
    colid = event.GetColumn() 
    self.listCtrl.SetStringItem(rowid,colid,new_data,) 
    #Update a textctrl on screen 
    self.SetData() 
    #Update database 
    self.OnUpdate(None) 
    event.Skip() 

以上是使用正常的listctrl( ) 在我提出這個解決方案之前,這個特殊的問題讓我頭痛不止。我懷疑還有其他人,但我找不到。事實上,根據我的網絡搜索,似乎並不只有少數人遇到過這個問題。

可以更換線路
ROWID = self.listCtrl.GetFocusedItem()

ROWID = event.GetIndex() 並得到同樣的結果這或許讀好