Best way to create table-like lists?


#1

Hi,

I tried different approaches to create table-like lists. What I need

  • a head (1-3 rows), non-scrollable
  • a scrollable body
  • head and body cells must align

My first draft was:
VBox
-> Table (for head), childs are labels
-> Scrolledwindow
—> Viewport
------> Table (for data), childs are labels

The problem is that head table and body table are not aligned. For
example because the scrollbars which are not present in head table.

My next attempt is this class, using a Layout object allowing me to
attach object in a fixed position.

Draft:
VBox
-> Layout (for head)
—> Labels (fixed position)
-> Scrollwindow
—> Layout (for body)
-----> Labels (fixed position)

#table.rb
class Table

attr_accessor :widths
attr_accessor :number_of_columns
attr_accessor :height
attr_accessor :x
attr_accessor :y
attr_accessor :color
attr_accessor :head_data
attr_accessor :head
attr_accessor :body
attr_accessor :body_scrollwindow
attr_accessor :x_pos #bad name should be p pos in pixel

def initialize(widths)
set_column_widths(widths)
self.height = 16
self.x = 0
self.y = 0
set_color

# Head
self.head = Gtk::Layout.new


# Body in a scrollwindow
scrollwindow = Gtk::ScrolledWindow.new
self.body =

Gtk::Layout.new(scrollwindow.hadjustment,scrollwindow.vadjustment)
scrollwindow.add body
self.body_scrollwindow = scrollwindow

end

def set_column_widths(widths)
self.widths = widths
self.number_of_columns = widths.size
self.x_pos = []
cur = 0
i = 0
widths.each do |w|
self.x_pos[i] = cur
cur = cur + w
i = i + 1
end
end

def head_data(data)
self.head_data = data
data.each do |h|
add_head_label(h)
end
end

def add(str)
label = Gtk::Label.new(str.to_s)
label.set_alignment(0,0)
label.width_request = self.widths[self.x]
label.height_request = self.height
eventbox = Gtk::EventBox.new
eventbox << label
eventbox.modify_bg(Gtk::STATE_NORMAL,self.color)
add_widget(eventbox)
end

def add_widget(widget,target=self.body)
target.put(widget,self.x_pos[self.x],self.height*self.y)
self.x = self.x + 1
check_if_linebreak
end

def check_if_linebreak
if self.x >= self.number_of_columns
self.x = 0
self.y = self.y + 1
set_color
end
end

def attach(box)
total_width = 0
self.widths.each{|w| total_width = total_width + w}
total_height = y * self.height

self.head.height_request = self.height
self.body.set_size(total_width,total_height)

box.pack_start(self.head,false,true,0)
box.pack_start(self.body_scrollwindow,true,true,0)

box.show_all

end

private
def set_color
if self.y % 2 == 0
self.color = Gdk::Color::parse("#cccccc")
else
self.color = Gdk::Color::parse("#dddddd")
end
end

def add_head_label(str)
label = Gtk::Label.new(str.to_s)
label.set_alignment(0,0)
label.width_request = self.widths[self.x]
label.height_request = self.height
eventbox = Gtk::EventBox.new
eventbox << label
eventbox.modify_bg(Gtk::STATE_NORMAL,Gdk::Color::parse("#cacaca"))
add_widget(eventbox,self.head)
end

end

This is a test program for this table:

test.rb

require ‘gtk2’
require ‘table.rb’

window = Gtk::Window.new
head = [“Test”,“Test2”,“next”,“something else”,“Hello World”]
table = Table.new([40,55,55,100,150])
table.head_data(head)
100.times do
table.add(“test”)
table.add(“test…”)
table.add("…")
table.add(“test”)
table.add(“lorem ipsum”)
end
vbox = Gtk::VBox.new

table.attach(vbox)
window.add(vbox)
window.set_default_size(640,480)

window.show_all

Gtk.main

What’s annoying me is that I have a gap between head and body of the
table. It seems to be in the scrolledwindow above the Layout object.
How to debug this?

Are there any other proposals to do this kind of table? I’ve seen that
gtk-extra has a spreadsheet widget, but I haven’t seen any ruby bindings
for it and/or a win32 binary (which is unfortunately mandatory).


#2

Am Samstag, den 23.06.2007, 16:16 +0200 schrieb joaz:

Hi,

I tried different approaches to create table-like lists. What I need

  • a head (1-3 rows), non-scrollable
  • a scrollable body
  • head and body cells must align

Hi,

you can use the Gtk::TreeView as the display widget and the
Gtk::ListStore for your data.

Cheers
detlef


This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/


#3

Detlef R. wrote:

Hi,

you can use the Gtk::TreeView as the display widget and the
Gtk::ListStore for your data.

Cheers
detlef
Hi Detlef,

Thanks for your suggestion.

I made this list:

test.rb

require ‘gtk2’

window = Gtk::Window.new

content_types = Integer, String, String, String, Float
liststore = Gtk::ListStore.new(*content_types)
i = 0
100.times do
iter = liststore.append
iter[0] = i # row identified
iter[1] = “test#{i}”
iter[2] = “next#{i}”
iter[3] = “lorem ipsum#{i}”
iter[4] = rand(10000).to_f / 100

i = i + 1
end

view = Gtk::TreeView.new(liststore)
view.enable_search=true
view.search_column=2

render columns

i = 1
[“test”,“super”,“perfect”,“lorem”].each do |name|
renderer = Gtk::CellRendererText.new
col = Gtk::TreeViewColumn.new(name, renderer, :text => i)
col.sort_column_id = i
col.resizable = true
view.append_column(col)

i = i + 1
end

double click on row

view.signal_connect(“row-activated”) do |view, path, column|
puts “Row #{path.to_str} was clicked!”

if iter = view.model.get_iter(path)
puts “Double-clicked row contains id #{iter[0]}!”
end
end

show in a scrolled window

scrolledwindow = Gtk::ScrolledWindow.new.add view

window.add scrolledwindow
window.set_default_size(640,480)

window.show_all

Gtk.main

That works nicely so far. But I need another feature: The application
should be API based and gets an already filtered list from the server.

That means I want to have a text field for searching above or below
every column head.
Is there any way to include or stick this to the table head?

I’ve seen the Gtk::CellEditable interface, but this has to stick with
the Head of the table. It may not disappear when scrolling.

Any ideas?


#4

It looks like the TreeViewColumn object has a widget property, that you
can assign instead of a title. This should let you customize your
headers as much as you like. Like put a vbox in the title containing a
Gtk::Label and a Gtk::Entry(which you can rig up to search with signals
and whatnot)

That works nicely so far. But I need another feature: The application
should be API based and gets an already filtered list from the server.

That means I want to have a text field for searching above or below
every column head.
Is there any way to include or stick this to the table head?

I’ve seen the Gtk::CellEditable interface, but this has to stick with
the Head of the table. It may not disappear when scrolling.

Any ideas?


#5

Conan R. wrote:

It looks like the TreeViewColumn object has a widget property, that you
can assign instead of a title. This should let you customize your
headers as much as you like. Like put a vbox in the title containing a
Gtk::Label and a Gtk::Entry(which you can rig up to search with signals
and whatnot)

I tried this:
col = Gtk::TreeViewColumn.new(name, renderer, :text => i)
col.sort_column_id = i
col.resizable = true

box = Gtk::VBox.new
box << Gtk::Entry.new

box << Gtk::Label.new(name)
box.show_all
col.set_widget(box)

The problem is, that the Gtk::Entry is not editable at all because it
catches any mouse click on the header for the sorting function.

I think I’ll switch to a sidebar for searching.


#6

Hmm, that make sense. You could always disable the sorting(hopefully
then it would forward all clicks to the widget) and add another widget
to the vbox for sorting, maybe a button or something. But at this
point, it probably does make more sense to have a sidebar.

joaz wrote:

I tried this:
col = Gtk::TreeViewColumn.new(name, renderer, :text => i)
col.sort_column_id = i
col.resizable = true

box = Gtk::VBox.new
box << Gtk::Entry.new

box << Gtk::Label.new(name)
box.show_all
col.set_widget(box)

The problem is, that the Gtk::Entry is not editable at all because it
catches any mouse click on the header for the sorting function.

I think I’ll switch to a sidebar for searching.