these are first few tries with python and I want to add 2 widgets to a gtk.
I know and saw that you can only add one at a time and already know how to do that.
can someone give me the loophole to be able to have also a "tree" and a right mouse click menu?
This is my code:
import gtk
class treeNode():
def __init__(self, father, name, link):
self.father = father
self.name = name
self.link = link
class PyApp(gtk.Window):
def __init__(self):
super(PyApp, self).__init__()
self.set_size_request(700, 500)
self.set_position(gtk.WIN_POS_CENTER)
self.connect("destroy", gtk.main_quit)
self.set_title("Assignment1")
eventbox = gtk.EventBox()
tree = gtk.TreeView()
trying = gtk.TreeViewColumn()
trying.set_title("Get Busy")
cell = gtk.CellRendererText()
trying.pack_start(cell, True)
trying.add_attribute(cell, "text", 0)
treestore = gtk.TreeStore(str)
father = None
name = ["default"]
node = treestore.append(father, name)
node = treeNode(father, name, node)
lst = [node]
father = lst[0].link
name = ["cluster1"]
node = treestore.append(father, name)
node = treeNode(father, name, node)
lst.append(node)
father = lst[1].link
name = ["clusterA"]
node = treestore.append(father, name)
node = treeNode(father, name, node)
lst.append(node)
father = lst[0].link
name = ["cluster2"]
node = treestore.append(father, name)
node = treeNode(father, name, node)
lst.append(node)
father = lst[3].link
name = ["clusterA"]
node = treestore.append(father, name)
node = treeNode(father, name, node)
lst.append(node)
tree.append_column(trying)
tree.set_model(treestore)
self.add(tree)
self.show_all()
self.menu = gtk.Menu()
addMenu = gtk.MenuItem("Add")
renManu = gtk.MenuItem("Rename")
remMenu = gtk.MenuItem("Remove")
self.menu.append(addMenu)
self.menu.append(renManu)
self.menu.append(remMenu)
eventbox.connect("button-release-event", self.menu_display)
self.add(eventbox)
self.show_all()
def menu_display(self, widget, event):
if event.button == 3:
self.menu.popup(None, None, None, event.button, event.time, None)
self.menu.show_all()
PyApp()
gtk.main()
Thanks a lot
Please try to write clear questions: "I want to add 2 widgets to a gtk" is not meaningful.
I'm going to assume you want to add multiple widgets into a Window (or some other Bin), is that right? You can't do that since a Bin can only have one child (as the runtime error message will tell you): instead you should add a suitable container widget -- like a VBox -- into the Window, and then add your widgets into the container widget.
Related
I have a RadioButtonWidget class that receives a list of names (button_list) and a QtWidgets.QGroupBox (radio_group_box) and creates a radio button for each name. The problem I have is that after creating the buttons, I cannot change them. That is if I call the class again with another list of names, nothing changes. I need to create a function inside my class to remove any existing radio buttons so that I can add a new list inside it.
I tried to do radio_group_box.deleteLater() outside the class but this removes the whole box.
class RadioButtonWidget(QtWidgets.QWidget):
def __init__(self, radio_group_box, button_list):
super().__init__()
self.radio_group_box = radio_group_box
self.radio_button_group = QtWidgets.QButtonGroup()
#create the radio buttons
self.radio_button_list = []
for each in button_list:
self.radio_button_list.append(QtWidgets.QRadioButton(each))
if button_list != []:
#set the default checked item
self.radio_button_list[0].setChecked(True)
#create layout for radio buttons and add them
self.radio_button_layout = QtWidgets.QVBoxLayout()
# add buttons to the layout and button group
counter = 1
for each in self.radio_button_list:
self.radio_button_layout.addWidget(each)
self.radio_button_group.addButton(each)
self.radio_button_group.setId(each,counter)
counter += 1
# add radio buttons to the group box
self.radio_group_box.setLayout(self.radio_button_layout)
def selected_button(self):
return self.radio_button_group.checkedId()
Instead of removing the radio buttons, you can create a whole new radio button layout and set it for the group box exactly as you did in the constructor. Here is an example where the function set_group_box_buttons will remove the existing layout from radio_group_box (which is done by setting it to a temp widget), and add a new one with the new buttons.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class RadioButtonWidget(QWidget):
def __init__(self, radio_group_box, button_list):
super().__init__()
self.radio_group_box = radio_group_box
self.set_group_box_buttons(button_list)
grid = QGridLayout(self)
grid.addWidget(self.radio_group_box)
def selected_button(self):
return self.radio_button_group.checkedId()
def set_group_box_buttons(self, button_list):
self.radio_button_group = QButtonGroup()
self.radio_button_list = [QRadioButton(x) for x in button_list]
if button_list:
self.radio_button_list[0].setChecked(True)
if self.radio_group_box.layout():
QWidget().setLayout(self.radio_group_box.layout())
self.radio_button_layout = QVBoxLayout()
for i, v in enumerate(self.radio_button_list):
self.radio_button_layout.addWidget(v)
self.radio_button_group.addButton(v)
self.radio_button_group.setId(v, i)
self.radio_group_box.setLayout(self.radio_button_layout)
class Template(QWidget):
def __init__(self):
super().__init__()
self.rbw = RadioButtonWidget(QGroupBox('Radio Buttons'), ['Radio 1', 'Radio 2', 'Radio 3'])
self.box = QLineEdit()
self.box.returnPressed.connect(self.replace_buttons)
grid = QGridLayout(self)
grid.addWidget(self.rbw, 0, 0)
grid.addWidget(self.box, 0, 1)
def replace_buttons(self):
self.rbw.set_group_box_buttons(self.box.text().split(', '))
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = Template()
gui.show()
sys.exit(app.exec_())
To demonstrate, I added a QLineEdit which will update the names when you press enter. Before:
After:
There's a conceptual error in your code: you are creating a new RadioButtonGroup, which is a widget, but you are not using it.
As long as each group box will only contain the radio buttons, there is no need to create a new widget (especially if you're not actually using it); you just have to create a layout if the groupbox doesn't have one yet.
There are at least two possible approaches to your question.
For both of them I always use existing radios if possible, to avoid unnecessary object destruction each time the options change, so that they are removed only when the number of options decreases. This also avoids unnecessary layout updates (especially if the number of options is the same).
I also kept the logical "interface" consistent, providing the same method and behavior of update_options(groupBox, options).
QObject based group
With this implementation, I'm creating an object that acts as an interface responsible of creating a QButtonGroup and setting the options, while also providing signals for the state change or the current checked radio.
class RadioButtonGroup(QtCore.QObject):
optionToggled = QtCore.pyqtSignal(object, int, bool)
optionChanged = QtCore.pyqtSignal(object, int)
def __init__(self, radio_group_box, button_list):
super().__init__()
self.groupBox = radio_group_box
layout = radio_group_box.layout()
self.buttonGroup = QtWidgets.QButtonGroup(self)
self.buttonGroup.buttonToggled[int, bool].connect(self.changed)
if layout is None:
layout = QtWidgets.QVBoxLayout(radio_group_box)
for i, text in enumerate(button_list, 1):
radio = QtWidgets.QRadioButton(text)
layout.addWidget(radio)
self.buttonGroup.addButton(radio, i)
def button(self, id):
return self.buttonGroup.button(id)
def changed(self, i, state):
self.optionToggled.emit(self, i, state)
if state:
self.optionChanged.emit(self, i)
def selected_button(self):
return self.buttonGroup.checkedId()
def update_options(self, button_list):
layout = self.groupBox.layout()
# this method will keep the current checked radio as checked, if you want
# to reset it everytime, just uncomment the next commented lines
#self.buttonGroup.setExclusive(False)
for i, text in enumerate(button_list, 1):
radio = self.buttonGroup.button(i)
if radio:
#radio.setChecked(False)
radio.setText(text)
else:
radio = QtWidgets.QRadioButton(text)
layout.addWidget(radio)
self.buttonGroup.addButton(radio, i)
#self.buttonGroup.setExclusive(True)
if len(button_list) == len(self.buttonGroup.buttons()):
return
# there are more radios than needed, remove them
for radio in self.buttonGroup.buttons():
id = self.buttonGroup.id(radio)
if id > i:
self.buttonGroup.removeButton(radio)
radio.deleteLater()
class ObjectBased(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('buttongroup.ui', self)
self.pushButton.clicked.connect(self.setOptions)
self.groupBoxes = self.groupBox1, self.groupBox2, self.groupBox3
self.radioButtonGroups = []
for box in self.groupBoxes:
group = RadioButtonGroup(box,
['Option {}'.format(o + 1) for o in range(randrange(1, 10))])
self.radioButtonGroups.append(group)
group.optionChanged.connect(self.optionChanged)
def setOptions(self):
buttonGroup = self.radioButtonGroups[self.comboBox.currentIndex()]
options = ['Option {}'.format(o + 1) for o in range(self.spinBox.value())]
buttonGroup.update_options(options)
def optionChanged(self, radioButtonGroup, id):
groupBox = radioButtonGroup.groupBox
print('{} checked {} ({})'.format(
groupBox.title(), id, radioButtonGroup.button(id).text()))
Self contained
In this mode, the logic is all within the window class. While this approach is slightly simpler than the other one, we're missing an unique "interface", which might be useful for access from external objects instead.
class SelfContained(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('buttongroup.ui', self)
self.pushButton.clicked.connect(self.setOptions)
self.radioButtonGroups = []
for g, groupBox in enumerate((self.groupBox1, self.groupBox2, self.groupBox3)):
buttonGroup = QtWidgets.QButtonGroup(self)
self.radioButtonGroups.append((groupBox, buttonGroup))
buttonGroup.buttonToggled[int, bool].connect(lambda id, state, g=g: self.optionChanged(g, id, state))
self.update_options(g, ['Option {}'.format(o + 1) for o in range(randrange(1, 10))])
def update_options(self, groupId, button_list):
groupBox, buttonGroup = self.radioButtonGroups[groupId]
layout = groupBox.layout()
if layout is None:
layout = QtWidgets.QVBoxLayout(groupBox)
# as above...
#buttonGroup.setExclusive(False)
for i, text in enumerate(button_list, 1):
radio = buttonGroup.button(i)
if radio:
#radio.setChecked(False)
radio.setText(text)
else:
radio = QtWidgets.QRadioButton(text)
layout.addWidget(radio)
buttonGroup.addButton(radio, i)
#buttonGroup.setExclusive(True)
if len(button_list) == len(buttonGroup.buttons()):
return
for radio in buttonGroup.buttons():
id = buttonGroup.id(radio)
if id > i:
buttonGroup.removeButton(radio)
radio.deleteLater()
def setOptions(self):
groupId = self.comboBox.currentIndex()
options = ['Option {}'.format(o + 1) for o in range(self.spinBox.value())]
self.update_options(groupId, options)
def optionChanged(self, groupId, id, state):
if state:
groupBox, buttonGroup = self.radioButtonGroups[groupId]
print('{} checked {} ({})'.format(groupBox.title(), id, buttonGroup.button(id).text()))
How can I collect all Qtreeview items so i can then iterate over them and apply necessary changes like display text updates, or color changes?
Is there an easy way to collect all of them using the 'match' method?
def get_checked(self):
model = self.treeview.model()
checked = model.match(
model.index(0, 0), QtCore.Qt.CheckStateRole,
QtCore.Qt.Checked, -1,
QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)
for index in checked:
item = model.itemFromIndex(index)
print(item.text())
test code:
from PySide import QtGui, QtCore
from PySide import QtSvg, QtXml
import sys
class Person:
def __init__(self, name="", children=None):
self.name = name
self.children = children if children else []
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.resize(300, 400)
self.init_ui()
def init_ui(self):
# Setup Tabs Widget
# self.treeview = QtGui.QTreeView()
self.treeview = QtGui.QTreeView()
self.treeview.setHeaderHidden(True)
self.treeview.setUniformRowHeights(True)
self.treeview.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.model = QtGui.QStandardItemModel()
self.treeview.setModel(self.model)
self.action = QtGui.QAction('Print', self)
self.action.setShortcut('F5')
self.action.triggered.connect(self.get_checked)
fileMenu = QtGui.QMenu("&File", self)
fileMenu.addAction(self.action)
self.menuBar().addMenu(fileMenu)
# Setup central widget
self.setCentralWidget(self.treeview)
# populate data
self.populate_people()
self.treeview.expandAll()
def populate_people(self):
parent = Person("Kevin", [
Person("Tom", [Person("Sally"), Person("Susan")]),
Person("Snappy", [Person("John"), Person("Kimmy"),
Person("Joe")]),
Person("Chester", [Person("Danny"), Person("Colleen")])
]
)
self.create_nodes(parent, self.model)
def create_nodes(self, node, parent):
tnode = QtGui.QStandardItem()
tnode.setCheckable(True)
tnode.setData(QtCore.Qt.Unchecked, role=QtCore.Qt.CheckStateRole)
tnode.setData(node.name , role=QtCore.Qt.DisplayRole)
tnode.setData(node, role=QtCore.Qt.UserRole) # store object on item
parent.appendRow(tnode)
for x in node.children:
self.create_nodes(x, tnode)
def get_checked(self):
print "collecting..."
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Here is a recursive solution (requires Python >= 3.3):
def iterItems(self, root):
def recurse(parent):
for row in range(parent.rowCount()):
for column in range(parent.columnCount()):
child = parent.child(row, column)
yield child
if child.hasChildren():
yield from recurse(child)
if root is not None:
yield from recurse(root)
Alternative recursive solution (for Python2/Python3):
def iterItems(self, root):
def recurse(parent):
if root is not None:
for row in range(parent.rowCount()):
for column in range(parent.columnCount()):
child = parent.child(row, column)
yield child
if child.hasChildren():
for item in recurse(child):
yield item
return recurse(root)
And here is an iterative solution (for Python2/Python3):
def iterItems(self, root):
if root is not None:
stack = [root]
while stack:
parent = stack.pop(0)
for row in range(parent.rowCount()):
for column in range(parent.columnCount()):
child = parent.child(row, column)
yield child
if child.hasChildren():
stack.append(child)
(NB: this solution gives a more predictable ordering, and is a little faster)
Usage:
root = self.treeview.model().invisibleRootItem()
for item in self.iterItems(root):
print(item.text())
The root argument can be any item in a QStandardItemModel.
I have created 2 trees with idlelib.TreeWidget in Canvas, left and right.
I am able to print out the name of a tree node if double-clicked, but what I need is double-clicking tree node ONLY from the left will print out messages.
Please run the following code (left tree is self.canvas, right is self.canvas2):
from Tkinter import Tk, Frame, BOTH, Canvas
from xml.dom.minidom import parseString
from idlelib.TreeWidget import TreeItem, TreeNode
class DomTreeItem(TreeItem):
def __init__(self, node):
self.node = node
def GetText(self):
node = self.node
if node.nodeType == node.ELEMENT_NODE:
return node.nodeName
elif node.nodeType == node.TEXT_NODE:
return node.nodeValue
def IsExpandable(self):
node = self.node
return node.hasChildNodes()
def GetSubList(self):
parent = self.node
children = parent.childNodes
prelist = [DomTreeItem(node) for node in children]
itemlist = [item for item in prelist if item.GetText().strip()]
return itemlist
def OnDoubleClick(self):
print self.node.nodeName
content = '''
<level0>
<level1/>
</level0>
'''
class Application(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.parent.geometry('%dx%d+%d+%d' % (800, 300, 0, 0))
self.parent.resizable(0, 0)
dom = parseString(content)
item = DomTreeItem(dom.documentElement)
self.canvas = Canvas(self, bg = "cyan")
self.canvas.grid(column = 0, row = 0, sticky = 'NSWE')
node = TreeNode(self.canvas, None, item)
node.update()
dom2 = parseString(content)
item2 = DomTreeItem(dom2.documentElement)
self.canvas2 = Canvas(self, bg = "yellow")
self.canvas2.grid(column = 1, row = 0, sticky = 'NSWE')
node2 = TreeNode(self.canvas2, None, item2)
node2.update()
self.pack(fill = BOTH, expand = True)
def main():
root = Tk()
Application(root)
root.mainloop()
if __name__ == '__main__':
main()
You just need to modify the DomTreeItem class to take an argument that determines if it should act on double-click or not:
class DomTreeItem(TreeItem):
def __init__(self, node, doubleclick=True): # set the value of double-click
self.node = node
self.doubleclick = doubleclick # make the value an instance variable
def GetText(self):
node = self.node
if node.nodeType == node.ELEMENT_NODE:
return node.nodeName
elif node.nodeType == node.TEXT_NODE:
return node.nodeValue
def IsExpandable(self):
node = self.node
return node.hasChildNodes()
def GetSubList(self):
parent = self.node
children = parent.childNodes
prelist = [DomTreeItem(node, self.doubleclick) for node in children] # pass it to the nodes
itemlist = [item for item in prelist if item.GetText().strip()]
return itemlist
def OnDoubleClick(self):
if self.doubleclick: # check if it's set to True
print self.node.nodeName # and only print it then
Then, when you make a new instance of the class, just set doubleclick to True or False. If you don't want a double-click to trigger on the second tree, instantiate it like this:
item2 = DomTreeItem(dom2.documentElement, doubleclick=False)
I have created 2 trees with idlelib.TreeWidget in Canvas, left and right.
I am also able to print out the name of a tree node if double-clicked, but what I need is double-clicking one tree node will make a certain tree node visible and selected.
I have a simple example here. If you double click "level1" on the left hand side, "ccc" on the right hand side should be visible and automatically selected. How do you do that?
Please run the following code:
from Tkinter import Tk, Frame, BOTH, Canvas
from xml.dom.minidom import parseString
from idlelib.TreeWidget import TreeItem, TreeNode
class DomTreeItem(TreeItem):
def __init__(self, node):
self.node = node
def GetText(self):
node = self.node
if node.nodeType == node.ELEMENT_NODE:
return node.nodeName
elif node.nodeType == node.TEXT_NODE:
return node.nodeValue
def IsExpandable(self):
node = self.node
return node.hasChildNodes()
def GetSubList(self):
parent = self.node
children = parent.childNodes
prelist = [DomTreeItem(node) for node in children]
itemlist = [item for item in prelist if item.GetText().strip()]
return itemlist
def OnDoubleClick(self):
print self.node.nodeName
left = '''
<level0>
<level1/>
</level0>
'''
right = '''
<aaa>
<bbb> <ccc/> </bbb>
</aaa>
'''
class Application(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.parent.geometry('%dx%d+%d+%d' % (800, 300, 0, 0))
self.parent.resizable(0, 0)
dom = parseString(left)
item = DomTreeItem(dom.documentElement)
self.canvas = Canvas(self, bg = "cyan")
self.canvas.grid(column = 0, row = 0, sticky = 'NSWE')
node = TreeNode(self.canvas, None, item)
node.update()
dom2 = parseString(right)
item2 = DomTreeItem(dom2.documentElement)
self.canvas2 = Canvas(self, bg = "yellow")
self.canvas2.grid(column = 1, row = 0, sticky = 'NSWE')
node2 = TreeNode(self.canvas2, None, item2)
node2.update()
self.pack(fill = BOTH, expand = True)
def main():
root = Tk()
Application(root)
root.mainloop()
if __name__ == '__main__':
main()
First, your double click callback must be aware of your TreeNode node2 (I can think of global variable, attribute in DomTreeItem or bounce to another component).
Then you can rely on expand() method of TreeNode, read the children attribute and expand sequentially until the element you want. Note that children attribute is only populated after the node has been expanded.
1. Quick answer
Quick and dirty solution for the example you have provided
class DomTreeItem(TreeItem):
def OnDoubleClick(self):
if self.GetText() == "level1":
node2.expand()
node2.children[0].expand()
node2.children[0].children[0].select()
[...]
class Application(Frame):
def __init__(self, parent):
global node2
2. Generic solution
Here is a more general method to display an arbitrary item in a tree.
def reach(node_tree, path):
tokens = path.split("/")
current_node = node_tree
for name in tokens:
if len(current_node.children) == 0 and current_node.state != "expanded":
current_node.expand()
candidates = [child for child in current_node.children if child.item.GetText() == name]
if len(candidates) == 0:
print("did not find '{}'".format(name))
return
current_node = candidates[0]
current_node.select()
You might use it this way
if self.GetText() == "level1":
reach(node2, "bbb/ccc")
3. Architecture proposal
Besides the expansion an selection of an item, I propose you a cleaner architecture through a DIY observer.
DIY Observer
(mimic the Tkinter bind call but does not rely on tkinter machinery since generating event with user data is not properly handled)
class DomTreeItem(TreeItem):
def __init__(self, node, dbl_click_bindings = None):
self.node = node
self.dbl_click_bindings = [] if (dbl_click_bindings == None) else dbl_click_bindings
[...]
def OnDoubleClick(self):
self.fireDblClick()
def bind(self, event, callback):
'''mimic tkinter bind
'''
if (event != "<<TreeDoubleClick>>"):
print("err...")
self.dbl_click_bindings.append(callback)
def fireDblClick(self):
for callback in self.dbl_click_bindings:
callback.double_click(self.GetText())
Dedicated component
Rely on the reach method presented above.
class TreeExpander:
def __init__(self, node_tree, matching_items):
self.node_tree = node_tree
self.matching_items = matching_items
def double_click(self, item_name):
print("double_click ({0})".format(item_name))
if (item_name in self.matching_items):
reach(self.node_tree, self.matching_items[item_name])
Subscription
class Application(Frame):
def __init__(self, parent):
[...]
expander = TreeExpander(node2, {
"level1": "bbb/ccc"
})
item.bind("<<TreeDoubleClick>>", expander)
I did not find docs for idlelib, in this case, you can try to look at the code. The following snippet allows you to find which file host this module.
import idlelib.TreeWidget
print(idlelib.TreeWidget.__file__)
I did a class that inserts a new tab whenever it is called with a notebook as argument. What I like to do is to associate an appropriate containt to this new tab. I thought that calling my class CreateTab with this widget as argument would be a good idea. But when I make:
>>> notebook.insert_page(treeview, hbox, 0)
I keep having this error:
Gtk-WARNING **: Can't set a parent on widget which has a parent
Clearly, what I would like to do is : whenever I click on a button from my main window, for example 'Fish button', it creates a new tab with my widget displaying 'all the fish from the sea'.
Here is my 'CreateTab' class:
class CreateTab():
def __init__(self, notebook, title):
self.notebook = notebook
self.pages = self.notebook.get_n_pages()
self.create_tab(title + str(self.pages))
self.notebook.set_current_page(self.pages)
def create_tab(self, title):
hbox = Gtk.HBox(False, 0)
label = Gtk.Label(title)
hbox.pack_start(label, True, True, 0)
pixbuf = Gtk.IconTheme.get_default().load_icon(Gtk.STOCK_CLOSE, 16,0)
image = Gtk.Image()
image.set_from_pixbuf(pixbuf)
btn = Gtk.Button()
btn.set_focus_on_click(False)
btn.add(image)
hbox.pack_start(btn, False, False, 0)
hbox.show_all()
#widget = Gtk.Label(title)
widget = Gtk.TreeView()
widget.show_all()
self.notebook.insert_page(widget, hbox,self.pages)
btn.connect('clicked', self.on_closetab_button_clicked, widget)
def on_closetab_button_clicked(self, sender, widget):
pagenum = self.notebook.page_num(widget)
self.notebook.remove_page(pagenum)
And for instance, the widget I'd like to associate :
class CellRendererTextWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="CellRendererText Example")
self.set_default_size(200, 200)
self.liststore = Gtk.ListStore(str, str)
self.liststore.append(["Fedora", "http://fedoraproject.org/"])
self.liststore.append(["Slackware", "http://www.slackware.com/"])
self.liststore.append(["Sidux", "http://sidux.com/"])
treeview = Gtk.TreeView(model=self.liststore)
renderer_text = Gtk.CellRendererText()
column_text = Gtk.TreeViewColumn("Text", renderer_text, text=0)
treeview.append_column(column_text)
renderer_editabletext = Gtk.CellRendererText()
renderer_editabletext.set_property("editable", True)
column_editabletext = Gtk.TreeViewColumn("Editable Text",
renderer_editabletext, text=1)
treeview.append_column(column_editabletext)
renderer_editabletext.connect("edited", self.text_edited)
self.add(treeview)
def text_edited(self, widget, path, text):
self.liststore[path][1] = text
I would be gratefull for any help or suggestion since I'm stuck in this for two days !
The solution I found is to call my class CreateTab with a tab name (str) and a class in argument in charge to create the content.
For example, from main.py, I launch the creation of a new tab called "Supplier's list":
CreateTab(title='Suppliers's list', Content=Suppliers)
From the class CreateTab, I create a VBox()
container = VBox()
and I launch Content with the new created VBox in argument.
Content(container)
So in Content (which can be whatever I want as Suppliers, Customers, Invoices...), I create all my widgets and I attach them in a grid. Here is a simplified Suppliers class:
class Suppliers(Gtk.Window):
def __init__(self, container):
liststore = Gtk.ListStore(int, str, str, str, str, int)
self.data = session.load_contacts({'type_contact': 'collab'})
for c in self.data:
row = ([c.id, c.nom, c.prenom, c.telephone, c.mail, c.actif])
liststore.append(row)
# creation of a treeview
treeview = Gtk.TreeView(model=liststore)
...
# creation of a ScrolledWindow to attach the treeview
scroll = Gtk.ScrolledWindow()
scroll.add(treeview)
# creation of a check button to filter the treeview
actif_btn = Gtk.CheckButton(label="Active suppliers")
actif_btn.connect('clicked', self.active_selected, liststore)
actif_btn.set_active(True)
# I create a grid to attach every thing
grid = Gtk.Grid()
grid.add(actif_btn)
# I attach every thing to the initial container
container.pack_start(grid, False, False, 10)
container.pack_start(scroll, True, True, 0)
container.show_all()
I hope this will help someone.
I wonder if I can do the same with a window imported from a glade file.