문제

상태를 표시 할 수 있도록 특정 행 선택한 색상이 표준 색상 대신 (창에서 파란색) 빨간색으로 사용하고 싶습니다. WXPYTHON에서 이것이 가능하다면 누구든지 있습니까?

도움이 되었습니까?

해결책

원하는 것을 수행하려면 특정 항목을 선택할 때 선택 색상이 다릅니다. Win32로 떨어야합니다. 다행히도 파이썬에서 그렇게하는 것은 그리 어렵지 않습니다. 그러나 코드 플랫폼을 의존하게 만듭니다. 나는 오늘 작은 프로그램에서 그것을 시도했다. 장르가 "바위"가 아닌 경우 선택을 주황색으로 만듭니다. 스크린 샷은 다음과 같습니다.

선택된 암석 항목alt text

선택된 혼합 품목. RNB와 블루스는 주황색으로 선택됩니다Alt Text http://img258.imageshack.us/img258/1307/soshot2.jpg

코드는 다음과 같습니다. 처음에는 무섭게 보이지만 Win32를 알고 있다면 그렇게 나쁘지 않습니다. 나는 pywin32 패키지 및 STD CTYPES 라이브러리. Win32Con 모듈에서 사용할 수 없었기 때문에 SDK 상수의 일부를 정의해야했습니다.

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()

다른 팁

수업에서 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)

따라서이 경우 기본값과 밝은 회색 속성 사이의 배경색을 번갈아 가며 번갈아 가고 있습니다.

이 기능은 각 행에 페인트 칠대로 호출되므로 모든 종류의 상태를 표시하는 데 사용할 수 있습니다. 행을 선택한 경우 쉬운 경우입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top