Python: Changing the select colour in a GtkTreeview - gtk3

I want to disable the selection colour at a treeview. So I want to set the selected color to white with modify_base. I found this solution, but it doesn't work. This is my code:
import gi
from gi.repository import Gdk, Gtk
gi.require_version('Gtk', '3.0')
treestore = InterfaceTreeStore()
treeview = Gtk.TreeView()
treeview.set_model(treestore)
treeview.modify_base(Gtk.StateFlags.SELECTED, Gdk.Color(red=65535, blue=65535, green=65535))

gtk_widget_modify_base has been deprecated since 3.0. You could have used gtk_widget_override_background_color, if it wasn't deprecated since 3.16. It's documentation states that:
If you wish to change the way a widget renders its background you should use a custom CSS style
However, if you want to disable selection color, the simpliest way is to unselect.
Your "changed" signal callback might look something like this:
def changed_cb(selection):
model, iter = get_selected (selection)
# if there is no selection, iter is None
if iter is None:
return
# do something useful
# now unselect
path = model.get_path(iter)
selection.unselect_path(path)
path.free() # not sure if python frees it automatically

Related

TreeView multiple selection does not work correctly after changing selection without UI

This is potentially a bug, though perhaps I'm misunderstanding something.
Brief description
Basically, I have found that using "Shift+Arrows" to do multiple selection in a Gtk.TreeView does not work correctly after changing the selection using Gtk.TreeSelection.select_iter. On the other hand, if you change the selection by clicking on a row and then pressing "Shift+Arrows", the selection behaves as one would expect.
I should note that if you change the selected row by calling Gtk.TreeSelection.select_iter, the UI updates as you would expect and calling Gtk.TreeSelection.get_selected_rows() returns the rows it should. It's only when you then try to select multiple rows using the arrow keys that you get strange behavior.
This is perhaps best illustrated in this self contained example, which I've tried to make as simple as possible:
Code
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class TreeViewBug(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.connect('destroy', Gtk.main_quit)
# Create model consisting of row path and a name
self.treeModel = Gtk.ListStore(int, str)
self.treeModel.append([0, 'alice'])
self.treeModel.append([1, 'bob'])
self.treeModel.append([2, 'chad'])
self.treeModel.append([3, 'dan'])
self.treeModel.append([4, 'emma'])
self.treeView = Gtk.TreeView()
self.treeView.append_column(Gtk.TreeViewColumn('path', Gtk.CellRendererText(), text=0))
self.treeView.append_column(Gtk.TreeViewColumn('name', Gtk.CellRendererText(), text=1))
self.treeView.set_model(self.treeModel)
# Allow for multiple selection
self.treeView.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
self.add(self.treeView)
def run(self):
self.show_all()
# Focus the TreeView so we can test multiple select via keyboard without clicking on a row
self.treeView.grab_focus()
# Manually change the selected row to the row with "chad"
chadIter = self.treeModel[2].iter
self.treeView.get_selection().select_iter(chadIter)
print('Press "Shift+Down" and see what happens')
print(' it should select "chad, dan", but instead it selects "bob, chad"')
print('Afterwards, try clicking on "chad" and then pressing Shift+Down. It should behave normally')
Gtk.main()
if __name__ == '__main__':
tv = TreeViewBug()
tv.run()
Things I've tried
I initially encountered the bug when my code changed the selected row via Gtk.TreeSelection.select_iter in response to a button click.
I've also tried:
adding a custom select function (Gtk.TreeSelection.set_select_function)
clearing the selection before changing it (Gtk.TreeSelection.unselect_all)
changing the selection asynchronously (GLib.idle_add).
redrawing TreeView after changing selection
Speculations
I'm guessing that TreeView/TreeViewSelection has some internal state variable tracking selection and row that, for some reason, isn't getting properly updated when TreeSelection.select_iter is called. These variables are probably related to UI features, because TreeSelection.get_selected_rows still works properly. Also it makes sense the UI would need additional state information since the UI logic of multiple selection depends on previous UI interaction (Shift+Down behaves differently when extending a selection depending on whether you initially selected upwards or downwards)
Because a Gtk.TreeView uses MVC, you actually need to set the cursor of the treeview. This may affect the rest of the program, depending on what you are doing. Example:
#chadIter = self.treeModel[2].iter
#self.treeView.get_selection().select_iter(chadIter)
path = 2
column = self.treeView.get_column(0)
edit = False
self.treeView.set_cursor(path, column, edit)

Change font face/size of the top GTKWindow?

I'm trying to use .NET Core GTK. For WinForms, we can select the form, and then click the Font property to change the font face or size within the Form designer. If we change the top form's font, it is applied to all the child controls on the form.
I wanted to do similar thing in Glade, but I cannot find a "Font" GUI in any of the attribute tabs.
Is this possible with GTK#?
If so, can it be done within Glade?
If the answer to 2 is no, can it be done in the code?
Yes this is possible in both GTK and Glade, although some code will be required to change all the forms font.
In GTK you will be using the GtkFontChooserWidget. This should let you choose between fonts.
In Glade, when you are using the attributes tab you are able to change font size with the Scale attribute. I haven't yet figured out how to change the actual font through those attributes yet. Thankfully there is a workaround. Instead of using Attributes, use Markup. Markup works just fine for both font size and font style.
Markup Example
<span font='36' face='Georgia'>Markup</span>
Assuming you are using a GtkComboBoxText to list possible fonts and button for selecting, you would just need a handler that would go through each of the labels and change the font to the designated one.
def when_visible(window):
"""
This is where per-window initialization takes place.
Values to be displayed are populated into their widgets.
"""
global FONT_FACE
name = Gtk.Buildable.get_name(window) # Window currently on
if 'font_select_screen' = name:
font = BUILDER.get_object('fontEntryCombo')
FONT_FACE = font.get_active_text()
elif 'random_screen' = name:
label1_text = "<span font='36' face='{}'>Label</span>".format(FONT_FACE)
label1 = BUILDER.get_object('label1')
label1.set_markup(label1_text)

Combining Glade XML with HeaderBar

I am a beginner to using Glade and PyGTK and I am trying to create a window with a custom title bar that is created using the header bar component and the rest of the UI being done through a GLADE file. However instead of getting one window I am getting two different windows, one containing the header bar and the other containing the UI components developed in Glade. Could someone point me as to how to make them appear in the same window. PFB the code that has been written so far :
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gio
class HeaderBarWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="MLPP")
self.set_border_width(10)
self.set_default_size(400, 200)
hb = Gtk.HeaderBar()
hb.set_show_close_button(True)
hb.props.title = "MLPP"
self.set_titlebar(hb)
titleBarImage = Gtk.Image()
titleBarImage.set_from_file('TitleIcon.png')
hb.pack_start(titleBarImage);
gladefile = "MLPP.glade"
builder = Gtk.Builder()
builder.add_from_file(gladefile)
self.add(builder.get_object("window1"))
win = HeaderBarWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
builder.add_from_file(gladefile)
self.add(builder.get_object("window1"))
Here you seem to get a "window" and add that to your intial Window. I guess you don't want to add the window defined in the Glade file, but one of its children. You probably have a Box or some other container defined. Try to get_object(box1) or however you identify your widget of desire.

Mac style joined buttons (segmented control) with Gtk

I've seen it done in the ubuntu software center, and with a few gnome apps.
Where two buttons look like a single rectangle with a line through it, how is this being done?
In GTK 3.0 and later, use the INLINE_TOOLBAR style class or LINKED style class.
#!/usr/bin/env python
from gi.repository import Gtk
button_names = [
Gtk.STOCK_ABOUT,
Gtk.STOCK_ADD,
Gtk.STOCK_REMOVE,
Gtk.STOCK_QUIT]
buttons = [Gtk.ToolButton.new_from_stock(name) for name in button_names]
toolbar = Gtk.Toolbar()
for button in buttons:
toolbar.insert(button, -1)
style_context = toolbar.get_style_context()
style_context.add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR)
window = Gtk.Window()
window.set_size_request(200, 50)
window.add(toolbar)
window.connect('delete-event', Gtk.main_quit)
window.show_all()
Gtk.main()
Fwiw, since I recently had the same question, here's another answer with an up-to-date citation and using C instead of some wrapper. (I use GTKmm, but I feel we should refer to the native C API unless a wrapper is explicitly stated.)
I wanted to achieve the same thing and eventually stumbled upon the answer, at the official page HowDoI: Buttons. This effect is achieved by putting the targeted Buttons in a Container and giving the latter the CSS class linked. (That page says using a Box is normal, but asBox will probably be deprecated soon and Grid is superior anyway... use a Grid.)
So:
GtkWidget *const grid = gtk_grid_new ();
GtkStyleContext *const context = gtk_widget_get_style_context (grid);
gtk_style_context_add_class (context, "linked");
/* Add your Buttons to the Grid */
That link also discusses some other handy embellishments we can make to GtkButtons, including the classes suggested-action and destructive-action.
For similar questions, it's very illustrative to browse the source of (A) an application that does what you want to replicate and (B) the Adwaita theme CSS.

Creating columns with editable cells in Gtk treeview using Glade

I am trying to create a simple GUI with table containing x and y coordinates of samples. I use treeview, and I want the cells of the table to be editable by user. Is it possible to specify if the cells should be editable directly in Glade in cellrenderer properties, or do I have to specify it in my code? I use Glade 3.6.1
I have just found out that unticking box "Editable" in the Tree View Editor when editing my treeview, enables me to specify whether the cells shall be editable or not, because if the box is unticked, the cells editable property is no longer connected with the model.
But if I run the program, cells are editable, but the value that I write inside disappears. How can I fix that? Why doesn't the cell store the value I type inside?
Thanks for any hint
For anyone dealing with a similar problem, I have solved it - whenever a cell is edited, appropriate record in the model needs to be changed, example code in Python:
cell.connect("edited", self.text_edited, model, column)
def text_edited( self, w, row, new_text, model, column)
model[row][column] = new_text
I found I had to do something just a little different, but I am also using Ubuntu's Quickly development environment. I did have to go into Glade and uncheck the "Editable" box in my cellrenderer, which then brought up a toggable "Yes/No" button. Then my code looks like:
#psuedo-code function definition
cellcolumn_widget.connect("edited", self.function, list_or_treestore, columnnumber)
#actual code, editing second column so column is passed as 1
self.builder.get_object("cellrenderer_chapter").connect("edited", self.cell_edited, self.builder.get_object("liststore_chapters"),1)
def cell_edited(self, widget, row, new_text, model, column):
model.set_value(model.get_iter(row),column,new_text)
for python GTK, by default, text in Gtk.CellRendererText widgets is not editable, you can change this by setting the value of the “editable” property to True:
renderer = Gtk.CellRendererText();
renderer.set_property("editable", True);
then you can connect to the “edited” signal and update your Gtk.TreeModel and/or database accordingly:
renderer.connect("edited", self.entry_edited);
def entry_edited(self, widget, path, text):
self.listStore[path][number_of_row] = text; # put the number_of_row to be edited
check this tutorial for more information python gtk 3 tutorial - CellRendererText