在Gtk + 3上,我使用TreeModel
来存储嵌套信息,并使用CellRendererText
和CellRendererToggle
进行显示。用户可以在每个切换按钮上进行clic,当有嵌套按钮并且它们不处于相同状态时,我希望上层的按钮反映“不一致”状态。如何为 一个元素 ?
为了更清晰,我希望从Transmission bittorrent客户端实现的示例:
我知道如何将单元格渲染器的所有按钮设置为与myCellRendererToggle.set_properties(inconsistent=True)
不一致的状态,但似乎我无法从此处访问单个元素;
我知道如何访问TreeStore模型的特定行,但我只能设置«True»和«False»值。
我的代码非常接近官方文档,因此您可以帮助我:https://python-gtk-3-tutorial.readthedocs.org/en/latest/cellrenderers.html#cellrenderertoggle(我使用treeStore而不是listStore)
这是我的代码:
class HelloMyApp:
def __init__(self):
# Set the Glade file
self.builder = Gtk.Builder()
self.builder.add_from_file(GLADEFILE)
dic = {
"on_button1_clicked" : self.btnValidate_clicked,
"on_MainWindow_destroy" : self.quit,
"on_window1_delete_event" : self.quit,
}
self.builder.connect_signals(dic)
window = self.builder.get_object("window1")
treeview1 = self.builder.get_object("treeview1")
######## This is my model : it stores a string and a boolean. #########
self.treeModel = Gtk.TreeStore(str, bool)
# Example on how to insert data in the model
treeIter = self.treeModel.append(None, ['example one', True])
self.treeModel.append(treeIter, [' simple elt', True])
treeIter = self.treeModel.append(treeIter, ['example two', False])
self.treeModel.append(treeIter, ['under example two', True])
select = treeview1.get_selection()
select.set_mode(Gtk.SelectionMode.BROWSE)
select.connect("changed", self.on_tree_selection_changed, buf)
# Using one column of text and another column with the toggle buttons
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Title", renderer, text=0)
treeview1.append_column(column)
###### Here is the CellRendereToggle ################
renderer_toggle = Gtk.CellRendererToggle()
renderer_toggle.connect("toggled", self.on_cell_toggled)
column_toggle = Gtk.TreeViewColumn("Installer", renderer_toggle, active=1)
treeview1.append_column(column_toggle)
treeview1.set_model(self.treeModel)
window.show_all()
if __name__ == "__main__":
HelloMyApp = HelloMyApp()
Gtk.main()
谢谢!
编辑:回答Marcus :我无法理解,当我在函数内部更改CellRendererToggle的属性时,它会更改每一行。
编辑解决方案:正如Marcu指出的那样,我们必须在每种情况下设置属性,这就是我添加else
部分的原因。
def cellRenderer_func(column, cellRenderer, treeModel, treeIter, userData):
if 'cat' in treeModel.get_value(treeIter, 0):
# it happens only ones in my model,
# so here I am in a row I want to change to inconsistent.
cellRenderer.set_property('inconsistent',True)
# I was expecting that changes the box of that row but it affects every row.
else:
cellRenderer.set_property('inconsistent', False) # and that's ok now.
我必须再试一次。 我想知道......我们真的必须手动完成它,它不是一个开箱即用的树视图功能吗?
答案 0 :(得分:4)
可以通过使用单元格数据功能设置一个元素的属性。由于我只在C中完成了这个,我只能传递给PyGTK文档的链接,我还没有看到PyGObject的这个特性的相关文档。
对于PyGTK已记录here,this页面底部给出了一个示例,PyGTK的单元数据函数的使用也在this文档中。
例如,如果您想在传输中执行相同操作,则可以执行以下操作: 由于您将当前iter作为单元格数据函数的参数接收,因此您可以遍历其中的所有子项并检查子项的状态。然后,您将知道在父节点上设置哪个状态。现在要说的是,在单元数据函数中设置属性只会影响这个单元格,而不会影响树视图的所有元素。
我还可以为您自己的应用程序提供一个可视化示例:
我在此树视图中有“值”列。如果“菜单元素”列中的值设置为“已启用”且“类型”列中的值为“选项”,则会显示一个复选框而不是文本(我突出显示了这样的行)。示例图像还显示活动搜索,突出显示搜索结果。两者都可以使用单元格数据函数来设置您在问题中要求的一个元素的属性。
修改强>
我已经完成了一些示例代码。重点是始终为每个单元格设置单元格属性。所以不仅仅是“if ...,然后设置属性”而是“if,设置这样的属性,否则,设置属性就是这样”。 (它基于旧的PyGTK文档,但它应该澄清事情。)
#!/usr/bin/env python
# example basictreeview.py
import pygtk
pygtk.require('2.0')
import gtk
class BasicTreeViewExample:
def set_status(self, column, cell, model, iter):
if 'inconsistent' in model.get_value(iter, 0):
cell.set_property('inconsistent',True)
else:
cell.set_property('inconsistent',False)
return
def delete_event(self, widget, event, data=None):
gtk.main_quit()
return False
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title("Basic TreeView Example")
self.window.set_size_request(200, 200)
self.window.connect("delete_event", self.delete_event)
self.treestore = gtk.TreeStore(str)
for parent in range(4):
piter = self.treestore.append(None, ['parent %i' % parent])
for child in range(3):
if child == 1:
self.treestore.append(piter, ['consistent'])
else:
self.treestore.append(piter, ['inconsistent'])
self.treeview = gtk.TreeView(self.treestore)
self.tvcolumn0 = gtk.TreeViewColumn('Column 0')
self.tvcolumn1 = gtk.TreeViewColumn('Column 1')
self.treeview.append_column(self.tvcolumn0)
self.treeview.append_column(self.tvcolumn1)
self.text = gtk.CellRendererText()
self.toggle = gtk.CellRendererToggle()
self.tvcolumn0.pack_start(self.text, True)
self.tvcolumn1.pack_start(self.toggle, True)
self.tvcolumn0.add_attribute(self.text, 'text', 0)
self.tvcolumn1.set_cell_data_func(self.toggle, self.set_status)
self.window.add(self.treeview)
self.window.show_all()
def main():
gtk.main()
if __name__ == "__main__":
tvexample = BasicTreeViewExample()
main()
答案 1 :(得分:1)
我最近遇到了同样的问题,如果您希望直接从模型中的列设置属性,则不需要单元数据功能。来自问题的代码中所需的更新应该如下:
self.treeModel = Gtk.TreeStore(str, bool, bool)
...
column_toggle = Gtk.TreeViewColumn("Installer", renderer_toggle, active=1, inconsistent=2)
然后根据需要在新列中设置不一致的值。
作为关于何时在模型中选择单元格数据函数或新列的提示,请考虑以下因素(Gtk+ By Example):
每次要渲染该(渲染器)列中的单元格时,都会调用您的单元格数据函数。如果您使用过该功能,请查看该功能在该程序中的调用频率。如果你在单元格数据函数中执行耗时的操作,事情就不会很快,特别是如果你有很多行。