立石です。

衝動にかられてtkcombobox.rbというものを作りました。
今まで作りたかったけど面倒でやめていた方はどうぞ使
って下さい。

;; すでに誰か作ってるかも、、、(^^;

			Takaaki Tateishi <ttate / jaist.ac.jp>

#! -*- ruby -*-
#
# tkcombobox.rb
# written by ttate / jaist.ac.jp at 1999/10/31
#
# FREE FOR ANY USE, BUT COPYRIGHTED BY THE AUTHOR
#
# examples
# -------------------------------------------------------
# require 'tkcombobox'
# combo = TkCombobox.new(nil,'fg' => 'black','width' => 30)
# combo.entry['fg'] = 'blue'
# combo.entries = ['entry1', 'entry2', 'entry3']
# combo.select_proc = proc{|index,entry| print("index=#{index}, entry=#{entry}\n")}
# combo.pack
# Tk.mainloop
# -------------------------------------------------------
# require 'tkcombobox'
# combo = TkCombobox.new(nil,'fg' => 'red','width' => 30)
# combo.entry['fg'] = 'blue'
# combo.list_proc = proc{[Time.now.to_s,'entry1','entry2']}
# combo.select_proc = proc{|index,entry| print("index=#{index}, entry=#{entry}\n")}
# combo.pack
# Tk.mainloop
# --------------------------------------------------------

require 'tk'
require 'tkscrollbox'

class TkCombobox < TkEntry
  include TkComposite
  attr_reader :entries, :list_proc, :select_proc, :entry, :scrollbox
  attr_writer :entries, :list_proc, :select_proc

DOWN_ARROW_IMG = <<STR
  #define dwnarrow.icn_width 15
  #define dwnarrow.icn_height 15
  static unsigned char dwnarrow.icn_bits[] = {
    0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07,
    0xe0, 0x07, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03,
    0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
STR

  def initialize_composite(keys=nil)
    @entries = []
    @list_proc = nil

    @select_proc = proc{|index,entry| nil}

    @eframe = TkFrame.new(@frame)
    image = TkBitmapImage.new('data' => DOWN_ARROW_IMG)
    @entry = TkEntry.new(@eframe,
			{ 'bd' => 1,
			  'highlightthickness' => 0})
    @label = TkButton.new(@eframe,
			 {'bd' => 1,
			   'image' => image,
			   'highlightthickness' => 0,
			   'command' => proc{cmd_scrollbox}})
    @entry.pack('side' => 'left', 'fill' => 'x', 'expand' => 'yes')
    @label.pack('side' => 'right')

    @tframe = TkToplevel.new(@frame)
    @tframe.overrideredirect(1)
    @tframe.transient
    @tframe.withdraw
    @scrollbox = TkScrollbox.new(@tframe,
				 'border' => 1)
    @scrollbox.pack('fill' => 'both',
		    'expand' => 'yes')

    @eframe.pack('fill' => 'both', 'expand' => 'yes')

    @scrollbox.bind('Double-1',proc{|y| doubleclicked_scrollbox(y)},"%y")
    @scrollbox.bind('Any-Leave',proc{hide_scrollbox})

    for key in ['width', 'foreground', 'fg', 'background', 'bg']
      delegate(key,  @entry,@scrollbox)
    end
    for key in ['relief','border']
      delegate(key, @eframe)
    end

    configure keys if keys
  end

  def doubleclicked_scrollbox(y)
    @entry.delete(0,'end')
    i = @scrollbox.nearest(y)
    s = @scrollbox.get(i)
    @entry.insert(0,s)
    select_proc.call(i,s)
    hide_scrollbox
  end

  def cmd_scrollbox
    case @tframe.state
    when "withdrawn"
      if( @list_proc )
	show_scrollbox @list_proc.call
      else
	show_scrollbox @entries
      end
    else
      hide_scrollbox
    end
  end

  def show_scrollbox(entries = nil)
    width = TkWinfo.width(@eframe)
    height = 5 * TkWinfo.height(@entry)
    rootx = TkWinfo.rootx(@eframe)
    rooty = TkWinfo.rooty(@eframe).to_i + TkWinfo.height(@eframe).to_i
    geometry = "#{width}x#{height}+#{rootx}+#{rooty}"
    @tframe.geometry(geometry)
    @tframe.deiconify
    if( entries )
      entries.each{|entry|
	@scrollbox.insert("end",entry)
      }
    end
  end

  def hide_scrollbox
    @tframe.withdraw
    @scrollbox.delete(0,"end")
    @entry.focus
  end
end