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

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)

Related

Tabulator column.setWidth() not saving to history

I have a headerMenu dropdown to "show" and "hide" columns, and persistence is set to true. When I manually resize the columns the new width is persistent, but it is not when using the dropdown (the column does resize, however, it just doesn't stay that way on the next reload). I noticed that the columnResized callback is also not triggered by my code.
var headerMenu = [
{
label:"Hide Column",
action:function(e, column){
column.setWidth(40);
}
},
Am I missing something here? How do I get this to work and be persistent?
This is the correct behaviour, and fairly standard across a range of table functions and callbacks
Both the callback and the persistence module only track user interaction with the table. This allows maximum flexibility for the developer to call additional functions on the table with out interfering with the direct user experience.
In your case you appear to be trying to hide a column by changing its width? there is a hide function you can call on a column to hide it, if that is what y0u are attempting.
column.hide()

Bokeh - How to use box tool without default selections?

I have built a bokeh app that allows users to select windows in data and run python code to find and label (with markers) extreme values within these limits. For ease of interaction, I use the box select tool for the range selection. My problem arises when repeating this process for subsequent cases. After markers are placed for the results, they are rendered invisible by setting alpha to zero and another case needs to be chosen. When the new select box includes previous markers, they become visible based on the selection. How do I override this default behavior? Can markers be made unselectable? or can I add code to the customJS to hide them after they are selected?
Thanks in advance for any help!
There are a few possible approaches. If you just want non-selected glyphs to "disappear" visually, you can set a policy to do that as described here:
http://docs.bokeh.org/en/latest/docs/user_guide/styling.html#selected-and-unselected-glyphs
Basically, for bokeh.plotting, pass
nonselection_fill_alpha=0.0,
nonselection_line_alpha=0.0,
as arguments to your plot.circle call or whatever. Or if you are using the low level bokeh.models interface, something like:
renderer.nonselection_glyph = Circle(fill_alpha=0.0, line_alpha=0.0)
But be aware (I think you already are) that the invisible markers are still there, and still selectable if the user happens to draw a box over them with the selection tool.
If you truly want only a subset of the data to be visible and selectable after a selection, I'd say you want to replace the data in the column data source wholesale with the subset in your selection callback.

Display checkbox inside a listbox

In my (programmatic) Matlab GUI, I have a listbox uicontrol.
What I want is to display checkboxes in front of each option. When a user clicks the checkbox, it's marked (and the element will be considered during the calculations later). While if the user clicks the label, a description of the selected option will be displayed in a text uicontrol to inform the user what the option means.
Basically, I want functionality similar to installation programs where you can select components to install and can get information about said components by clicking them (which does not necessarily mark them as selected).
Is there a way to do this with checkboxes or something similar?
There are actually 2 built-in controls that you could use within Matlab:
com.jidesoft.swing.CheckboxList
com.mathworks.mwswing.checkboxlist.CheckBoxList
Usage example (more details in my Matlab-Java book):
jList = java.util.ArrayList; % any java.util.List will be ok
jList.add(0,'First');
jList.add(1,'Second');
jList.add(2,'Third');
jList.add(3,'and last');
jCBList = com.mathworks.mwswing.checkboxlist.CheckBoxList(jList);
jScrollPane = com.mathworks.mwswing.MJScrollPane(jCBList);
[jhCBList,hContainer] = javacomponent(jScrollPane,[10,10,80,65],gcf);
set(jCBList, 'ValueChangedCallback', #myMatlabCallbackFcn);
jCBModel = jCBList.getCheckModel;
jCBModel.checkAll;
jCBModel.uncheckIndex(1);
jCBModel.uncheckIndex(3);
There's no "ready" way for doing that - as listboxes take only plain strings as entries.
You could "manually" draw checkbox fitted into the area of the listbox, but that might mean quite a lot of work to get everything working...
Another alternative is to go for a java-componenent - e.g. using the jide components available in matlab. See e.g.
http://undocumentedmatlab.com/blog/using-jide-combo-boxes/
for a few examples.

SilverLight 4 DataGrid & MVVM: Using SelectionChanged trigger to check checkbox, but NotifyPropertyChanged causes crash

I have a DataGridCheckBoxColumn in my DataGrid which is to indicate the rows the user has selected. I want the checkboxes to be checked/unchecked with a single click. Making the column editable (i.e. IsReadOnly="False") means the user has to click twice (first click just selects the row, 2nd click changes the checkbox), so I decided to set/clear the property the column is bound to in the view model code in response to the SelectionChanged trigger firing.
Setting/clearing the property works fine, however as soon as I call NotifyPropertyChanged("name of collection the grid is bound to") to get the view to show the change, this causes the SelectionChanged trigger to fire again. This loops about 10 times until an exception is thrown.
If I remove the call to NotifyPropertyChanged, the SelectionChanged trigger fires once, but of course I don't see any change in the UI. The collection is a PagedCollectionView if this makes any difference.
How can I get this to work? Note - I am using MVVM pattern, so everything is done with bindings to View Model (no code behind).
Thanks
Sounds like you have a infinite loop by design.
but try using the selectionchanging instead of selectionchanged,
or put a isloading flag in your viewmodel and dont call the inotify if the isloading is true
I found a very simple solution that doesn't involve triggers or code behind. See: Silverlight single-click checkbox DataGrid columns
It seems to work by using a column template, but only providing the CellEditingTemplate and no CellTemplate.

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