I have the following code in pygtk:
....
rendererText = gtk.CellRendererText()
self.columns["hour"] = gtk.TreeViewColumn("Uur", rendererText, text=0)
self.columns["hour"].set_sort_column_id(0)
self.treeview.append_column(self.columns["hour"])
self.columnControls["ond"] = gtk.CellRendererToggle()
self.columns["ond"] = gtk.TreeViewColumn("ond", self.columnControls["ond"], active=1)
self.columns["ond"].set_sort_column_id(1)
self.treeview.append_column(self.columns["ond"])
....
So, I'd personally expect that if I click the checkbox that appears in the column entrys would be "togglable", but it isn't. Is this because of my OS (Mac OS X 10.8), or is there some kind of property I forgot to set?
You have to bind a callback function, which may reverse the value in that GtkListStore/GtkTreeStore, to toggled signal. Like this:
def on_cellrenderertoggle_toggled(self, cellrenderertoggle, path):
# self.liststore is the tree modal of that treeview
self.liststore[path][1] = not self.liststore[path][1]
A full tutorial can be found here: http://python-gtk-3-tutorial.readthedocs.org/en/latest/cellrenderers.html#cellrenderertoggle
Related
GTK ComboBox has style property "arrow-size" (link). I want to set it to 0.
Unfortunately next snippet doesn't work. No error messages reported and arrow appears in default size (=15)
import pygtk
pygtk.require('2.0')
import gtk
def the_dialog():
dialog = gtk.Dialog("Title", None, gtk.DIALOG_MODAL)
liststore = gtk.ListStore(str)
for a in ["one","two","three"]:
liststore.append([a])
rc_str = """
style 'no_arrow_style' {
GtkComboBox::arrow-size = 0
}
widget_class '*' style 'no_arrow_style'
"""
gtk.rc_parse_string(rc_str)
combo_box = gtk.ComboBox()
cell = gtk.CellRendererText()
combo_box.pack_start(cell)
combo_box.add_attribute(cell, 'text', 0)
combo_box.set_model(liststore)
combo_box.get_cells()
dialog.vbox.pack_start(combo_box)
dialog.show_all()
dialog.run()
the_dialog()
Combo box with default "v"-shaped arrow:
GtkComboBox::arrow-size actually means "minimum arrow size". To see the difference set it to 100. The example snippet did work.
So I'm grabbing links of events off a website and putting them into a drop down menu to be selected. My code for the menu:
import Tkinter as tk
from Tkinter import StringVar
selectMenu = tk.Tk()
# #-> this is what I have
# Followed by what you can use
#var = Vars()
#events = var.GetVars('Event')
events = " "
options = []
links = []
#forms = (driver.find_elements_by_class_name("with-cats")) #This is what I have
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
for x in forms:
#info = x.text
info = x #Again, this is so you can try it for yourself
if events in info.lower():
links.append(x)
for link in range(0,len(links)):
#options.append(links[link].text)
options.append(links[link])
list(set(options))
selection = []
for link in range(0,len(options)):
selection.append(options[link])
select = StringVar(selectMenu)
select.set("--None Selected--")
menu = tk.OptionMenu(selectMenu, select, *(selection))
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menu.pack(side="top", pady=10)
selectMenu.attributes('-topmost', True)
selectMenu.mainloop()
So this works fine and dandy, but I would like to improve the look to make it more obvious which events are open. To clarify, an event found that is open and put into the menu may look like "This is a cool event", but one that is closed would be read as "This is a cool event Closed". My aim is to be able to make the foreground red of either just the word Closed or the string containing Closed, whichever is possible if any (And I'm not sure if it's possible because menus and buttons on osx are usually defaulted to system settings, maybe there is a way around this?).
Current: Desired:
According to the documentation for OptionMenu here and here I don't think there is a way to set the color of text.
You might be able to get something close to what you want by using a listBox instead. See post here for the listBox example.
Found a solution! Using a Menu inside of a MenuButton the same way Tkinter creates MenuOptions, I was able to create a custom MenuOption. If you want to add more options, you can use the menbutton.configure() option to edit the button, and menbutton.menu to edit the menu items.
import Tkinter as tk
from Tkinter import Menu, Menubutton
class Vars():
global vari
vari = {}
def GetVars(self, var):
return vari.get(str(var))
def SendVars(self, var, val):
vari[str(var)] = val
class App():
def buttselect(self, link, menbutton, selectMenu):
var = Vars()
var.SendVars("Selection", link) # Store selected event
menbutton.configure(text=link) # Set menu text to the selected event
def prnt(self, link):
var = Vars()
print var.GetVars("Selection") # Print event
def __init__(self, selectMenu):
events = " "
options = []
links = []
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
menbutton = Menubutton (selectMenu, text="--None Selected--", relief="raised")
menbutton.grid()
menbutton.menu = Menu (menbutton, tearoff=0)
menbutton["menu"] = menbutton.menu
#Get a list of event names
for x in forms:
info = x #Again, this is so you can try it for yourself
#If desired event keyword is in an event name, add it to the correct links
if events in info.lower():
links.append(x)
#Remove duplicates
for link in range(0,len(links)):
options.append(links[link])
list(set(options))
#Final list of event names turned into menu commands
for link in options:
if "Closed" in link:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu), foreground='red')
else:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu))
b = tk.Button(selectMenu, text="Selection", command= lambda link=link: self.prnt(link)) #Print selected event
b.pack()
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menbutton.pack(side="top", pady=10)
selectMenu = tk.Tk()
selectMenu.attributes('-topmost', True)
app = App(selectMenu)
selectMenu.mainloop()
This results in exactly the result desired:
I found a way!
Let's say x is an optionmenu with options:
options=['Red','Blue','Green']
defopt=tk.StringVar(options[0]) #StringVariable to hold the selected option.
x=tk.OptionMenu(self.optmenuframe,defopt,*options)
Now, get the menu object from the optionmenu and use entryconfig method. That's it!
x.children['menu'].entryconfig(0,foreground='red')
x.children['menu'].entryconfig(1,foreground='blue')
x.children['menu'].entryconfig(2,foreground='green')
#0 is the index of the option you want to apply the configurations to.
Used: python 2.79, gtk 2.0
Dear python and PyGtk-users
In my program I want to give the opportunity to show searchresults of a great datafile in a gtk.TreeView using the method in the code. In the function that creates the ListStore I also create the csv-file the store is using. Now I can see, that the csv-file has changed after a new search with different keywords, but the TreeView does not, it still keeps the result of the first search, though I clear the store everytime self.search is running. It's really enerving if you need to restart the program for every new search...
I already tried some things, like creating a proper function for the datacreatin for the store, but nothing serves and the truth is that I don't have a lot of ideas...
And everything I found in the internet about this was about autorefreshing of the store with a timer or other topics more profound, seems like everyone instead of me knows how to do this...
Can anyone tell me, what mistake I am making? How do I refresh a TreeView?(as you can see self.search is called by a button...) here the relevant part of the code:
import gtk, csv
class BASE:
#...
#some other funtions, irrelevant for the problem
#...
def search(self, widget, event, data=None):
#...
#all the searchingstuff and the creation of 'inwrite.csv'
#...
with open('/home/emil/Documents/inwrite.csv', 'r') as storefile:
lines = storefile.readlines()
store = gtk.ListStore(str, str, str, str, str, str)
store.clear()
i=0
while i < len(lines):
line = [lines[i]]
csvfile = csv.reader(line, delimiter=',')
for row in csvfile:
temp = (row[0], row[1], row[2], row[3], row[4], row[5])
store.append(temp)
i = i + 1
self.tabview = gtk.TreeView(store)
self.tabview.set_rules_hint(True)
self.tabview.set_reorderable(True)
self.sw.add(self.tabview)
self.tabview.show()
self.create_columns(self.tabview)
def __init__(self):
#...
#creating the Window, entries,...
#...
self.button1 = gtk.Button('Buscar')
self.button1.connect('clicked', self.search, 'button 1')
#...
#packing and showing the whole GUI
#...
def create_columns(self, tabview):
rendererText = gtk.CellRendererText()
rendererText.props.wrap_width = 80
rendererText.props.wrap_mode = gtk.WRAP_WORD
column = gtk.TreeViewColumn('Codigo', rendererText, text=0)
column.set_sort_column_id(0)
self.tabview.append_column(column)
#...
#creating 5 more columns by the same principle
#...
def main(self):
gtk.main()
if __name__=='__main__':
base = BASE()
run = base
run.main()
thanks for your help, tell me if you need more information!
I do not know what is exactly wrong with your program (if you want to know that, you should provide a working minimal example).
Nevertheless, you do not need to manually update the TreeView because the TreeView always shows the content of the ListStore or TreeStore. You also do not have to create the ListStore everytime. You can create it one time and clear and insert the new entries when the event is emitted.
Here is a small example that shows how it works:
#from gi.repository import Gtk # uncomment to use PyGObject
import gtk as Gtk
class TestCase:
def __init__(self):
win = Gtk.Window()
button = Gtk.Button('Show')
button.connect('clicked', self.on_button_clicked)
self.clicked = 0
self.liststore = Gtk.ListStore(int)
self.liststore.append((self.clicked,))
view = Gtk.TreeView(self.liststore)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn('demo', renderer, text=0)
view.append_column(column)
box = Gtk.HBox()
box.pack_start(button, True, True, 0)
box.pack_start(view, True, True, 0)
win.add(box)
win.connect('delete-event', Gtk.main_quit)
win.show_all()
def on_button_clicked(self, button):
self.clicked += 1
self.liststore.clear()
self.liststore.append((self.clicked,))
if __name__ == "__main__":
TestCase()
Gtk.main()
It also seems that you first create your csv file and read it afterwards. I don't know about the rest of your program but it is probably better to use the data directly and insert it into the ListStore and not read it from the csv file. It might be even possible then to just remove and insert the new entries and not clear the whole ListStore and insert everything again. That would be more efficient with bigger amounts of data.
I want to implement a feature which will allow user to navigate in Gtk.TreeView widget by arrow keys, unfortunately select_iter() method is not doing what I was expecting from it, i. e. it fails to select parent node of selected node :P
And now I need explanation why it's not working or hint on some kind of workaround of this issue.
Below is ready to run test program which demonstrates this problem. Problematic line of code is tagged with #FIXME.
from gi.repository import Gtk
from gi.repository import Gdk
class WizardManager(Gtk.Dialog):
'''Dialog window which makes possible to choose type of resource to create by editor.'''
def __init__(self, parent):
super().__init__('Wizard manager', parent, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT)
self.set_default_response(Gtk.ResponseType.OK)
self.set_decorated(False)
self.set_size_request(640, 480)
vbox = self.get_content_area()
self.__tree_store = Gtk.TreeStore(str)
self.__tree_view = Gtk.TreeView(self.__tree_store)
self.__tree_view.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
self.__tree_view.connect('key-press-event', self.__on_tree_view_key_press)
self.__tree_view.set_headers_visible(False)
text_renderer = Gtk.CellRendererText()
text_column1 = Gtk.TreeViewColumn(None, text_renderer)
text_column1.add_attribute(text_renderer, 'text', 0)
self.__tree_view.append_column(text_column1)
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.add(self.__tree_view)
vbox.pack_start(scrolled_window, True, True, 0)
self.__populate_tree_store()
self.show_all()
def __on_tree_view_key_press(self, tree_view, event):
# TODO Implement tree navigation with arrow keys
tree_selection = tree_view.get_selection()
selected_iter = tree_selection.get_selected()[1]
if selected_iter:
selected_tree_path = self.__tree_store.get_path(selected_iter)
# Right arrow and Return should expand selected node.
if event.keyval == Gdk.KEY_Right or event.keyval == Gdk.KEY_Return:
tree_view.expand_row(selected_tree_path, False)
# Left arrow should collapse node or select it parent.
elif event.keyval == Gdk.KEY_Left:
if not tree_view.collapse_row(selected_tree_path):
# Unable to collapse node it must be empty. select it's parent.
parent_iter = selected_iter.copy()
if self.__tree_store.iter_parent(parent_iter):
# FIXME Why select_iter() executes without error and is not able to select parent node?
# same goes for select_path() :P
tree_selection.select_iter(parent_iter)
def __populate_tree_store(self):
# Ordinary resources
self.__tree_store.append(None, ('File',))
self.__tree_store.append(None, ('Directory',))
# Python files
python_dir = self.__tree_store.append(None, ('Python',))
self.__tree_store.append(python_dir, ('Python module',))
self.__tree_store.append(python_dir, ('Python package',))
# Django files
django_dir = self.__tree_store.append(python_dir, ('Django',))
self.__tree_store.append(django_dir, ('Django project',))
self.__tree_store.append(django_dir, ('Django app',))
if __name__ == '__main__':
app = Gtk.Window(Gtk.WindowType.TOPLEVEL)
app.connect('destroy', lambda a: Gtk.main_quit())
dlg = WizardManager(app)
dlg.run()
dlg.destroy()
Gtk.main()
Here you have a hint!
#! /usr/bin/python
###########################################################
#
# Basic Gtk.TreeView Example with two sortable columns
#
###########################################################
# use the new PyGObject binding
from gi.repository import Gtk
import os
import getpass # this is only to automatically print your home folder.
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='My Window Title')
self.connect('delete-event', Gtk.main_quit)
# Gtk.ListStore will hold data for the TreeView
# Only the first two columns will be displayed
# The third one is for sorting file sizes as numbers
store = Gtk.ListStore(str, str, long)
# Get the data - see below
self.populate_store(store)
treeview = Gtk.TreeView(model=store)
# The first TreeView column displays the data from
# the first ListStore column (text=0), which contains
# file names
renderer_1 = Gtk.CellRendererText()
column_1 = Gtk.TreeViewColumn('File Name', renderer_1, text=0)
# Calling set_sort_column_id makes the treeViewColumn sortable
# by clicking on its header. The column is sorted by
# the ListStore column index passed to it
# (in this case 0 - the first ListStore column)
column_1.set_sort_column_id(0)
treeview.append_column(column_1)
# xalign=1 right-aligns the file sizes in the second column
renderer_2 = Gtk.CellRendererText(xalign=1)
# text=1 pulls the data from the second ListStore column
# which contains filesizes in bytes formatted as strings
# with thousand separators
column_2 = Gtk.TreeViewColumn('Size in bytes', renderer_2, text=1)
# Mak the Treeview column sortable by the third ListStore column
# which contains the actual file sizes
column_2.set_sort_column_id(1)
treeview.append_column(column_2)
# Use ScrolledWindow to make the TreeView scrollable
# Otherwise the TreeView would expand to show all items
# Only allow vertical scrollbar
scrolled_window = Gtk.ScrolledWindow()
scrolled_window.set_policy(
Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
scrolled_window.add(treeview)
scrolled_window.set_min_content_height(200)
self.add(scrolled_window)
self.show_all()
def populate_store(self, store):
directory = '/home/'+getpass.getuser()
for filename in os.listdir(directory):
size = os.path.getsize(os.path.join(directory, filename))
# the second element is displayed in the second TreeView column
# but that column is sorted by the third element
# so the file sizes are sorted as numbers, not as strings
store.append([filename, '{0:,}'.format(size), size])
# The main part:
win = MyWindow()
Gtk.main()
I need to store items in a Gtk TreeView and when interacting with this TreeView, the user will can select one or more items in the list.
Because I'm new to GTK, I managed to populate the treeview and display a checkbox as the code below shows. But when I try to select, nothing happens and I do not know how to make this possible.
This is my Code:
# the column is created
renderer_products = gtk.CellRendererText()
column_products = gtk.TreeViewColumn("Products", renderer_products, text=0)
# and it is appended to the treeview
view.append_column(column_products)
# the column checkbox is created
renderer_checkbox = gtk.CellRendererToggle()
column_checkbox = gtk.TreeViewColumn("Selected", renderer_checkbox, text=0)
# and it is appended to the treeview
view.append_column(column_checkbox)
If you want to select the whole row and something happen:
#double click or not double click use
Gtk.TreeView.set_activate_on_single_click (bool)
#connect the treeview
treeview.connect ("row-activated", on_row_activate)
#inside the callback
def on_row_activate (treeview, path, column):
model = treeview.get_model ()
iter = treeview.get_iter (path)
yourdata = model[iter][model_index]
#do whatever with yourdata
If you want when you click the toggle and something happen:
#connect the renderer
renderer_checkbox.connect ("toggled", on_selected_toggled)
#inside the callback
def on_selected_toggled (renderer, path):
#modify the model or get the value or whatever