python gui tkinter用法杂记

1.treeview 遍历

iids = tree.selection()
    t = tree.get_children()
    for i in t:
        print(tree.item(i,'values'))

 

2. 如何将 ttk treeview 的某一行转入编辑状态

   事实上,(python 3)treeview 有一个 readonly 属性。但我用的是 python 2。

   解决方案:在双击 treeview 时根据鼠标的位置定位单元格,然后在此单元格里面贴入一个 Entry 控件即可。

def on_detail_bom_line_db_click(self, event):
        ''' Executed, when a row is double-clicked. Opens
        read-only EntryPopup above the item's column, so it is possible
        to select text '''
    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> close previous popups</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> self.entryPopup:
        self.entryPopup.destroy()

    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> what row and column was clicked on</span>
rowid = self.bom_lines.identify_row(event.y) column = self.bom_lines.identify_column(event.x)
    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> clicked row parent id</span>
    parent =<span style="color: rgba(0, 0, 0, 1)"> self.bom_lines.parent(rowid)
    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">print 'parent:'+parent</span>
    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> do nothing if item is top-level</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> parent == <span style="color: rgba(128, 0, 0, 1)">''</span><span style="color: rgba(0, 0, 0, 1)">:
        </span><span style="color: rgba(0, 0, 255, 1)">pass</span>

    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> get column position info</span>
    x,y,width,height =<span style="color: rgba(0, 0, 0, 1)"> self.bom_lines.bbox(rowid, column)

    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> y-axis offset</span>
    pady = height // 2

    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> place Entry popup properly</span>
    url = self.bom_lines.item(rowid, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">text</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

    self.entryPopup </span>= StickyEntry(self.bom_lines, url, width=12<span style="color: rgba(0, 0, 0, 1)">)
    self.entryPopup.place( x</span>=x, y=y+pady, anchor=W)</pre>

扩展了 Entry,添加了一点点行为:

class StickyEntry(Entry):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, parent, text, **<span style="color: rgba(0, 0, 0, 1)">kw):

    </span><span style="color: rgba(128, 0, 0, 1)">'''</span><span style="color: rgba(128, 0, 0, 1)"> If relwidth is set, then width is ignored </span><span style="color: rgba(128, 0, 0, 1)">'''</span>

    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">fa = super(self,StickyEntry)</span>

    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">fa.__init__(parent, **kw)</span>
apply(Entry.__init__, (self, parent), kw)
    self.insert(0, text)

    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">self['state'] = 'readonly'</span>
self['readonlybackground'] = 'white'
    self[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">selectbackground</span><span style="color: rgba(128, 0, 0, 1)">'</span>] = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">#1BA1E2</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">

    self[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">exportselection</span><span style="color: rgba(128, 0, 0, 1)">'</span>] =<span style="color: rgba(0, 0, 0, 1)"> False



    self.focus_force()

    self.bind(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&lt;Control-a&gt;</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, self.selectAll)

    self.bind(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&lt;Escape&gt;</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">lambda</span> *<span style="color: rgba(0, 0, 0, 1)">ignore: self.destroy())



</span><span style="color: rgba(0, 0, 255, 1)">def</span> selectAll(self, *<span style="color: rgba(0, 0, 0, 1)">ignore):

    </span><span style="color: rgba(128, 0, 0, 1)">'''</span><span style="color: rgba(128, 0, 0, 1)"> Set selection on the whole text </span><span style="color: rgba(128, 0, 0, 1)">'''</span><span style="color: rgba(0, 0, 0, 1)">

    self.selection_range(0, </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">end</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)



    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> returns 'break' to interrupt default key-bindings</span>

    <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">break</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>

3. treeview 的 heigth 属性咋回事?

   比如设置为 60(pixels),结果抛出屏幕很多。 原因是这个是行数!!!

 

4. Entry 的 width 似乎也不是像素为单位的!

   随便设置一个数字,比如 20,能有 200pixel 或者更多的效果。

   经过验证,似乎是数字字符的个数(比如 20,就刚好能放 20 个数字字符!)

   具体以什么字符为基准未知!

 

5. 如何给 ttk treeview 设置竖直滚动条?

   添加一个 Srollbar 控件,并将其 set 函数丢给 treeview 的 yscrollcommand 进行绑定。

   注意布局,Scrollbar 控件最好紧挨着 treeview,并且在右边。

vbar = ttk.ScrollBar(container, orient=VERTICAL, command = your_treeview.yview)

your_treeview.configure(yscrollcomand=vbar.set)

your_treeview.grid(row=0)

vbar.grid(row=0, column=1,sticky=NS)

6. 如何将 ttk treeview 中的内容清空?

调用其 delete 方法,如下:

items = your_treeview.get_children()

[your_treeview.delete(item) for item in items]

7. 如何得到 ttk treeview 被双击的单元格的值?

  获取单元格的值,使用 treeview 的 get 函数即可,参数 (row, column) , row-- iid , column - index of column (started with '#')

  理论上讲,只通过控件是无解的。通过自己定义坐标边界的方式来解决,即给每一列定义宽度(像素单位)。event.x/y 能够取到坐标。在分析此坐标落在哪一列的坐标范围内即可分析出。

def get_cell_value(self, event, tree=None, col_widths=None):
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">

获取ttk treeview某一个单元格的值(在鼠标事件中)

:param event:

:param tree:

:param col_widths:

:return:

</span><span style="color: rgba(128, 0, 0, 1)">"""</span>

<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> tree:

    tree </span>=<span style="color: rgba(0, 0, 0, 1)"> self.bom_lines

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> col_widths:

    col_widths</span>=<span style="color: rgba(0, 0, 0, 1)">self.form_bom_line_widths

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> isinstance(event,Event):

    </span><span style="color: rgba(0, 0, 255, 1)">raise</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">event must type of Tkinter.Event</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

x</span>=<span style="color: rgba(0, 0, 0, 1)"> event.x

y</span>=<span style="color: rgba(0, 0, 0, 1)"> event.y

row </span>=<span style="color: rgba(0, 0, 0, 1)"> tree.identify_row(y)

vals </span>= tree.item(row, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">values</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

index </span>= -1

<span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(len(col_widths)):

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> x&gt;=<span style="color: rgba(0, 0, 0, 1)">0:

        x</span>-=<span style="color: rgba(0, 0, 0, 1)">col_widths[i]

    </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">:

        index</span>=i-1

        <span style="color: rgba(0, 0, 255, 1)">break</span>

<span style="color: rgba(0, 0, 255, 1)">if</span> index!=-1<span style="color: rgba(0, 0, 0, 1)">:

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> vals[index]

</span><span style="color: rgba(0, 0, 255, 1)">return</span> False</pre>

后记:实际上是本人疏忽,有一个 identify_column 的函数可以用来根据 x 的值定位具体的列。因此上述代码属于重复造轮子。

your_treeview.identify_column(event.x)

8. 如何设置 ttk treeview 中某一个单元格的值?

 跟上面一样,通过 event.x 的所在区间得到列的 index,然后调用 treeview 的set 方法即可。代码如下:

def set_cell_value(self, event, value, tree=None, col_widths=None):
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">

设置ttk treeview某一个单元格的值(在鼠标事件中)

:param event:

:param value:要设置的值

:param tree:

:param col_widths:

:return:

</span><span style="color: rgba(128, 0, 0, 1)">"""</span>

<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> tree:

    tree </span>=<span style="color: rgba(0, 0, 0, 1)"> self.bom_lines

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> col_widths:

    col_widths</span>=<span style="color: rgba(0, 0, 0, 1)">self.form_bom_line_widths

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> isinstance(event,Event):

    </span><span style="color: rgba(0, 0, 255, 1)">raise</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">event must type of Tkinter.Event</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

x</span>=<span style="color: rgba(0, 0, 0, 1)"> event.x

y</span>=<span style="color: rgba(0, 0, 0, 1)"> event.y

row </span>=<span style="color: rgba(0, 0, 0, 1)"> tree.identify_row(y)

index </span>= -1

<span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(len(col_widths)):

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> x&gt;=<span style="color: rgba(0, 0, 0, 1)">0:

        x</span>-=<span style="color: rgba(0, 0, 0, 1)">col_widths[i]

    </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">:

        index</span>=i-1

        <span style="color: rgba(0, 0, 255, 1)">break</span>

<span style="color: rgba(0, 0, 255, 1)">if</span> index!=-1<span style="color: rgba(0, 0, 0, 1)">:

    tree.set(row,column</span>=index,value=<span style="color: rgba(0, 0, 0, 1)">value)

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> True

</span><span style="color: rgba(0, 0, 255, 1)">return</span> False</pre>

9. Entry 如何设置选中文本的背景色?

比如设置为红色(警示作用)

#choice 1:Entry 的子类的 __init__ 方法中

self['selectbackground']='red'

#choice 2:Entry 实例 ent

ent.config(selectbackground
='red')

10. ttk treeview 的样式设定

  奇数行背景浅蓝色。有一个问题,就是选中了奇数行后,其背景色不变!暂时未破解。

def brush_treeview(self, tv):
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">

改变treeview样式

:param tv:

:return:

</span><span style="color: rgba(128, 0, 0, 1)">"""</span>

<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> isinstance(tv, ttk.Treeview):

    </span><span style="color: rgba(0, 0, 255, 1)">raise</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">argument tv of method bursh_treeview must be instance of ttk.TreeView</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">=============给bom_lines设置样式=====</span>
items = tv.get_children()
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(len(items)):

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> i%2==1<span style="color: rgba(0, 0, 0, 1)">:

        tv.item(items[i], tags</span>=(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">oddrow</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">))

tv.tag_configure(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">oddrow</span><span style="color: rgba(128, 0, 0, 1)">'</span>, background=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">#eeeeff</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>

TAG OPTIONS

  1. -foreground
  2. -background
  3. -font
  4. -image

11. 如何通过鼠标的滚轮控制 scrollbar 的滚动?

默认情况下,是没有这种关联的。

似乎 tk 框架中没法处理。此问题先放着。

 

12. 如何绑定数据到下拉框,并能够进行数据的模糊搜索定位?

可以使用 ttk 的 Combobox, 对其进行事件绑定(比如 Return 事件),demo 如下:

self.cb_product_id.bind('<Return>', self.on_search_product_id)

实际处理:

def on_search_product_id(self,event):
product_no </span>=<span style="color: rgba(0, 0, 0, 1)"> self.cb_product_id.get()

res </span>= self.bom.product_search(condition=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name_template ilike '%%</span><span style="color: rgba(128, 0, 0, 1)">"</span>+product_no+<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%%' </span><span style="color: rgba(128, 0, 0, 1)">"</span>, limit=20<span style="color: rgba(0, 0, 0, 1)"> )

self.cb_product_id[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">values</span><span style="color: rgba(128, 0, 0, 1)">'</span>]=[x[1] <span style="color: rgba(0, 0, 255, 1)">for</span> x <span style="color: rgba(0, 0, 255, 1)">in</span> res]</pre>

有一个问题就是,这个 values 只有 text,通常 web 的 selection 都会有 (value,text) 这样的组合,这里有些小不足。弥补的方法就是继承 Combobox,如下:

class NewCBox(ttk.Combobox):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, master, dictionary={}, *args, **<span style="color: rgba(0, 0, 0, 1)">kw):

    ttk.Combobox.</span><span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, master, values = sorted(list(dictionary.keys())),  *args, **<span style="color: rgba(0, 0, 0, 1)">kw)

    self.dictionary </span>=<span style="color: rgba(0, 0, 0, 1)"> dictionary

    self.bind(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">&lt;&lt;ComboboxSelected&gt;&gt;</span><span style="color: rgba(128, 0, 0, 1)">'</span>, self.selected) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">purely for testing purposes</span>



<span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> set_dict(self, dictionary):

    self.dictionary</span>=<span style="color: rgba(0, 0, 0, 1)">dictionary

    self[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">values</span><span style="color: rgba(128, 0, 0, 1)">'</span>]=<span style="color: rgba(0, 0, 0, 1)"> sorted(list(dictionary.keys()))



</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> value(self):

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> self.dictionary[self.get()]



</span><span style="color: rgba(0, 0, 255, 1)">def</span> selected(self, event): <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">Just to test</span>

    <span style="color: rgba(0, 0, 255, 1)">print</span>(self.value())</pre>

13. 如何用代码打开 Combobox 的列表?

 demo 代码,引用自这里。原理:直接丢事件,使用event_generate 函数。

 

from Tkinter import *

import ttk

root = Tk()

c = ttk.Combobox(root)

c.pack()

c['values'] = ['1','2','3']

def dropdown():

c.event_generate(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">&lt;Button-1&gt;</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

b = Button(root, text='test', command=dropdown)

b.pack()

root.mainloop()

14. 如何将两个长度相同的 list 用一句代码合成一个 dict?

my_dict = dict(list(zip(list1,list2)))

其中 list1 将作为 key,list2 将作为 value

即使用 zip 压缩为元组 (key,value),然后用 dict 生成字典。

 

15. 如何实现 Combobox 的 onchange 事件的处理?

通过 <<ComboboxSelected>> 事件来处理,如下代码:

your_combobox.bind('<<ComboboxSelected>>',your_select)

def your_select(event):

</span><span style="color: rgba(0, 0, 255, 1)">pass</span></pre>

16. 如何设置 Combobox 的默认选项?

使用 Combobox 的 current 函数即可,如下:

default_index=0

your_combobox.current(default_index)

17. 如何通过代码选中 Combobox 中输入的所有文本,通过 Control + A 键组合。

entry 可以通过 selection_range(0, 'end') 实现。combobox 是没有这个操作支持的。只能够曲线救国了。

通过选择对应的选项来实现。尝试以下代码无果而终。此问题先放着。

my_combobox.bind('<Control-a>', select_all_input)

def select_all_input(self,event):

</span><span style="color: rgba(0, 0, 255, 1)">print</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Ctrl+A</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">

text </span>=<span style="color: rgba(0, 0, 0, 1)"> self.get()

vals </span>= self.cget(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">values</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(len(vals)):

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> vals[i]==<span style="color: rgba(0, 0, 0, 1)">text:

        self.current(i)</span></pre>

18. 默认全部展开 ttk treeview 的节点,该如何实现?

treeview.item("Main", open=False)

即直接修改每个 item 的 open 选项。通过 treeview.tv.event_generate("<<TreeviewOpen>>") 是没有作用的。

def expand_tree(self, tv, root_id):
iids </span>=<span style="color: rgba(0, 0, 0, 1)"> tv.get_children(root_id)

</span><span style="color: rgba(0, 0, 255, 1)">for</span> iid <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> iids:

    tv.item(iid,open</span>=<span style="color: rgba(0, 0, 0, 1)">True)

    self.expand_tree(tv, iid)</span></pre>

19. 如何实现其他键盘事件? 

ctrl+f/g 等等。直接绑定就好,语法如下:

<Control-key> , 其中 key 就是相应的字符。例如 ctrl+f 的绑定如下:

your_treeview.bind('<Control-f>', find_something)

20. 如何实现弹出式的输入框?

没有现成的控件,做一个就好了。以下是一个搜索框:

class PopupEntry:
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, parent=None,default_value=<span style="color: rgba(128, 0, 0, 1)">''</span>, callback=<span style="color: rgba(0, 0, 0, 1)">None):

    self.callback </span>=<span style="color: rgba(0, 0, 0, 1)"> callback

    self.top </span>=<span style="color: rgba(0, 0, 0, 1)"> Toplevel(parent)

    Label(self.top, text</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">请输入:</span><span style="color: rgba(128, 0, 0, 1)">"</span>).grid(row=<span style="color: rgba(0, 0, 0, 1)">0)

    self.e </span>=<span style="color: rgba(0, 0, 0, 1)"> Entry(self.top)

    self.e.grid(row</span>=0,column=1<span style="color: rgba(0, 0, 0, 1)">)

    Button(self.top, text</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">确定</span><span style="color: rgba(128, 0, 0, 1)">"</span>, command=self.ok).grid(row=1<span style="color: rgba(0, 0, 0, 1)">)

    Button(self.top, text</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">取消</span><span style="color: rgba(128, 0, 0, 1)">"</span>, command=self.top.destroy).grid(row=1,column=1<span style="color: rgba(0, 0, 0, 1)">)

    self.</span><span style="color: rgba(128, 0, 128, 1)">__set</span><span style="color: rgba(0, 0, 0, 1)">(default_value)

    self.e.bind(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">&lt;Double-1&gt;</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(0, 0, 255, 1)">lambda</span> *<span style="color: rgba(0, 0, 0, 1)">args:self.e.delete(0,END))

    self.e.bind(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">&lt;Return&gt;</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">, self.on_return)

    self.top.maxsize(</span>200,60<span style="color: rgba(0, 0, 0, 1)">)

    self.top.resizable(False,False)

    self.top.title(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">搜索</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)



</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> on_return(self,event):

    self.ok()



</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> ok(self):

    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">print "value is", self.e.get()</span>

    <span style="color: rgba(0, 0, 255, 1)">if</span> self.callback <span style="color: rgba(0, 0, 255, 1)">and</span><span style="color: rgba(0, 0, 0, 1)"> callable(self.callback):

        self.callback(self.e.get())

    self.top.destroy()</span></pre>

关于窗口的细节控制,发现了一个不错的资源。这里

 

21. 弹出的 TopLevel 窗口如何设置焦点?

这里有解答。即调用grab_set不过这个方案貌似在 win7 下面不起作用。

解决方案:TopLevel 里面的控件调用 focus 方法。比如,输入框

your_entry.focus()

22. 如何选中 ttk treeview 的多行数据?

tree_view.selection_set(items)

注意,items 是 iids,即以 I 开头的行的 id 编码的元组。

 

23. 如何设置右键菜单?

context_menu = Menu(self.tv, tearoff=0)

context_menu.add_command(label="复制", command=copy_handler)

some_widget.bind('<3>', show_context_menu)

def show_context_menu(event):

context_menu.post(event.x_root,event.y_root)

def copy_handler():

</span><span style="color: rgba(0, 0, 255, 1)">pass</span></pre>

24. 如何用 python 操作剪贴板?

https://pypi.python.org/pypi/clipboard/

import clipboard

clipboard.copy("abc") # now the clipboard content will be string "abc"

text
= clipboard.paste() # text will have the content of clipboard

需要安装额外的包,原生貌似不支持。

在 windows 上还有一个方法,参考这里。在我的机器上会报错。暂时不折腾,避免安装多余的包。

 

25. 如何改变 Label 的值?

your_label['text']='new value'# or 

your_label.configure(text='new value')

26. 如何定位到 ttk treeview 的某行?

使用 treeview 的 yview_moveto 函数,yview_moveto(fraction)

fraction ,float 类型, [0~1.0]。例如定位到最后一行,如下:

your_Treeview.yview_moveto(1.0)

27. 如何在右键菜单中添加分隔符?

your_menu.add_seperator()

28. 如何设置 checkbutton 的 checked 属性?

要设置 variable 属性,那么窗体类中需要记录这个属性。如果有多个 checkbox,那么必须有多个类变量类记录他们。

这样很不 pythonic。好吧,把它扩展下,如下:

class NewCBtn(Checkbutton):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, master,*args, **<span style="color: rgba(0, 0, 0, 1)">kw):

    self.value </span>=<span style="color: rgba(0, 0, 0, 1)"> IntVar()

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span> kw:kw={<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">variable</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">:self.value}

    </span><span style="color: rgba(0, 0, 255, 1)">else</span>:kw.update({<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">variable</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">:self.value})

    Checkbutton.</span><span style="color: rgba(128, 0, 128, 1)">__init__</span>(self,master,*args,**<span style="color: rgba(0, 0, 0, 1)">kw)



</span><span style="color: rgba(0, 0, 255, 1)">def</span> checked(self,value=<span style="color: rgba(0, 0, 0, 1)">None):

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> value <span style="color: rgba(0, 0, 255, 1)">is</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> None:

        self.value.set(value </span><span style="color: rgba(0, 0, 255, 1)">and</span> 1 <span style="color: rgba(0, 0, 255, 1)">or</span><span style="color: rgba(0, 0, 0, 1)"> 0)

    </span><span style="color: rgba(0, 0, 255, 1)">return</span> self.value.get()</pre>

29. 如何删除 Text 中的文本?

很诡秘的写法:

your_text.delete("1.0",END)

而 Entry 中如此删除:

your_entry.delete(0,END)

所以 Text 的删除有点火星人的作风。

 

29. 为何以下逻辑进入第一个分支?

from Tkinter import *

root = Tk()

b = Combobox(root)

if isinstance(ctrl,Entry):

</span><span style="color: rgba(0, 0, 255, 1)">print</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Entry</span><span style="color: rgba(128, 0, 0, 1)">"</span>

elif isinstance(ctrl,Combobox):

</span><span style="color: rgba(0, 0, 255, 1)">print</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Combobox</span><span style="color: rgba(128, 0, 0, 1)">"</span>

else:

</span><span style="color: rgba(0, 0, 255, 1)">print</span> unkown</pre>

因为 Combobox 是 Entry 的子类。所以对于有继承关系的判断分支,孙子应该放在最前面,防止被父亲或者祖父给短路了。

 

30. tk 中图像的处理?

常规方法是用 Label, 设置其 image 属性。由于涉及到了变量(图片)的生命周期问题,因而把它封装为一个类,如下:

class NewImage(Label):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, master=None,image_path=r<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">nullImage.png</span><span style="color: rgba(128, 0, 0, 1)">'</span>, cnf={}, **<span style="color: rgba(0, 0, 0, 1)">kw):

    image </span>=<span style="color: rgba(0, 0, 0, 1)"> Image.open(image_path)

    self.default_image </span>=<span style="color: rgba(0, 0, 0, 1)"> ImageTk.PhotoImage(image)

    self.current_image </span>=<span style="color: rgba(0, 0, 0, 1)"> self.default_image

    Label.</span><span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, image=self.current_image, master=master, cnf=cnf,**<span style="color: rgba(0, 0, 0, 1)">kw)



</span><span style="color: rgba(0, 0, 255, 1)">def</span> Image(self,base64_source=None,encoding=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">base64</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">):

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span> base64_source <span style="color: rgba(0, 0, 255, 1)">is</span><span style="color: rgba(0, 0, 0, 1)"> None:

        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> base64_source:

            base64_source </span>= resize_img(base64_source,size=(100,100<span style="color: rgba(0, 0, 0, 1)">))

            image_stream </span>=<span style="color: rgba(0, 0, 0, 1)"> io.BytesIO(base64_source.decode(encoding))

            image </span>=<span style="color: rgba(0, 0, 0, 1)"> Image.open(image_stream)

            self.current_image </span>=<span style="color: rgba(0, 0, 0, 1)">ImageTk.PhotoImage(image)

            self[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">image</span><span style="color: rgba(128, 0, 0, 1)">'</span>]=<span style="color: rgba(0, 0, 0, 1)">self.current_image

        </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">:

            self[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">image</span><span style="color: rgba(128, 0, 0, 1)">'</span>]=<span style="color: rgba(0, 0, 0, 1)">self.default_image

    </span><span style="color: rgba(0, 0, 255, 1)">return</span> self[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">image</span><span style="color: rgba(128, 0, 0, 1)">'</span>]</pre>

31. 如何禁止窗口最大化?

对于窗体来说,有一个 resizable 方法,接受两个参数 (x_resizable,y_resizable),分别表示横向和纵向是否可以拉伸。

 

32. 如何设置 Label 的字体颜色?

foreground  -- fg (字体颜色, 前景色)

background -- bg(底色,背景色)

例如设置蓝色,如下:

Label(text='your_label', fg='blue').pack()

33. 如何设置 Label 的字体?

import tkFont

...

ft1 = tkFont.Font(family = 'Fixdsys',size = 10,weight = tkFont.BOLD)

Label(f, text=u'产品编号 (*)', fg='blue', font=ft1).grid(row=1,column=1, sticky=W)

Fixdsys 表示系统字体

 

34. 如何获取控件相对于屏幕的坐标?

ctrl.winfo_rootx()/winfo_rooty()

例如,entry

my_entry.winfo_rootx()

得到的就是 my_entry 这个输入框的左上角的 x 坐标(相对于屏幕)

相对于父容器,则用

ctrl.winfo_x()/winfo_y()

 

35. 如何隐藏窗口的标题栏?

只对 Toplevel 有效,使用其 overrideredirect 方法。

demo 代码:

from Tkinter import *

root = Tk()

top = Toplevel(root)

top.overrideredirect(True)

root.mainloop()

36. ttk treeview 如何隐藏几列?如何设置隐藏的列的值?如何设置显示的列的值?

隐藏:

  在构造函数里面有一个参数 displaycolumns=['c1','c2',...,'cn'],设置显示的列。 columns=['c1','c2',...,'cm'] 设置所有的列 (m>n)。

那么 n+1 ~ m 都是隐藏的列。

设置隐藏列的值:

  没有直接的函数,只能通过 treeview.item(iid, values=new_value_list) 来设置所有列的值(包括隐藏列)

设置显示列的值:

      有一个 set 函数, treeview.set(row,column,value)

      

37. ttk treeview 如何隐藏第一列?

     构造函数里面的选项 show=['headings'] 即可。

38. 如何隐藏指定行?

   暂时无解。

39. 如何得到 treeview 中被选中的行?

通过 selection 方法而不是 selection_get 方法,即:

your_treeview.selection()

这样得到的是一个 iid 的 list。

 

40. treeview.delete?

删除多个元素时以下写法会报错,莫名其妙

iids = your_treeview.selection()

your_treeview.delete(iids)

错误信息,iids 中的 item 无法找到,而只能按照上述记录6的方式进行。

 

41. 如何用模拟 treeview 的单击事件?

比如单击某一行。

your_treeview.event_generate('<1>',x=1,y=1)

x=1,y=1 为鼠标单击的坐标,根据具体情况而定。event_generate 的 **kw 参数可以接受以下值:

-when, -above, -borderwidth, -button, -count, -data, -delta, -detail, -focus, -height, -keycode, -keysym, -mode, -override, -place, -root, -rootx, -rooty, -sendevent, -serial, -state, -subwindow, -time, -warp, -width, -window, -x, or -y

 

 42. 如何中断事件链?

比如 treeview 的 <1> 时间后,紧接着是 <<TreeviewSelected>>。

Combobox 的键盘事件后,还有其他事件阻止 Ctrl-A 实现全选的效果。

执行到一个事件,同时不需要再执行后面的事件,可以返回 'break' 进行中断,如下:

def some_event(self,event):
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">do something</span>

<span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">break</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>

43. 如何 disable 右键菜单里面的某个命令?

使用 mehu 的 entryconfigure 方法,demo 如下:

from Tkinter import *

root = Tk()

#panel = Frame(root)

#panel.pack()

m
= Menu(root,tearoff=0)

m.add_command(label='test1')

m.add_command(label='test2')

def context_menu(event):

m.post(event.x,event.y)

root.geometry("400x400+0+0")

root.bind('<3>',context_menu)

m.entryconfigure(1,state='disabled')

root.mainloop()

44. 如何遍历 Menu 的菜单项?

暂时无解。

 

45. 如何打开一个选择文件对话框?

详细资料参考这里。主要使用 tkFileDialog 模块的 askopenfilename 方法。demo 如下:

# -*- coding: CP936 -*-

from Tkinter import *

from tkFileDialog import *

root = Tk()

filename=askopenfilename(parent = root)

print filename

root.mainloop()