From: Morton Goldberg Date: 2006-09-23T17:14:39+09:00 Subject: Re: Ruby TK list question On Sep 22, 2006, at 2:21 PM, Harry Truax wrote: > Hi everyone, > > I am trying to do the following: I am trying to have one list re- > display > it's contents with new information based upon a selection made in > another > list without having the user click on a button. So the user would > click on > one list's element (highlighting it in the process) and the other > list would > dynamically re-draw it's list of info with new list elements being > displayed. > > Thanks for your help, The following is a little program I wrote to explore the exact question you're asking. It displays a two-stage color browser for X11 colors. The first stage is a list of color categories and the second is a list of color names. Disclaimer: this has only been tested on OS X (10.4). In particular, the path to rgb.txt probably isn't valid on other platforms. #! /usr/bin/ruby -w # Author: Morton Goldberg # # Date: August 26, 2006 # # X11 color browser require 'tk' DEBUG = [] class X11ColorCategory # Full path name of the X11 colors file. RGB_TXT = "/usr/X11R6/lib/X11/rgb.txt" #Dictionary of rgb values keyed by color name. COLORS = {} def X11ColorCategory.read_rgb_table # read and parse the X11 colors file. File.foreach(RGB_TXT) do |rgb| next if rgb =~ /^!/ # skip header line rgb = rgb.lstrip.split(/\s+/) r = rgb.shift g = rgb.shift b = rgb.shift key = rgb.join(' ') COLORS[key] = "r:#{r} g:#{g} b:#{b}" end COLORS end def X11ColorCategory.all ALL_CATEGORIES end def X11ColorCategory.rgb(color_name) COLORS[color_name] end def extract(pattern) @members, OTHER.members = OTHER.members.partition {|m| m =~ pattern} self end def initialize(name) @name = name @members = [] end attr_accessor :name, :members ALL = X11ColorCategory.new('ALL') X11ColorCategory.read_rgb_table.each {|key,| ALL.members << key} ALL.members.sort! OTHER = X11ColorCategory.new('OTHER') ALL.members.each {|m| OTHER.members << m} REDS = X11ColorCategory.new('REDS'). extract(/red|rose|pink|salmon|fire/i) GREENS = X11ColorCategory.new('GREENS'). extract(/green|chartreuse|olive|honeydew/i) BLUES = X11ColorCategory.new('BLUES'). extract(/blue|navy/i) CYANS = X11ColorCategory.new('CYANS'). extract(/cyan|aqua|azure|turquoise/i) MAGENTAS = X11ColorCategory.new('MAGENTAS'). extract(/magenta|maroon|violet|plum|purple|orchid|thistle/i) YELLOWS = X11ColorCategory.new('YELLOWS'). extract(/yellow|gold|lemon|corn/i) ORANGES = X11ColorCategory.new('ORANGES'). extract(/orange|tomato|peach|coral/i) BROWNS = X11ColorCategory.new('BROWNS'). extract(/brown|tan|wood|choc|sienna|wheat|peru/i) WHITES = X11ColorCategory.new('WHITES'). extract(/white|ivory|snow|lace/i) GRAYS = X11ColorCategory.new('GRAYS'). extract(/gr[ae]y|gainsboro/i) ALL_CATEGORIES = [ REDS, ORANGES, YELLOWS, GREENS, CYANS, BLUES, MAGENTAS, BROWNS, WHITES, GRAYS, OTHER ] end class X11ColorBrowser # Action performed when category selection is made. def category_selected_action @category_names.focus @selected_category = X11ColorCategory.all[@category_names.curselection[0]] @color_names.delete(0, 'end') @selected_category.members.each {|m| @color_names.insert ("end", m)} @color_names.selection_set(0) color_selected_action end # Action performed when color selection is made. def color_selected_action color = @selected_category.members[@color_names.curselection[0]] @color_rect.background(color) @rgb_lbl.text(X11ColorCategory.rgb(color)) end #Action performed when browser window is mapped. def window_mapped_action return if @mapped @mapped = true X11ColorCategory.all.each do |category| @category_names.insert("end", category.name) end @category_names.selection_set(0) category_selected_action end def initialize # Flag indicating that window has been mapped at least once. @mapped = false # Holder for currently selected color category @selected_category = nil # Set up the browser window. root = TkRoot.new {title 'Color Browser'} # Panel at top of browser containing scrolling list of X11 colors and # label displaying selected color. top_pnl = TkFrame.new(root) # List box displaying names of X11 color categories. @category_names = TkListbox.new(top_pnl) # Scroll bar for the color names list. vbar1 = TkScrollbar.new(top_pnl) @category_names.yscrollbar(vbar1) # List box displaying names of X11 colors within selected category. @color_names = TkListbox.new(top_pnl) # Scroll bar for the color names list. vbar2 = TkScrollbar.new(top_pnl) @color_names.yscrollbar(vbar2) # Label displaying selected color. @color_rect = TkLabel.new(top_pnl, 'width'=>25) # Request layout of top panel. @category_names.pack("side"=>"left", "fill"=>"both", "expand"=>true, "padx"=>5) vbar1.pack("side"=>"left", "after"=>@category_names, "fill"=>"y") @color_names.pack("side"=>"left", "after"=>vbar1, "fill"=>"both", "expand"=>true, "padx"=>5) vbar2.pack("side"=>"left", "after"=>@color_names, "fill"=>"y") @color_rect.pack("side"=>"right", "fill"=>"both", "expand"=>true, "padx"=>5) top_pnl.pack("side"=>"top", "fill"=>"both", "expand"=>true, "padx"=>5, "pady"=>8) # Panel at bottom of browser containing exit button and label # displaying RGB values of selected color. btm_pnl = TkFrame.new(root) # Label displaying rgb values of selected color. @rgb_lbl = TkLabel.new(btm_pnl) { text "r:xxx g:xxx b:xxx" } # Exit button. @quit_btn = TkButton.new(btm_pnl) { text "Exit" command {Tk.root.destroy} } # Request layout of bottom panel. @rgb_lbl.pack("side"=>"left", "anchor"=>"w") @quit_btn.pack("side"=>"right") btm_pnl.pack("side"=>"bottom", "fill"=>"x", "padx"=>10, "pady"=>8) # Set initial window geometry; i.e., size and placement. win_w, win_h = 750, 300 root.minsize(win_w, win_h) win_x = (root.winfo_screenwidth - win_w) / 2 root.geometry("#{win_w}x#{win_h}+#{win_x}+50") # Make Cmnd+Q work as expected. root.bind('Command-q') {@quit_btn.invoke} # Bind mouse button-1, space bar, window map event to their actions. @category_names.bind('Map') {window_mapped_action} ev = TkVirtualEvent.new('ButtonRelease-1', 'space') @category_names.bind(ev) {category_selected_action} ev = TkVirtualEvent.new('ButtonRelease-1', 'space') @color_names.bind(ev) {color_selected_action} Tk.mainloop end end begin X11ColorBrowser.new ensure puts DEBUG unless DEBUG.empty? end Sorry to push all this code on you. I'm afraid I'm too busy at the moment to edit it down to just the parts that will answer your question. Regards, Morton