2009-02-26 10 views

Antwort

4

Um zu tun, was Sie wollen, d. H. Haben eine andere Auswahlfarbe, wenn bestimmte Elemente ausgewählt sind, müssen Sie in Win32 fallen. Glücklicherweise ist es in Python nicht schwer, das zu tun. Es macht jedoch Ihre Code-Plattform abhängig. Ich habe es heute in einem kleinen Programm ausprobiert. Wenn das Genre nicht "Rock" ist, mache ich die Auswahl orange. Hier sind einige Screenshots.

Rock-Elemente ausgewählt alt text http://img26.imageshack.us/img26/981/soshot1.jpg

Gemischte Elemente ausgewählt. Beachten Sie, dass RnB und Blues mit Orange ausgewählt wurden alt text http://img258.imageshack.us/img258/1307/soshot2.jpg

Hier ist der Code. Es sieht zunächst unheimlich aus, aber wenn Sie irgendwelche Win32 kennen, ist es nicht so schlimm. Ich benutze das pywin32 Paket und die Std-Ctypes-Bibliotheken. Ich musste einige der SDK-Konstanten definieren, da sie im win32con-Modul nicht verfügbar waren.

import sys 
import wx 
import wx.lib.mixins.listctrl as listmix 

import win32api 
import win32gui 
import win32con 
import win32gui_struct 
import commctrl 
import ctypes 
from ctypes.wintypes import BOOL, HWND, RECT, UINT, DWORD, HDC, DWORD, LPARAM, COLORREF 

LVM_FIRST = 0x1000 
LVM_GETSUBITEMRECT=(LVM_FIRST + 56) 
LVIR_BOUNDS    =0 
LVIR_ICON    =1 
LVIR_LABEL    =2 
LVIR_SELECTBOUNDS  =3 
DEFAULT_GUI_FONT =17 

#LPNMHDR 
class NMHDR(ctypes.Structure): 
    pass 
INT = ctypes.c_int 
NMHDR._fields_ = [('hwndFrom', HWND), ('idFrom', UINT), ('code', INT)] 
LPNMHDR = ctypes.POINTER(NMHDR) 

#LPNMCUSTOMDRAW 
class NMCUSTOMDRAW(ctypes.Structure): 
    pass 
NMCUSTOMDRAW._fields_ = [('hdr', NMHDR), ('dwDrawStage', DWORD), ('hdc', ctypes.c_int), 
         ('rc', RECT), ('dwItemSpec', DWORD), ('uItemState', UINT), 
         ('lItemlParam', LPARAM)] 
LPNMCUSTOMDRAW = ctypes.POINTER(NMCUSTOMDRAW) 

#LPNMLVCUSTOMDRAW 
class NMLVCUSTOMDRAW(ctypes.Structure): 
    pass 
NMLVCUSTOMDRAW._fields_ = [('nmcd', NMCUSTOMDRAW), 
          ('clrText', COLORREF), 
          ('clrTextBk', COLORREF), 
          ('iSubItem', ctypes.c_int), 
          ('dwItemType', DWORD), 
          ('clrFace', COLORREF), 
          ('iIconEffect', ctypes.c_int), 
          ('iIconPhase', ctypes.c_int), 
          ('iPartId', ctypes.c_int), 
          ('iStateId', ctypes.c_int),       
          ('rcText', RECT), 
          ('uAlign', UINT) 
          ] 
LPNMLVCUSTOMDRAW = ctypes.POINTER(NMLVCUSTOMDRAW) 


musicdata = { 
1 : ("Bad English", "The Price Of Love", "Rock"), 
2 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"), 
3 : ("George Michael", "Praying For Time", "Rock"), 
4 : ("Gloria Estefan", "Here We Are", "Rock"), 
5 : ("Linda Ronstadt", "Don't Know Much", "Rock"), 
6 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"), 
7 : ("Paul Young", "Oh Girl", "Rock"), 
8 : ("Paula Abdul", "Opposites Attract", "Rock"), 
9 : ("Richard Marx", "Should've Known Better", "Rock"), 
10 : ("Bobby Brown", "My Prerogative", "RnB"), 
} 




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

    def ShouldCustomDraw(self, row): 
     if self.IsSelected(row): 
      listitem = self.GetItem(row, 2) 
      genre = listitem.GetText() 

      return genre != "Rock" 


    def CustomDraw(self, lpcd):   
     if lpcd.contents.nmcd.dwDrawStage == commctrl.CDDS_PREPAINT: 
      return (True, commctrl.CDRF_NOTIFYITEMDRAW) 

     if lpcd.contents.nmcd.dwDrawStage == commctrl.CDDS_ITEMPREPAINT:     
      if self.ShouldCustomDraw(lpcd.contents.nmcd.dwItemSpec): 
       #do custom drawing for non Rock selected rows 
       #paint the selection background 
       color = win32api.RGB(255, 127, 0) #orange 
       brush = win32gui.CreateSolidBrush(color) 
       r = lpcd.contents.nmcd.rc 
       win32gui.FillRect(int(lpcd.contents.nmcd.hdc), (r.left+4, r.top, r.right, r.bottom), brush)     
       win32gui.DeleteObject(brush) 
       return (True, commctrl.CDRF_NOTIFYSUBITEMDRAW)      

     if lpcd.contents.nmcd.dwDrawStage == commctrl.CDDS_ITEMPREPAINT|commctrl.CDDS_SUBITEM:     
      row = lpcd.contents.nmcd.dwItemSpec 
      col = lpcd.contents.iSubItem 
      item = self.GetItem(row, col) 
      text = item.GetText() 
      #paint the text 
      rc = RECT() 
      rc.top = col 
      if col > 0: 
       rc.left = LVIR_BOUNDS 
      else: 
       rc.left = LVIR_LABEL 
      success = win32api.SendMessage(self.Handle, LVM_GETSUBITEMRECT, row, ctypes.addressof(rc)) 
      if col > 0: 
       rc.left += 5 
      else: 
       rc.left += 2 
      rc.top += 2 

      if success:     
       oldColor = win32gui.SetTextColor(lpcd.contents.nmcd.hdc, win32gui.GetSysColor(win32con.COLOR_HIGHLIGHTTEXT))     
       win32gui.DrawText(lpcd.contents.nmcd.hdc, text, len(text), (rc.left, rc.top, rc.right, rc.bottom), win32con.DT_LEFT|win32con.DT_VCENTER) 
       win32gui.SetTextColor(lpcd.contents.nmcd.hdc, oldColor)         

      return (True, commctrl.CDRF_SKIPDEFAULT) 


     # don't need custom drawing 
     return (True, commctrl.CDRF_DODEFAULT) 


class MyFrame(wx.Frame): 
    def __init__(self, *args, **kwds): 
     wx.Frame.__init__(self, *args, **kwds) 
     self._sizer = wx.BoxSizer(wx.VERTICAL) 
     tID = wx.NewId() 
     self._ctl = MyListCtrl(self, tID, 
           style=wx.LC_REPORT 
           #| wx.BORDER_SUNKEN 
           | wx.BORDER_NONE 
           | wx.LC_EDIT_LABELS 
           | wx.LC_SORT_ASCENDING 
           #| wx.LC_NO_HEADER 
           #| wx.LC_VRULES 
           #| wx.LC_HRULES 
           #| wx.LC_SINGLE_SEL 
           ) 
     self._sizer.Add(self._ctl, 1, wx.EXPAND, 3) 
     self.PopulateList() 

     self.oldWndProc = win32gui.SetWindowLong(self.GetHandle(), win32con.GWL_WNDPROC, self.MyWndProc) 


    def MyWndProc(self, hWnd, msg, wParam, lParam): 

     if msg == win32con.WM_NOTIFY: 
      hwndFrom, idFrom, code = win32gui_struct.UnpackWMNOTIFY(lParam) 
      if code == commctrl.NM_CUSTOMDRAW and hwndFrom == self._ctl.Handle:     
       lpcd = ctypes.cast(lParam, LPNMLVCUSTOMDRAW) 
       retProc, retCode = self._ctl.CustomDraw(lpcd) 

       if retProc: 
        return retCode 


     # Restore the old WndProc. Notice the use of wxin32api 
     # instead of win32gui here. This is to avoid an error due to 
     # not passing a callable object. 
     if msg == win32con.WM_DESTROY: 
      win32api.SetWindowLong(self.GetHandle(), 
           win32con.GWL_WNDPROC, 
           self.oldWndProc) 

     # Pass all messages (in this case, yours may be different) on 
     # to the original WndProc 
     return win32gui.CallWindowProc(self.oldWndProc, 
            hWnd, msg, wParam, lParam) 

    def PopulateList(self): 
     self._ctl.InsertColumn(0, "Artist") 
     self._ctl.InsertColumn(1, "Title") 
     self._ctl.InsertColumn(2, "Genre") 

     items = musicdata.items() 

     for key, data in items:    
      index = self._ctl.InsertStringItem(sys.maxint, data[0]) 
      self._ctl.SetStringItem(index, 1, data[1]) 
      self._ctl.SetStringItem(index, 2, data[2]) 
      self._ctl.SetItemData(index, key) 


     self._ctl.SetColumnWidth(0, wx.LIST_AUTOSIZE) 
     self._ctl.SetColumnWidth(1, wx.LIST_AUTOSIZE) 
     self._ctl.SetColumnWidth(2, 100) 

     self.currentItem = 0 

class MyApp(wx.App): 
    def OnInit(self): 
     frame = MyFrame(None, -1, 'wxListCtrl StackOverflow') 
     frame.Show() 
     self.SetTopWindow(frame) 
     return 1 

if __name__ == "__main__": 
    app = MyApp(0) 
    app.MainLoop() 
7

In Ihrer Klasse, die Sie von wx.ListCtrl ableiten, werfen Sie einen Blick auf überwiegenden

def OnGetItemAttr(self, item): 
    return self.normalAttr[item % 2] 
# 

, wo das Element Attribut vor der Zeit initialisiert verwenden:

self.normalAttr = [] 
    self.normalAttr.append(wx.ListItemAttr()) 
    grayAttr = wx.ListItemAttr() 
    grayAttr.SetBackgroundColour(lightGray) 
    self.normalAttr.append(grayAttr) 

in diesem Fall also, Ich wechsle Hintergrundfarben zwischen dem Standard und einem hellgrauen Attribut.

Diese Funktion wird für jede Zeile so aufgerufen, wie sie gezeichnet wird. Sie können damit alle Arten von Status anzeigen. Wenn Zeile ausgewählt ist, sollte ein einfacher Fall sein.