# Ruby/Tk/Iwidgets tabnotebook (and scrollbar)

**URL:** <https://www.ruby-forum.com/t/ruby-tk-iwidgets-tabnotebook-and-scrollbar/127426>\
**Category:** Ruby\
**Created:** [January 29, 2008, 2:55am UTC](https://www.ruby-forum.com/t/ruby-tk-iwidgets-tabnotebook-and-scrollbar/127426 "2008-01-29T02:55:32Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![kmeister2000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/a183cd/32.png) [@kmeister2000](https://www.ruby-forum.com/u/kmeister2000)\
**Post date:** [January 29, 2008, 2:55am UTC](https://www.ruby-forum.com/t/ruby-tk-iwidgets-tabnotebook-and-scrollbar/127426/1 "2008-01-29T02:55:32Z")

</div>

Hi

I’ve created an iwidgets tabnotebook, with a large number of tabs,  
and attached a scrollbar.

Moving the scroll bar successfully moves back and forth amongst pages,  
but the subset of tabs displayed does not change.

e.g say you have 20 tabs, and there is room for 1…6 to be displayed.

As you scroll from tab #6 to tab #7, the tabs shown should change  
from 1…6 to 2…7

Using notebook.select or notebook.view also has this behaviour.

Am I doing something wrong?

Cheers  
Karl

#!/usr/bin/env ruby  
require ‘tk’  
require ‘tkextlib/iwidgets’

# Create the tabnotebook widget and pack it.

tn = Tk::Iwidgets::Tabnotebook.new(:width=\>300, :height=\>100)  
tn.pack(:anchor=\>:nw, :fill=\>:both, :expand=\>true,  
:side=\>:top, :padx=\>10, :pady=\>0)

# Add twenty pages to the tabnotebook

1.upto(20) { |t|  
txt = 'Page ’ + t.to\_s  
tn.add(:label =\> txt)  
}

# Add a button on page 1 to change to tab 20

button = TkButton.new(tn.child\_site(0),:text =\>‘Go to Page 20’).pack  
button.command {  
tn.select(19) # tn.view etc have the same problem  
}

# Select the first page of the tabnotebook.

tn.select(0)

# Create the scrollbar

# and the notebook together, then pack the scrollbar

tn.xscrollbar(TkScrollbar.new).pack(:fill=\>:x,  
:expand=\>true, :padx=\>10)

Tk.mainloop

---

<div class="post-metadata">

**Author:** ![kmeister2000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/a183cd/32.png) [@kmeister2000](https://www.ruby-forum.com/u/kmeister2000)\
**Post date:** [February 5, 2008, 10:13am UTC](https://www.ruby-forum.com/t/ruby-tk-iwidgets-tabnotebook-and-scrollbar/127426/2 "2008-02-05T10:13:59Z")

</div>

From: Karl M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Subject: Ruby/Tk/Iwidgets tabnotebook (and scrollbar)  
Date: Tue, 29 Jan 2008 10:55:26 +0900  
Message-ID: [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> I’ve created an iwidgets tabnotebook, with a large number of tabs,  
> and attached a scrollbar.
> 
> Moving the scroll bar successfully moves back and forth amongst pages,  
> but the subset of tabs displayed does not change.  
> (snip)  
> Am I doing something wrong?

You must control start position of the tabset.

> 1.upto(20) { |t|  
> txt = 'Page ’ + t.to\_s  
> tn.add(:label =\> txt)  
> }

# Command to control the tabset

tabset = tn.component\_widget(‘tabset’)  
tabset.command{|idx|  
left = tabset.tabcget(idx, :left)  
prev = tabset.index(idx) - 1  
if prev \< 0  
tabset.start = 0  
elsif left \< 0  
tabset.start -= left  
elsif left + (tabwidth = tabset.tabcget(idx,:width)) \> (tabset\_width =  
tabset.width)  
tabset.start -= left - tabset\_width + 2\*(left -  
tabset.tabcget(prev,:left)) - tabwidth + 1  
end  
}

---

<div class="post-metadata">

**Author:** ![kmeister2000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/a183cd/32.png) [@kmeister2000](https://www.ruby-forum.com/u/kmeister2000)\
**Post date:** [February 5, 2008, 7:56pm UTC](https://www.ruby-forum.com/t/ruby-tk-iwidgets-tabnotebook-and-scrollbar/127426/3 "2008-02-05T19:56:19Z")

</div>

Probably the following is better. Sorry.

> 1.upto(20) { |t|  
> txt = 'Page ’ + t.to\_s  
> tn.add(:label =\> txt)  
> }

# Command to control the tabset

class Tk::Iwidgets::Tabnotebook  
def show\_tab(idx)  
if (prev = @tabset.index(idx) - 1) \< 0  
@tabset.start = 0  
return  
end  
case cget(:tabpos)  
when ‘s’, ‘n’  
poskey = :left  
szkey = :width  
when ‘e’, ‘w’  
poskey = :top  
szkey = :height  
end  
if (hd = @tabset.tabcget(idx, poskey)) \< 0  
@tabset.start -= hd  
elsif hd + (sz = @tabset.tabcget(idx, szkey)) \> (tabs\_sz =  
@tabset[szkey])  
@tabset.start -= hd - tabs\_sz + 2\*(hd - @tabset.tabcget(prev,  
poskey)) - sz + 1  
end  
end  
end

tn.component\_widget(‘tabset’).command{|idx|  
tn.view(idx)  
tn.show\_tab(idx)  
}

---

<div class="post-metadata">

**Author:** ![kmeister2000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/a183cd/32.png) [@kmeister2000](https://www.ruby-forum.com/u/kmeister2000)\
**Post date:** [February 5, 2008, 11:54pm UTC](https://www.ruby-forum.com/t/ruby-tk-iwidgets-tabnotebook-and-scrollbar/127426/4 "2008-02-05T23:54:00Z")

</div>

Hidetoshi NAGAI wrote:

> Probably the following is better. Sorry.

Yay! This worked very well. Thank you 🙂

Cheers  
Karl

---

<div class="post-metadata">

**Author:** ![kmeister2000](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/a183cd/32.png) [@kmeister2000](https://www.ruby-forum.com/u/kmeister2000)\
**Post date:** [February 7, 2008, 10:29pm UTC](https://www.ruby-forum.com/t/ruby-tk-iwidgets-tabnotebook-and-scrollbar/127426/5 "2008-02-07T22:29:37Z")

</div>

From: Karl M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Subject: Re: Ruby/Tk/Iwidgets tabnotebook (and scrollbar)  
Date: Wed, 6 Feb 2008 07:53:53 +0900  
Message-ID: [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> > Probably the following is better. Sorry.
> 
> Yay! This worked very well. Thank you 🙂

The previous version does not work with some of widget options  
(e.g. tn.equaltabs = false, tn.gap = 2, and so on).  
And, ‘show\_tab’ method should be implemented on Tk::Iwidgets::Tabset.  
The following is the final version (I hope so ;-)).  
If it has no problem, I’ll add ‘show\_tab’ method to official files.

==================================================================

# Command to control the tabset

class Tk::Iwidgets::Tabnotebook  
def show\_tab(idx)  
@tabset.show\_tab(idx)  
self  
end  
end

class Tk::Iwidgets::Tabset  
def show\_tab(idx)  
if index(idx) == 0  
self.start = 0  
return  
end

```
reutrn unless @canvas ||= self.winfo_children[0]

delta = 1 if (delta = cget(:gap)) == 'overlap' ||
               (delta = self.winfo_pixels(delta) + 1) <= 0

case cget(:tabpos)
when 's', 'n'
  if (head = tabcget(idx, :left)) < 0
    self.start -= head
    return
  end
  tabs_size = @canvas.winfo_width
  tab_start, tab_end = @canvas .
    find_overlapping(head, 0, head + delta, @canvas.winfo_height) .
    find_all{|id| @canvas.itemtype(id) == TkcPolygon} .
    map!{|id| bbox = @canvas.bbox(id); [bbox[0], bbox[2]]} . max

when 'e', 'w'
  if (head = tabcget(idx, :top)) < 0
    self.start -= head
    return
  end
  tabs_size = @canvas.winfo_height
  tab_start, tab_end = @canvas .
    find_overlapping(0, head, @canvas.winfo_width, head + delta) .
    find_all{|id| @canvas.itemtype(id) == TkcPolygon} .
    map!{|id| bbox = @canvas.bbox(id); [bbox[1], bbox[3]]} . max
end

if (size = tab_end - tab_start + 1) > tabs_size
  self.start -= tab_start
elsif head + size > tabs_size
  self.start -= head + size - tabs_size
end

self

```

end  
end

tn.component\_widget(‘tabset’).command{|idx|  
tn.view(idx)  
tn.show\_tab(idx)  
}

# An example to following to resizing of the Tabnotebook widget

# tn.bind(‘Configure’){ tn.show\_tab(:select) }
