Re: segfault when reattaching a tree model to a tree view
Peter Groves <[email protected]> Wed, 15 Sep 2010 03:02:54 -0500
| Newsgroups | gmane.comp.lang.ocaml.lib.gtk |
|---|---|
| Message-ID | <[email protected]> |
Jacques, You're example ran fine (once i ran it properly :). I noticed (through brute force guess and check) that in my code I was able to work around the bug by changing the vpolicy on the scroll bar to `ALWAYS instead of `AUTOMATIC. After much trial and error to bring your example in line with my code, I have been able to reproduce the bug with as few changes as possible to your example. The code is attached. The program should crash when you click the 'dump' button. In the current form, you can make the bug go away by either 1) changing the vpolicy of the scroll_window to 'ALWAYS on line 142, OR 2) you can remove the call to scrollContainer#set_resize_mode `IMMEDIATE; on line 140. Both result in correctly working code for me. While I'm sure you're capable or running a diff on the files, here are the changes I made: - I added a call to GtkMain.Main.init () on line 17. You will probably want to delete this. (My build system is weird - this was the easiest way for me to get it to link properly.) - When the 'dump' button is pressed, it definitely calls set_model#(Some model) instead of only on an exception. this is where the segfault occurs. - the scrolled_window is packed in a GBin.alignment container before being packed in the top level vbox layout. Honestly, I don't remember why this is in my code, I was applying it to all widgets to ensure some consistent behaviour, but I'm not sure what. So there you go - the bug occurs when the model is set on a tree_view in a scrolled_window with vpolicy of `AUTOMATIC and the scroll bar is in a GBin.alignment with it's resize_mode set to `IMMEDIATE. For me, the workaround of setting the vpolicy to `ALWAYS is acceptable. Sadly, this whole exercise has not led to a speed increase in the slowness I was originally trying to solve, but hopefully the bug report does some good. -Peter On Wed, Sep 15, 2010 at 2:11 AM, Jacques Garrigue <[email protected]> wrote: > On Wed, Sep 15, 2010 at 1:41 PM, Peter Groves <[email protected]> wrote: >> One more update: when I put the tree_view in a scrolled_window the >> "wrong" way, where the column headers scroll away like everything >> else, the problem also goes away. I do this by adding the tree_view to >> the scrolled_window using scroller#add_with_viewport instead of >> scroller#add. > > I was using #add_with_viewport. > Here is a new version of tree_model.ml which does it right. > Again, you must link it with gtkInit.cmo. > For me it works correctly. > > Jacques > _______________________________________________ Lablgtk mailing list [email protected] http://yquem.inria.fr/cgi-bin/mailman/listinfo/lablgtk
tree_model4.ml
(text/x-ocaml, 6.8 KB)
(**************************************************************************)
(* Lablgtk - Examples *)
(* *)
(* There is no specific licensing policy, but you may freely *)
(* take inspiration from the code, and copy parts of it in your *)
(* application. *)
(* *)
(**************************************************************************)
(* Various experiments with GtkTreeModelSort and GtkTreeModelFilter *)
type date = {
mon : int ;
day : int ;
}
let _ = GtkMain.Main.init ()
let format_date { mon = mon ; day = day } =
let mon_str = match mon with
| 1 -> "Jan" | 2 -> "Feb" | 3 -> "Mar" | 4 -> "Apr"
| 5 -> "May" | 6 -> "Jun" | 7 -> "Jul" | 8 -> "Aou"
| 9 -> "Sep" | 10 -> "Oct" | 11 -> "Nov" | 12 -> "Dec"
| _ -> invalid_arg "bad month" in
Printf.sprintf "% 2d %s" day mon_str
let data = [
`HOME, "home", true, { day = 29 ; mon = 02 } ;
`JUMP_TO, "go", true, { day = 15 ; mon = 02 } ;
`QUIT, "quit", false, { day = 27 ; mon = 01 } ;
`STOP, "stop", true, { day = 21 ; mon = 01 } ;
`DELETE, "delete", false, { day = 15 ; mon = 01 } ;
]
(* Sort function: sort according to string length ! *)
let sort_function column (model : #GTree.model) it_a it_b =
let a = model#get ~row:it_a ~column in
let b = model#get ~row:it_b ~column in
compare (String.length a) (String.length b)
let print_flags name (m : #GTree.model) =
Format.printf "%sflags: %s@." name
(String.concat "; "
(List.map
(function
| `ITERS_PERSIST -> "persistent iterators"
| `LIST_ONLY -> "list only")
m#flags))
type model = { model:GTree.model_sort;
model_filtered:GTree.model_filter;
store:GTree.list_store;
stock_id_col:GtkStock.id GTree.column;
str_col:string GTree.column;
vis_col:bool GTree.column;
date_col:date GTree.column; }
let make_model data =
let cols = new GTree.column_list in
let stock_id_col = cols#add GtkStock.conv in
let str_col = cols#add Gobject.Data.string in
let vis_col = cols#add Gobject.Data.boolean in
let date_col = cols#add Gobject.Data.caml in
let l = GTree.list_store cols in
print_flags "ListStore" l ;
List.iter
(fun (stock_id, str, vis, date) ->
let row = l#append () in
l#set ~row ~column:stock_id_col stock_id ;
l#set ~row ~column:str_col str ;
l#set ~row ~column:vis_col vis ;
l#set ~row ~column:date_col date)
data ;
let s = GTree.model_sort l in
print_flags "TreeModelSort" s ;
let f = GTree.model_filter s in
print_flags "TreeModelFilter" f ;
f#set_visible_column vis_col ;
(* let s' = GTree.model_sort f in *)
s#connect#sort_column_changed
(fun () ->
match s#get_sort_column_id with
| None -> Format.printf "no sort_column@."
| Some (id, `ASCENDING) ->
Format.printf "sort_column = %d, ascending@." id
| Some (id, `DESCENDING) ->
Format.printf "sort_column = %d, descending@." id) ;
s#set_sort_func 0 (sort_function str_col);
{model=s; model_filtered=f; store=l;
stock_id_col=stock_id_col; str_col=str_col;
vis_col=vis_col; date_col=date_col; }
let make_view store packing =
let view_col =
let col = GTree.view_column ~title:"Stock Icons" () in
let str_renderer =
GTree.cell_renderer_text [ `FAMILY "monospace" ; `XALIGN 1. ] in
col#pack str_renderer ;
col#add_attribute str_renderer "text" store.str_col ;
let pb_renderer = GTree.cell_renderer_pixbuf [ `STOCK_SIZE `BUTTON ] in
col#pack pb_renderer ;
col#add_attribute pb_renderer "stock_id" store.stock_id_col ;
col#set_sort_column_id 0 ;
col in
let view_date_col =
let col = GTree.view_column ~title:"Date" () in
let str_renderer = GTree.cell_renderer_text [ `XALIGN 0.5 ] in
col#pack str_renderer ;
col#set_cell_data_func str_renderer
(fun model row ->
let date = model#get ~row ~column:store.date_col in
str_renderer#set_properties [ `TEXT (format_date date) ]) ;
col in
let b =
GButton.check_button ~label:"_Filter data" ~use_mnemonic:true ~packing () in
let view_toggle_col =
let col = GTree.view_column ~title:"Active" () in
let toggle = GTree.cell_renderer_toggle [`ACTIVATABLE true] in
col#pack toggle ;
col#add_attribute toggle "active" store.vis_col;
toggle#connect#toggled (fun p ->
let l = store.store and column = store.vis_col in
let p =
if b#active then store.model_filtered#convert_path_to_child_path p
else p in
let row = l#get_iter (store.model#convert_path_to_child_path p) in
l#set ~row ~column (not (l#get ~row ~column)));
col in
let scrollContainer = GBin.alignment ~packing () in
scrollContainer#set_resize_mode `IMMEDIATE;
let scroller =
GBin.scrolled_window ~hpolicy:`AUTOMATIC ~vpolicy:`AUTOMATIC
~packing:scrollContainer#add ~width:150 ~height:100 () in
scroller#set_shadow_type `ETCHED_IN;
scroller#set_resize_mode `PARENT;
let v = GTree.view ~model:store.model ~width:200 ~packing:scroller#add ()
in
v#append_column view_col ;
v#append_column view_date_col ;
v#append_column view_toggle_col ;
b#connect#toggled
(fun () ->
let new_model =
if b#active
then store.model_filtered#coerce
else store.model#coerce in
(* let (id, dir) =
Gaux.default (-1, `ASCENDING) ~opt:current#get_sort_column_id in
new_model#set_sort_column_id id dir ; *)
v#set_model (Some new_model) ) ;
v
let inspect_data_1 column (model : GTree.model) =
Format.printf "@[<v 2>Traverse with iters:" ;
begin match model#get_iter_first with
| None -> Format.printf "@ empty model"
| Some row ->
let cont = ref true in
while !cont do
let data = model#get ~row ~column in
Format.printf "@ %s" data ;
cont := model#iter_next row
done
end ;
Format.printf "@]@."
let inspect_data_2 column (model : GTree.model) =
Format.printf "@[<v 2>Traverse with #foreach:" ;
model#foreach
(fun _ row ->
let data = model#get ~row ~column in
Format.printf "@ %s" data ;
false) ;
Format.printf "@]@."
let main =
let w = GWindow.window ~title:"GtkListStore test" () in
w#connect#destroy GMain.quit ;
let box = GPack.vbox ~packing:w#add () in
let m = make_model data in
let v = make_view m box#add in
begin
let b = GButton.button ~label:"Dump data" ~packing:box#pack () in
b#connect#clicked
(fun () ->
let model = m.model#coerce in
begin try
ignore v#model;
v#set_model None;
inspect_data_1 m.str_col model ;
v#set_model (Some model);
with _ -> ()
end;
inspect_data_2 m.str_col model)
end ;
w#show () ;
GMain.main ()