⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 listctrl.py

📁 bittorrent source by python. please enjoy
💻 PY
📖 第 1 页 / 共 2 页
字号:
# The contents of this file are subject to the BitTorrent Open Source License# Version 1.1 (the License).  You may not copy or use this file, in either# source code or executable form, except in compliance with the License.  You# may obtain a copy of the License at http://www.bittorrent.com/license/.## Software distributed under the License is distributed on an AS IS basis,# WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License# for the specific language governing rights and limitations under the# License.# written by Matt Chisholm, Steven Hazel, and Greg Hazelimport localeimport tracebackimport wxfrom UserDict import IterableUserDictfrom BitTorrent.obsoletepythonsupport import setfrom wx.lib.mixins.listctrl import ColumnSorterMixinfrom wx.lib.mixins.listctrl import getListCtrlSelectionimport osif os.name == 'nt':    LVM_FIRST = 0x1000    LVM_SETSELECTEDCOLUMN = (LVM_FIRST + 140)    import win32apidef highlight_color(c):    if c > 240:        c *= 0.97    else:        c = min(c * 1.10, 255)    return int(c)SEL_FOC = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSEDdef selectBeforePopup(ctrl, pos):    """Ensures the item the mouse is pointing at is selected before a popup.    Works with both single-select and multi-select lists."""    if not isinstance(ctrl, wx.ListCtrl):        return    n, flags = ctrl.HitTest(pos)    if n < 0:        return    if not ctrl.GetItemState(n, wx.LIST_STATE_SELECTED):        for i in xrange(ctrl.GetItemCount()):            ctrl.SetItemState(i, 0, SEL_FOC)        ctrl.SetItemState(n, SEL_FOC, SEL_FOC)class ContextMenuMixin(object):    def __init__(self):        self.context_menu = None        self.column_context_menu = None        self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)        self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColumnContextMenu)    def SetContextMenu(self, menu):        self.context_menu = menu    def SetColumnContextMenu(self, menu):        self.column_context_menu = menu    def OnColumnContextMenu(self, event):        if self.column_context_menu:            self.PopupMenu(self.column_context_menu)    def OnContextMenu(self, event):        pos = self.ScreenToClient(event.GetPosition())        top = self.GetItemRect(self.GetTopItem())        if pos[1] < top.y:            event.Skip()            return        pos -= self._get_origin_offset()        self.DoPopup(pos)    def DoPopup(self, pos):        """ pos should be in client coords """        if self.context_menu:            selectBeforePopup(self, pos)            selection = getListCtrlSelection(self)            if len(selection) > 0:                self.PopupMenu(self.context_menu)                returnclass BTListColumn(wx.ListItem):    def __init__(self, text, sample_data, renderer=None, comparator=None, enabled=True, width=50):        wx.ListItem.__init__(self)        self.SetText(text)        self.renderer = renderer        self.comparator = comparator        self.enabled = enabled        self.sample_data = sample_data        self.width = widthclass BTListRow(IterableUserDict):    __slots__ = ['data', 'index']    def __init__(self, index, data):        self.data = data        self.index = index    def __getitem__(self, i):        return self.data[i]class BTListCtrl(wx.ListCtrl, ColumnSorterMixin, ContextMenuMixin):    # Part of this class based on:    # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/426407    icon_size = 16    def __init__(self, parent):        wx.ListCtrl.__init__(self, parent, wx.ID_ANY, style=wx.LC_REPORT)        ContextMenuMixin.__init__(self)        self.il = wx.ImageList(self.icon_size, self.icon_size)        # TODO: use a real icon        self.il.Add(self.draw_blank())        self.il.Add(self.draw_sort_arrow('up'))        self.il.Add(self.draw_sort_arrow('down'))        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)        self.update_enabled_columns()        for i, name in enumerate(self.enabled_columns):            column = self.columns[name]            column.SetColumn(i)            self.InsertColumnItem(i, column)        self.itemData_to_row = {}        self.index_to_itemData = {}        self.selected_column = None        self.SelectColumn(self.enabled_columns[0])        cmenu = wx.Menu()        for name in self.column_order:            column = self.columns[name]            id = wx.NewId()            cmenu.AppendCheckItem(id, column.GetText())            cmenu.Check(id, column.enabled)            self.Bind(wx.EVT_MENU,                      lambda e, c=column, id=id: self.toggle_column(c, id, e),                      id=id)        self.SetColumnContextMenu(cmenu)        ColumnSorterMixin.__init__(self, len(self.enabled_columns))        self._last_scrollpos = 0        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)        self.default_rect = wx.Rect(0,0)    def OnEraseBackground(self, event=None):        nsp = self.GetScrollPos(wx.VERTICAL)        if self._last_scrollpos != nsp:            self._last_scrollpos = nsp            # should only refresh visible items, hmm            wx.CallAfter(self.Refresh)        dc = wx.ClientDC(self)        # erase the section of the background which is not covered by the        # items or the selected column highlighting        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))        f = self.GetRect()        r = wx.Region(0, 0, f.width, f.height)        x = self.GetVisibleViewRect()        offset = self._get_origin_offset(include_header=True)        x.Offset(offset)        r.SubtractRect(x)        if '__WXMSW__' in wx.PlatformInfo:            c = self.GetColumnRect(self.enabled_columns.index(self.selected_column))            r.SubtractRect(c)        dc.SetClippingRegionAsRegion(r)        dc.Clear()        if '__WXMSW__' in wx.PlatformInfo:            # draw the selected column highlighting under the items            dc.DestroyClippingRegion()            r = wx.Region(0, 0, f.width, f.height)            r.SubtractRect(x)            dc.SetClippingRegionAsRegion(r)            dc.SetPen(wx.TRANSPARENT_PEN)            hc = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)            r = highlight_color(hc.Red())            g = highlight_color(hc.Green())            b = highlight_color(hc.Blue())            hc.Set(r, g, b)            dc.SetBrush(wx.Brush(hc))            dc.DrawRectangle(c.x, c.y, c.width, c.height)    def update_enabled_columns(self):        self.enabled_columns = [name for name in self.column_order                                if self.columns[name].enabled]    def toggle_column(self, tcolumn, id, event):        self.update_column_widths()        sort_col = self.get_sort_column()        tcolumn.enabled = not tcolumn.enabled        self.column_context_menu.Check(id, tcolumn.enabled)        self.update_enabled_columns()        if not tcolumn.enabled:            self.DeleteColumn(tcolumn.GetColumn())        new_col_names = []        for i, name in enumerate(self.enabled_columns):            column = self.columns[name]            column.SetColumn(i)            if column == tcolumn:                self.InsertColumnItem(i, column)                new_col_names.append(name)            self.SetColumnWidth(column.GetColumn(), column.width)        self.SetColumnCount(len(self.enabled_columns))        self.SortListItems(col=sort_col)        for itemData in self.itemData_to_row.iterkeys():            self.InsertRow(itemData, self.itemData_to_row[itemData],                           sort=True, force_update_columns=new_col_names)        #self.SortItems()    def set_default_widths(self):        # must be called before *any* data is put into the control.        sample_data = {}        for name in self.column_order:            sample_data[name] = self.columns[name].sample_data        sample_row = BTListRow(None, sample_data)        self.InsertRow(-1, sample_row)        for name in self.column_order:            column = self.columns[name]            if name in self.enabled_columns:                self.SetColumnWidth(column.GetColumn(), wx.LIST_AUTOSIZE)                column.width = self.GetColumnWidth(column.GetColumn())            dc = wx.ClientDC(self)            header_width = dc.GetTextExtent(column.GetText())[0]            header_width += 4 # arbitrary allowance for header decorations            column.width = max(column.width, header_width)            if name in self.enabled_columns:                self.SetColumnWidth(column.GetColumn(), column.width)        self.default_rect = self.GetItemRect(0)        self.DeleteRow(-1)    def _get_origin_offset(self, include_header=None):        if include_header is None:            # Hm, I think this is a legit bug in wxGTK            if '__WXGTK__' in wx.PlatformInfo:                include_header = True            else:                include_header = False        if include_header:                        i = self.GetTopItem()            try:                r = self.GetItemRect(i)            except wx._core.PyAssertionError:                r = self.default_rect            return (r.x, r.y)        return (0, 0)    def add_image(self, image):        b = wx.BitmapFromImage(image)        assert b.Ok(), "The image (%s) is not valid." % str(image)        if '__WXMSW__' in wx.PlatformInfo:            # hack for 16-bit color mode            if b.GetDepth() > 24: # I mean, has alpha                b.SetMask(wx.Mask(b, wx.Colour(0, 0, 0)))        return self.il.Add(b)    # Arrow drawing    def draw_blank(self):        b = wx.EmptyBitmap(self.icon_size, self.icon_size)        dc = wx.MemoryDC()        dc.SelectObject(b)        dc.SetBackgroundMode(wx.TRANSPARENT)        dc.Clear()        dc.SelectObject(wx.NullBitmap)        b.SetMask(wx.Mask(b, (255, 255, 255)))        return b    # this builds an identical arrow to the windows listctrl arrows, in themed    # and non-themed mode.    def draw_sort_arrow(self, direction):        b = wx.EmptyBitmap(self.icon_size, self.icon_size)        w, h = b.GetSize()        ho = (h - 5) / 2        dc = wx.MemoryDC()        dc.SelectObject(b)        colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT)        dc.SetBackgroundMode(wx.TRANSPARENT)        dc.Clear()        dc.SetPen(wx.Pen(colour))        for i in xrange(5):            if direction == 'down':                j = 4 - i            else:                j = i            dc.DrawLine(i,j+ho,9-i,j+ho)        dc.SelectObject(wx.NullBitmap)        b.SetMask(wx.Mask(b, (255, 255, 255)))        return b    def GetBottomItem(self):        total = self.GetItemCount()        top = self.GetTopItem()        pp = self.GetCountPerPage()        # I purposefully do not subtract 1 from pp, because pp is whole items        bottom = min(top + pp, total - 1)        return bottom    def SelectColumn(self, col):        """Color the selected column (MSW only)"""        if self.selected_column == col:            return        col_num = self.enabled_columns.index(col)        if os.name == 'nt':            win32api.PostMessage(self.GetHandle(),                                 LVM_SETSELECTEDCOLUMN, col_num, 0)            if self.selected_column is not None:                self.RefreshCol(self.selected_column)            self.RefreshCol(col)            self.selected_column = col    def render_column_text(self, row, name):        """Renders the column value into a string"""        item = self.columns[name]        value = row[name]        if value is None:            text = '?'        elif item.renderer is not None:            try:                text = item.renderer(value)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -