感觉这样的listview如何
Tofloor
poster avatar
vala2012
deepin
2013-03-10 19:26
Author
  1. from draw import draw_text, draw_pixbuf
  2. from utils import get_text_size, get_match_parent, get_offset_coordinate
  3. from utils import is_single_click, is_double_click, is_left_button
  4. from listview_base import type_check
  5. from listview_base import ListViewBase
  6. from listview_base import View, Text
  7. import pango
  8. import gtk
  9. '''
  10. !!再也不用写item了.那是一件幸福的事情.
  11. DrawItem 事件可以针对每个 ListView 项发生。
  12. 当 View 属性设置为 View = Details 时,
  13. 还会发生 DrawSubItem 和 DrawColumnHeader 事件。
  14. 在这种情况下,可以处理 DrawItem 事件以绘制所有项共有的元素(如背景),
  15. 并处理 DrawSubItem 事件以便为各个子项(例如文本值)绘制元素。
  16. 您还可以仅使用这两个事件中的一个事件绘制 ListView 控件中的所有元素,尽管这可能不十分方便。
  17. 若要绘制详细信息视图中的列标题,必须处理 DrawColumnHeader 事件。
  18. '''
  19. class ListView(ListViewBase):
  20.     def __init__(self):
  21.         ListViewBase.__init__(self)
  22.         self.__init_settings()
  23.         self.__init_values()
  24.         self.__init_events()
  25.     def __init_settings(self):
  26.         self.add_events(gtk.gdk.ALL_EVENTS_MASK)
  27.     def __init_values(self):
  28.         #
  29.         self.__init_values_events()
  30.         self.__init_values_columns()
  31.         self.__init_values_items()
  32.     def __init_values_events(self):
  33.         self.__on_draw_column_heade = self.__on_draw_column_heade_hd
  34.         self.__on_draw_sub_item     = self.__on_draw_sub_item_hd
  35.         self.__on_draw_item         = self.__on_draw_item_hd
  36.         # 保存事件.
  37.         self.__double_click_hd  = None
  38.         self.__motion_notify_hd = None
  39.         self.__single_click_hd  = None
  40.     def __init_values_columns(self):
  41.         self.__columns_padding_height = 30
  42.     def __init_values_items(self):
  43.         self.__items_padding_height = 30
  44.         # 保存双击items.
  45.         self.__double_items = None
  46.         # 保存移动的items.
  47.         self.__motion_items = None
  48.         # 保存单击的items.
  49.         self.__single_items = None
  50.     def __init_events(self):
  51.         self.connect("realize",              self.__listview_realize_event)
  52.         self.connect("motion-notify-event",  self.__listview_motion_notify_event)
  53.         self.connect("button-press-event",   self.__listview_button_press_event)
  54.         self.connect("button-release-event", self.__listview_button_release_event)
  55.         self.connect("enter-notify-event",   self.__listview_enter_notify_event)
  56.         self.connect("leave-notify-event",   self.__listview_leave_notify_event)
  57.         self.connect("expose-event",         self.__listview_expose_event)
  58.     def __listview_realize_event(self, widget):
  59.         widget.set_realized(True)
  60.         scroll_win = get_match_parent(widget, "ScrolledWindow")
  61.         if scroll_win:
  62.             scroll_win.get_vadjustment().connect("value-changed",
  63.                                     self.__scroll_win_vajustment_changed)
  64.             scroll_win.get_hadjustment().connect("value-changed",
  65.                                     self.__scroll_win_hajustment_changed)
  66.             scroll_win.connect("scroll-event", self.__scroll_win_scroll_event)
  67.     def __scroll_win_scroll_event(self, widget, event):
  68.         self.__scroll_win_event()
  69.     def __scroll_win_vajustment_changed(self, adjustment):
  70.         self.__scroll_win_event()
  71.     def __scroll_win_hajustment_changed(self, adjustment):
  72.         self.__scroll_win_event()
  73.     def __scroll_win_event(self):
  74.         self.on_queue_draw_area()
  75.         self.window.process_updates(True)
  76.         self.window.process_updates(True)
  77.         self.on_queue_draw_area()
  78.     def __listview_motion_notify_event(self, widget, event):
  79.         #print "__listview_motion_notify_event..."
  80.         row_index, col_index = self.__get_items_mouse_data(event)
  81.         if not (None in [row_index]):
  82.             self.__motion_items = self.items[row_index]
  83.             # 发送信号.
  84.             if self.__motion_notify_hd:
  85.                 self.__motion_notify_hd(self, self.__motion_items, row_index, col_index)
  86.             self.on_queue_draw_area()
  87.     def __listview_button_press_event(self, widget, event):
  88.         # 判断双击的区域.
  89.         if is_double_click(event):
  90.             row_index, col_index = self.__get_items_mouse_data(event)
  91.             if not (None in [row_index]):
  92.                 self.__double_items = self.items[row_index]
  93.                 # 发送信号.
  94.                 if self.__double_click_hd:
  95.                     self.__double_click_hd(self, self.__double_items, row_index, col_index)
  96.                 self.on_queue_draw_area()
  97.     def __listview_button_release_event(self, widget, event):
  98.         #print "__listview_button_release_event..."
  99.         # 获取标题头触发的release事件返回的x索引.
  100.         if is_left_button(event):
  101.             # 列标头.
  102.             col_index =  self.__get_columns_mouse_data(event)
  103.             if col_index != None:
  104.                 print self.columns[col_index].text
  105.             # 获取items触发的release事件返回的x,y索引.
  106.             row_index, col_index = self.__get_items_mouse_data(event)
  107.             if not (None in [row_index]):
  108.                 # 发送信号.
  109.                 self.__single_items = self.items[row_index]
  110.                 self.__single_click_hd(self, self.__single_items, row_index, col_index)
  111.     def __listview_enter_notify_event(self, widget, event):
  112.         #print "__listview_enter_enter...notify_event..."
  113.         pass
  114.     def __listview_leave_notify_event(self, widget, event):
  115.         #print "__listview_leave_notify_event...."
  116.         pass
  117.     def connect_event(self, event_name, function_point):
  118.         if event_name == "double-click":
  119.             self.__double_click_hd  = function_point
  120.         elif event_name == "motion-notify":
  121.             self.__motion_notify_hd = function_point
  122.         elif event_name == "single-click":
  123.             self.__single_click_hd  = function_point
  124.     def __listview_expose_event(self, widget, event):
  125.         #print "__listview_expose_event.."
  126.         cr = widget.window.cairo_create()
  127.         rect = widget.allocation
  128.         #
  129.         if self.view == View.DETAILS: # 带标题头的视图, 比如详细信息.
  130.             self.__draw_view_details(cr, rect, widget)
  131.         #elif self.view ==
  132.         #
  133.         # 设置窗体的高度和宽度.
  134.         self.__set_listview_size()
  135.         return True
  136.     def __draw_view_details(self, cr, rect, widget):
  137.         #self.on_draw_item(e)
  138.         offset_x, offset_y, viewport = get_offset_coordinate(widget)
  139.         # 画标题头.
  140.         self.__draw_view_details_column(offset_y, cr, rect)
  141.         # 优化listview.
  142.         # 获取滚动窗口.
  143.         scroll_win = get_match_parent(self, "ScrolledWindow")
  144.         scroll_rect_h = rect.height
  145.         if scroll_win: # 如果没有滚动窗口,直接获取listview的高度.
  146.             scroll_rect_h = scroll_win.allocation.height
  147.         # dtk.ui.listview ===>>>
  148.         start_y = offset_y - self.__columns_padding_height
  149.         end_y   = offset_y + viewport.allocation.height - self.__columns_padding_height
  150.         start_index  = max(start_y / self.__items_padding_height, 0)
  151.         end_index    = (start_index + (scroll_rect_h + self.__columns_padding_height)/ self.__items_padding_height) + 1
  152.         #
  153.         # 剪切出绘制items的区域,防止绘制到标题头上.
  154.         cr.save()
  155.         cr.rectangle(rect.x + offset_x,
  156.                      rect.y + offset_y + self.__columns_padding_height,
  157.                      scroll_win.allocation.width,
  158.                      scroll_win.allocation.height)
  159.         cr.clip()
  160.         # 画 items.
  161.         self.__draw_view_details_items(start_index, end_index, cr, rect)
  162.         cr.restore()
  163.     def __draw_view_details_column(self, offset_y, cr, rect):
  164.         temp_column_w = 0
  165.         for index, column in enumerate(self.columns): # 绘制标题头.
  166.             # 保存属性.
  167.             e = ColumnHeaderEventArgs()
  168.             e.cr     = cr
  169.             e.column = column
  170.             e.column_index = index
  171.             e.text = column.text
  172.             e.x = rect.x + temp_column_w
  173.             e.y = offset_y + rect.y
  174.             e.w = column.width
  175.             e.h = self.__columns_padding_height + 1
  176.             e.text_color = column.text_color
  177.             #
  178.             temp_column_w += column.width
  179.             self.on_draw_column_heade(e)
  180.     def __draw_view_details_items(self, start_index, end_index, cr, rect):
  181.         temp_item_h  = self.__columns_padding_height
  182.         for row, item in enumerate(self.items[start_index:end_index]):
  183.             temp_item_w = 0
  184.             # 行中的列元素.
  185.             for column, sub_item in map(lambda s, c:(s, c),
  186.                                         self.columns,  
  187.                                         item.sub_items):
  188.                 if column and sub_item:
  189.                     # 保存subitem的所有信息.
  190.                     e = SubItemEventArgs()
  191.                     e.cr = cr
  192.                     e.sub_item = sub_item
  193.                     e.double_items = self.__double_items
  194.                     e.motion_items = self.__motion_items
  195.                     e.single_items = self.__single_items
  196.                     e.item     = item
  197.                     e.text = sub_item.text
  198.                     e.text_color = sub_item.text_color
  199.                     e.x = rect.x + temp_item_w
  200.                     e.y = rect.y + ((row + start_index) * self.__items_padding_height) + self.__columns_padding_height
  201.                     e.w = column.width
  202.                     e.h = self.__items_padding_height
  203.                     e.sub_item_index = row + start_index
  204.                     temp_item_w += column.width
  205.                     #
  206.                     self.on_draw_sub_item(e)
  207.             # 保存绘制行的y坐标.
  208.             temp_item_h += self.__items_padding_height
  209.     ################################################
  210.     ## @ on_draw_column_heade : 连接头的重绘函数.
  211.     def __on_draw_column_heade_hd(self, e):
  212.         e.cr.set_source_rgba(0, 0, 0, 0.1)
  213.         e.cr.rectangle(e.x, e.y, e.w, e.h)
  214.         e.cr.fill()
  215.         if self.columns[len(self.columns)-1] == e.column:
  216.             e.cr.rectangle(e.x + e.w, e.y, self.allocation.width - e.x, e.h)
  217.             e.cr.fill()
  218.         # 画标题栏文本.
  219.         draw_text(e.cr,
  220.                   e.text,
  221.                   e.x, e.y, e.w, e.h,
  222.                   text_color=e.text_color,
  223.                   alignment=Text.CENTER)
  224.         #
  225.     @property
  226.     def on_draw_column_heade(self):
  227.         return self.__on_draw_column_heade
  228.     @on_draw_column_heade.setter
  229.     def on_draw_column_heade(self, hd):
  230.         self.__on_draw_column_heade = hd
  231.         self.on_queue_draw_area()
  232.     @on_draw_column_heade.getter
  233.     def on_draw_column_heade(self):
  234.         return self.__on_draw_column_heade
  235.     @on_draw_column_heade.deleter
  236.     def on_draw_column_heade(self):
  237.         del self.__on_draw_column_heade
  238.     ################################################
  239.     ## @ on_draw_item : 连. 当 owner_draw 设置为真的时候发生.
  240.     def __on_draw_item_hd(self, e):
  241.         #print "__on_draw_item_hd..."
  242.         pass
  243.     @property
  244.     def on_draw_item(self, e):
  245.         return self.__on_draw_item
  246.     @on_draw_item.setter
  247.     def on_draw_item(self, hd):
  248.         self.__on_draw_item =  hd
  249.         self.on_queue_draw_area()
  250.     @on_draw_item.getter
  251.     def on_draw_item(self):
  252.         return self.__on_draw_item
  253.     @on_draw_item.deleter
  254.     def on_draw_item(self):
  255.         del self.__on_draw_item
  256.     ################################################
  257.     ## @ on_draw_sub_item : 连.
  258.     def __on_draw_sub_item_hd(self, e):
  259.         if e.double_items == e.item:
  260.             e.text_color = "#0000ff"
  261.         elif e.single_items == e.item:
  262.             e.text_color = "#00FF00"
  263.         if e.motion_items == e.item:
  264.             e.text_color = "#FF0000"
  265.         e.draw_text(e.cr,
  266.                   e.text,
  267.                   e.x, e.y, e.w, e.h,
  268.                   text_color=e.text_color,
  269.                   alignment=Text.CENTER)
  270.         
  271.     @property
  272.     def on_draw_sub_item(self, e):
  273.         return self.__on_draw_sub_item
  274.     @on_draw_sub_item.setter
  275.     def on_draw_sub_item(self, hd):
  276.         self.__on_draw_sub_item =  hd
  277.         self.on_queue_draw_area()
  278.     @on_draw_sub_item.getter
  279.     def on_draw_sub_item(self):
  280.         return self.__on_draw_sub_item
  281.     @on_draw_sub_item.deleter
  282.     def on_draw_sub_item(self):
  283.         del self.__on_draw_sub_item
  284.     def __set_listview_size(self):
  285.         # 设置listview的高度和宽度.
  286.         rect = self.allocation
  287.         listview_height =  (len(self.items)) * self.__items_padding_height + self.__columns_padding_height
  288.         listview_width  =  188 # 额外添加 188 的宽度.
  289.         for column in self.columns:
  290.             listview_width += column.width
  291.         if (rect.height != listview_height) or (rect.width != listview_width):
  292.             self.set_size_request(listview_width, listview_height)
  293.     def __get_items_mouse_data(self, event):
  294.         offset_x, offset_y, viewport = get_offset_coordinate(self)
  295.         if self.__in_items_check(offset_y, event):
  296.             event_x = event.x # 获取鼠标x.
  297.             # 获取行号.
  298.             event_y_padding = int(event.y - self.__columns_padding_height)
  299.             row_index = event_y_padding / self.__items_padding_height
  300.             x_padding = 0
  301.             col_index = 0
  302.             # 获取行item,列的sub_items.
  303.             for column in self.columns:
  304.                 if x_padding <= int(event.x) <= x_padding + column.width:
  305.                     break
  306.                 x_padding += column.width
  307.                 col_index += 1
  308.             # 判断是否在可显示的列内.
  309.             if ((row_index < len(self.items)) and
  310.                 (col_index < len(self.items[row_index].sub_items))):
  311.                 return row_index, col_index
  312.             else:
  313.                 return row_index, None
  314.         else: # 鼠标点击不在区域内.
  315.             return None, None
  316.     def __in_items_check(self, offset_y, event):
  317.         start_y = (offset_y) + self.__columns_padding_height
  318.         end_y   = start_y + ((len(self.items)) * self.__items_padding_height)
  319.         return (start_y < event.y < end_y)
  320.     def __get_columns_mouse_data(self, event):
  321.         offset_x, offset_y, viewport = get_offset_coordinate(self)
  322.         if self.__in_columns_check(offset_y, event):
  323.             # 获取行item,列的sub_items.
  324.             x_padding = 0
  325.             col_index = 0
  326.             for column in self.columns:
  327.                 if x_padding <= int(event.x) <= x_padding + column.width:
  328.                     return col_index
  329.                 x_padding += column.width
  330.                 col_index += 1
  331.             return None
  332.     def __in_columns_check(self, offset_y, event):
  333.         start_y = offset_y
  334.         end_y   = start_y + self.__columns_padding_height
  335.         return (start_y < event.y < end_y)
  336.     # 设置每行的高度.
  337.     @property
  338.     def items_height(self):
  339.         return self.__items_padding_height
  340.    
  341.     @items_height.setter
  342.     def items_height(self, height):
  343.         self.__items_padding_height = height
  344.         self.on_queue_draw_area()
  345.     @items_height.getter
  346.     def items_height(self):
  347.         return self.__items_padding_height
  348.     @items_height.deleter
  349.     def items_height(self):
  350.         del self.__items_padding_height
  351.     # 设置标题头的高度.
  352.     @property
  353.     def columns_height(slef):
  354.         return self.__columns_padding_height
  355.     @columns_height.setter
  356.     def columns_height(self, height):
  357.         self.__columns_padding_height = height
  358.         self.on_queue_draw_area()
  359.     @columns_height.getter
  360.     def  columns_height(self):
  361.         return self.__columns_padding_height
  362.     @columns_height.deleter
  363.     def columns_height(self):
  364.         del self.__columns_padding_height
  365. class ItemEventArgs(object):
  366.     def __init__(self):
  367.         self.cr = None
  368.         self.select_items = []
  369.         # 鼠标的起点和结束点.
  370.         self.start_x = 0
  371.         self.start_y = 0
  372.         self.end_x   = 0
  373.         self.end_y   = 0
  374.         self.state   = 0 # 状态.
  375.         # item.
  376.         self.item    = None
  377.         # Bounds
  378.         self.x =  0
  379.         self.y =  0
  380.         self.w =  0
  381.         self.h =  0
  382. class SubItemEventArgs(object):
  383.     def __init__(self):
  384.         self.cr = None
  385.         self.item = None
  386.         self.sub_item = None
  387.         self.sub_item_index = None
  388.         self.double_items = None
  389.         self.motion_items = None
  390.         self.single_items = None
  391.         self.text = ""
  392.         self.text_color = "#000000"
  393.         self.text_align = Text.LEFT
  394.         self.draw_text = draw_text
  395.         self.x = 0
  396.         self.y = 0
  397.         self.w = 0
  398.         self.h = 0
  399. class ColumnHeaderEventArgs(object):
  400.     def __init__(self):
  401.         self.cr     = None
  402.         self.column = None
  403.         self.column_index = 0
  404.         self.text = ""
  405.         self.text_color = "#000000"
  406.         self.text_align = Text.LEFT
  407.         self.draw_text = draw_text
  408.         self.x = 0
  409.         self.y = 0
  410.         self.w = 0
  411.         self.h = 0
  412. if __name__ == "__main__":
  413.     def test_btn_clicked(widget):
  414.         #listview1.items.clear()
  415.         #listview1.columns[3].width += 5
  416.         #listview1.items.add_range([["微软", "男", "程序员", "美国"]])
  417.         #listview1.items[0].sub_items.add("fdjkf")
  418.         #listview1.items[0].sub_items[0].text = "我爱你,精灵..."
  419.         listview1.begin_update()
  420.         for i in range(0, 20000):
  421.             #listview1.items.add_insert(0, [[str(i), "男", "程序员", "美国" + str(i)]])
  422.             listview1.items.add_range([[str(i),
  423.                                         "男",
  424.                                         "程序员",
  425.                                         "美国" + str(i),
  426.                                         "你是" + str(i),
  427.                                         "#FF" + str(i),
  428.                                         "#ED" + str(i)]])
  429.         listview1.end_update()
  430.         
  431.     def listview1_test_on_draw_column_heade(e):
  432.         print "listview1_test_on_draw_column_heade.... 重绘标题头"
  433.     def listview1_test_on_draw_sub_item(e):
  434.         print "sub item..我来啦...O(∩_∩)O哈哈~..."
  435.     def test_listview_double_click(listview, double_items, row, col):
  436.         print double_items.sub_items[0], row, col
  437.         # 测试双击改变第一个文本.
  438.         #listview.items[row].sub_items[0].text = "明天"
  439.         # 测试删除双击下的items.
  440.         #listview.items.remove(double_items)
  441.         # 测试在指定位置插入items.
  442.         #listview.items.add_insert(row + 1, [["long", "fjdkf", "fjdkf"]])
  443.         # 测试改变标题头高度.
  444.         #listview.columns_height += 5
  445.     def test_listview_motion_notify(listview, motion_items, row, col):
  446.         if col == None:
  447.             col = 0
  448.         print motion_items.sub_items[col].text, row, col
  449.     def test_listview_single_click(listview, single_items, row, col):
  450.         print single_items.sub_items[0].text
  451.     win = gtk.Window(gtk.WINDOW_TOPLEVEL)
  452.     win.connect("destroy", lambda w : gtk.main_quit())
  453.     win.set_size_request(500, 500)
  454.     listview1 = ListView()
  455.     listview1.connect_event("double-click",  test_listview_double_click)
  456.     listview1.connect_event("motion-notify", test_listview_motion_notify)
  457.     listview1.connect_event("single-click",  test_listview_single_click)
  458.     #listview1.connect_event("
  459.     #listview1.items_height = 130
  460.     #listview1.columns_height = 150
  461.     # 连接主要绘制函数.
  462.     #listview1.on_draw_column_heade =  listview1_test_on_draw_column_heade
  463.     #listview1.on_draw_sub_item     =  listview1_test_on_draw_sub_item
  464.     listview1.columns.add("姓名")
  465.     listview1.columns.add_range(["性别", "职业", "国籍", "企业", "前景", "背景",
  466.                                  "性别", "职业", "国籍", "企业", "前景", "背景",
  467.                                  "性别", "职业", "国籍", "企业", "前景", "背景",
  468.                                 ])
  469.     listview1.items.add("皮卡丘")
  470.     listview1.items[0].sub_items.add("男")
  471.     listview1.items[0].sub_items.add("宠物")
  472.     listview1.items[0].sub_items.add("宠物国")
  473.     listview1.items.add_range([["张飞", "男", "武士", "蜀国"],
  474.                               ["孙策", "男", "骑士", "吴国", "aaa", "b", "c", "d", "f"]])
  475.     listview1.items.add_range([["求伯灿", "男", "程序员", "中国"],
  476.                               ["linus", "男", "内核开发", "荷兰"]])
  477.     #
  478.     scroll_win = gtk.ScrolledWindow()
  479.     scroll_win.add_with_viewport(listview1)
  480.     vbox = gtk.VBox()
  481.     test_btn = gtk.Button("test")
  482.     test_btn.connect("clicked",  test_btn_clicked)
  483.     vbox.pack_start(scroll_win, True, True)
  484.     vbox.pack_start(test_btn, False, False)
  485.     win.add(vbox)
  486.     win.show_all()
  487.     #
  488.     listview1.columns[0].width = 245
  489.     listview1.columns[2].width = 145
  490.     listview1.columns[2].text = "职位"
  491.     gtk.main()
Copy the Code
listview.py_002.png
listview.py_004.png

完全吸取了DEEPIN-UI和C#的优点.
已经分层.数据层是数据层... ....
换成QT或者其他界面库都没有什么事情.
后面要添加5中视图,这是第一种视图.
使用begin_update 防止连续重绘.
在进行大数据添加的时候,这个是需要的.
比如添加 100000 个items, 或者1000000000个items.这时只是数据在添加, 由数据层发送通知给控制层, 控制层再控制绘制层,来绘制出我们需要的东西.

visual python 的第一个控件.
Reply Favorite View the author
All Replies
a287740928
deepin
2013-03-26 20:05
#1
搞个控件外观图比较直观点,这个不懂啊
Reply View the author
vala2012
deepin
2013-03-26 21:29
#2
搞个控件外观图比较直观点,这个不懂啊


已经搞了图片了,
一直没有时间去给visual python造控件,
前几个月造了一个 时间控件, Timer.
现在差不多有空了,
要造一些常用的控件.
不用去set_text, get_text.. 感激没有必要, 直接text就好了.
listview.columns[0].text = "fjdskf" 这样就可以改变视图,非常方便,
不用再去添加 listview.queue_draw() 来进行重绘...

你感觉这样方便吗?
listview.columns[0].set_text("fjdskf")
print listview.columns[0].get_text()

width = listview.columns[0].get_width()
listview.columns[0].set_width(width + 10)

还是这样.
list.........text = "fjsdkf"
print listview..text
listview.columns[0].width += 10

重载
listview1.on_draw_column_heade =  listview1_test_on_draw_column_heade (这个是你写的函数)
listview1.on_draw_sub_item          =  listview1_test_on_draw_sub_item (这时是你写的函数)
你需要做的很简单.
对我给你的返回值,进行各种各样的自绘, 你想搞什么,都可以, 画进度条, 画选择框, 画BUTTON, 都可以.
Reply View the author
New Thread

Popular Events

More
国际排名
WHLUG