2009-02-26 91 views

回答

4

爲了做你想做的事情,即選擇某些項目時有不同的選擇顏色,你需要放入win32。幸運的是,在python中做這件事並不難。但它確實使您的代碼平臺依賴。我今天在一個小程序中嘗試了它。如果流派不是「搖滾」,我會選擇橙色。這裏有一些截圖。

巖項目中選擇 alt text http://img26.imageshack.us/img26/981/soshot1.jpg

混合項目中選擇。注意RnB和Blues用橙色選擇 alt text http://img258.imageshack.us/img258/1307/soshot2.jpg

這是代碼。它起初看起來很可怕,但如果你知道任何win32,它並不是那麼糟糕。我利用了pywin32包和std ctypes庫。我不得不定義一些SDK常量,因爲它們在win32con模塊中不可用。

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

在你的類,你從wx.ListCtrl獲得,使用看一看首要

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

凡項屬性的時間提前初始化:

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

所以在這種情況下,我在默認和淺灰色屬性之間交替出現背景顏色。

這個函數被稱爲每一行的繪畫,所以你可以用它來指示各種狀態。如果選擇行應該是一個簡單的情況。