···
From: mhm26@drexel.edu (matt)
Subject: TkMenubar + Keyboard Shortcut
Date: Fri, 28 May 2004 22:00:40 +0900
Message-ID: 13383d7a.0405261900.1f42b3ec@posting.google.com
Is there any easy way to do keyboard short cuts with tkmenubar /
tkmenu, etc? (short cuts in the vein of Alt+F makes the file drop
down, and then alt+O would do open in the file menu).
I’m sorry but I couldn’t understand your request.
Is the binding for ‘underline’ option not enough for your purpose?
Or, do you want more easy way to create menus?
Did you read ext/tk/lib/tkmenubar.rb (or ext/tk/lib/tk/menubar.rb)?
Although tkmenubar.rb supports ‘command’ type and ‘separator’
menu items only.
If you want to create ‘checkbutton’ type items,
please try the following improved version of tkmenubar.rb.
tk/menubar.rb
Copyright (C) 1998 maeda shugo. All rights reserved.
This file can be distributed under the terms of the Ruby.
Usage:
menu_spec = [
[[‘File’, 0],
[‘Open’, proc{puts(‘Open clicked’)}, 0],
‘—’,
[‘Quit’, proc{exit}, 0]],
[[‘Edit’, 0],
[‘Cut’, proc{puts(‘Cut clicked’)}, 2],
[‘Copy’, proc{puts(‘Copy clicked’)}, 0],
[‘Paste’, proc{puts(‘Paste clicked’)}, 0]]
]
menubar = TkMenubar.new(nil, menu_spec,
‘tearoff’=>false,
‘foreground’=>‘grey40’,
‘activeforeground’=>‘red’,
‘font’=>‘-adobe-helvetica-bold-r-–12--iso8859-1’)
menubar.pack(‘side’=>‘top’, ‘fill’=>‘x’)
OR
menubar = TkMenubar.new
menubar.add_menu([[‘File’, 0],
[‘Open’, proc{puts(‘Open clicked’)}, 0],
‘—’,
[‘Quit’, proc{exit}, 0]])
menubar.add_menu([[‘Edit’, 0],
[‘Cut’, proc{puts(‘Cut clicked’)}, 2],
[‘Copy’, proc{puts(‘Copy clicked’)}, 0],
[‘Paste’, proc{puts(‘Paste clicked’)}, 0]])
menubar.configure(‘tearoff’, false)
menubar.configure(‘foreground’, ‘grey40’)
menubar.configure(‘activeforeground’, ‘red’)
menubar.configure(‘font’, ‘-adobe-helvetica-bold-r-–12--iso8859-1’)
menubar.pack(‘side’=>‘top’, ‘fill’=>‘x’)
OR
radio_var = TkVariable.new(‘y’)
menu_spec = [
[[‘File’, 0],
{:label=>‘Open’, :command=>proc{puts(‘Open clicked’)}, :underline=>0},
‘—’,
[‘Check_A’, TkVariable.new(true), 6],
{:type=>‘checkbutton’, :label=>‘Check_B’,
:variable=>TkVariable.new, :underline=>6},
‘—’,
[‘Radio_X’, [radio_var, ‘x’], 6],
[‘Radio_Y’, [radio_var, ‘y’], 6],
[‘Radio_Z’, [radio_var, ‘z’], 6],
‘—’,
[‘cascade’, [
[‘sss’, proc{p ‘sss’}, 0],
[‘ttt’, proc{p ‘ttt’}, 0],
[‘uuu’, proc{p ‘uuu’}, 0],
[‘vvv’, proc{p ‘vvv’}, 0],
], 0],
‘—’,
[‘Quit’, proc{exit}, 0]],
[[‘Edit’, 0],
[‘Cut’, proc{puts(‘Cut clicked’)}, 2],
[‘Copy’, proc{puts(‘Copy clicked’)}, 0],
[‘Paste’, proc{puts(‘Paste clicked’)}, 0]]
]
menubar = TkMenubar.new(nil, menu_spec,
‘tearoff’=>false,
‘foreground’=>‘grey40’,
‘activeforeground’=>‘red’,
‘font’=>‘Helvetia 12 bold’)
menubar.pack(‘side’=>‘top’, ‘fill’=>‘x’)
The format of the menu_spec is:
[
[
[text, underline, configs], # menu button
[label, command, underline, accelerator, configs], # command item
[label, TkVar_obj, underline, accelerator, configs], # checkbutton item
[label, [TkVar_obj, value],
underline, accelerator, configs], # radiobutton item
[label, [[…item_spec…], […item_spec…], …],
underline, accelerator, configs], # cascade item
‘—’, # separator
…
],
…
]
underline and accelerator are optional parameters.
Hashes are OK instead of Arrays.
To use add_menu, configuration must be done by calling configure after
adding all menus by add_menu, not by the constructor arguments.
require ‘tk’
require ‘tk/frame’
class TkMenubar<TkFrame
include TkComposite
def initialize(parent = nil, spec = nil, options = nil)
if parent.kind_of? Hash
options = _symbolkey2str(parent)
spec = options.delete(‘spec’)
super(options)
else
super(parent, options)
end
@menus = []
if spec
for menu_info in spec
add_menu(menu_info)
end
end
if options
for key, value in options
configure(key, value)
end
end
end
def _create_menu(parent, menu_info)
menu = TkMenu.new(parent)
for item_info in menu_info
if item_info.kind_of?(Hash)
item_info = _symbolkey2str(item_info)
item_type = (item_info.delete('type') || 'command').to_s
menu.add(item_type, item_info)
elsif item_info.kind_of?(Array)
options = {}
options['label'] = item_info[0] if item_info[0]
case item_info[1]
when TkVariable
# checkbutton
item_type = 'checkbutton'
options['variable'] = item_info[1]
options['onvalue'] = true
options['offvalue'] = false
when Array
# radiobutton or cascade
if item_info[1][0].kind_of?(TkVariable)
# radiobutton
item_type = 'radiobutton'
options['variable'] = item_info[1][0]
options['value'] = item_info[1][1] if item_info[1][1]
else
# cascade
item_type = 'cascade'
submenu = _create_menu(menu, item_info[1])
options['menu'] = submenu
end
else
# command
item_type = 'command'
options['command'] = item_info[1] if item_info[1]
end
options['underline'] = item_info[2] if item_info[2]
options['accelerator'] = item_info[3] if item_info[3]
if item_info[4] && item_info[2].kind_of?(Hash)
options.update(item_info[4])
end
menu.add(item_type, options)
elsif /^-+$/ =~ item_info
menu.add('separator')
else
menu.add('command', 'label' => item_info)
end
end
menu
end
private :_create_menu
def add_menu(menu_info)
btn_info = menu_info[0]
mbtn = TkMenubutton.new(@frame)
if btn_info.kind_of?(Hash)
for key, value in btn_info
mbtn.configure(key, value)
end
elsif btn_info.kind_of?(Array)
mbtn.configure('text', btn_info[0]) if btn_info[0]
mbtn.configure('underline', btn_info[1]) if btn_info[1]
# mbtn.configure('accelerator', btn_info[2]) if btn_info[2]
mbtn.configure(btn_info[2]) if btn_info[2] && btn_info[2].kind_of?(Hash)
else
mbtn.configure('text', btn_info)
end
menu = _create_menu(mbtn, menu_info[1..-1])
mbtn.menu(menu)
@menus.push([mbtn, menu])
delegate('tearoff', menu)
delegate('foreground', mbtn, menu)
delegate('background', mbtn, menu)
delegate('disabledforeground', mbtn, menu)
delegate('activeforeground', mbtn, menu)
delegate('activebackground', mbtn, menu)
delegate('font', mbtn, menu)
delegate('kanjifont', mbtn, menu)
mbtn.pack('side' => 'left')
end
def
return @menus[index]
end
end
Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)