TkMenubar + Keyboard Shortcut

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 can do this I think if I could find out how to be notified when the
TkMenu item disappears (from a click or keystroke somewhere…)… but
also if there’s an easier way, that would be nice.

Thanks for any help you can give

Matt

Hi,

···

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)

Hi,

···

From: Matthew Maycock ummaycoc@cs.drexel.edu
Subject: Re: TkMenubar + Keyboard Shortcut
Date: Tue, 1 Jun 2004 08:50:12 -0400 (EDT)
Message-ID: Pine.GSO.4.58.0406010846460.6066@queen.cs.drexel.edu

so I just wanna be able to push Alt+(Some char) and have a menu drop down,
and then be able to use up/down/left/right arrows and other alt
combinations to navigate/execute menu commands.

Doesn’t it work?
On my environment (Tk8.0.5 and 8.5a1), I can use arrow-keys
on the following sample.

require ‘tk’

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’=>‘Helvetica -12 bold’)
menubar.pack(‘side’=>‘top’, ‘fill’=>‘x’)

TkText.new.pack
Tk.mainloop


Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> wrote in message news:<20040602.110432.74747718.nagai@ai.kyutech.ac.jp>...

Hi,

From: Matthew Maycock <ummaycoc@cs.drexel.edu>
Subject: Re: TkMenubar + Keyboard Shortcut
Date: Tue, 1 Jun 2004 08:50:12 -0400 (EDT)
Message-ID: <Pine.GSO.4.58.0406010846460.6066@queen.cs.drexel.edu>
> so I just wanna be able to push Alt+(Some char) and have a menu drop down,
> and then be able to use up/down/left/right arrows and other alt
> combinations to navigate/execute menu commands.

Doesn't it work?
On my environment (Tk8.0.5 and 8.5a1), I can use arrow-keys
on the following sample.
------------------------------------------------------
require 'tk'

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'=>'Helvetica -12 bold')
menubar.pack('side'=>'top', 'fill'=>'x')

TkText.new.pack
Tk.mainloop
------------------------------------------------------

I can use up and down once I click on `File' - but I can't use
left/right to go between edit and file.

I also still can't figure out how to make Alt+F drop down file.
Inside your example, I'd like to be able to press Alt+F, Down, Enter
in that sequence to open a file...

Thanks for all your help, Hidetoshi

Matt

Hi,

···

From: mhm26@drexel.edu (matt)
Subject: Re: TkMenubar + Keyboard Shortcut
Date: Fri, 4 Jun 2004 01:03:38 +0900
Message-ID: <13383d7a.0406030759.217ba315@posting.google.com>

I can use up and down once I click on `File' - but I can't use
left/right to go between edit and file.

I also still can't figure out how to make Alt+F drop down file.
Inside your example, I'd like to be able to press Alt+F, Down, Enter
in that sequence to open a file...

Hmmm.... On my environment (Vine-2.6/GNOME), that sequence works.
What is your environment? Doesn't your window manager (or an other
application) carry off the key press?
--
                                  Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> wrote in message news:<20040604.011325.74741131.nagai@ai.kyutech.ac.jp>...

Hi,

From: mhm26@drexel.edu (matt)
Subject: Re: TkMenubar + Keyboard Shortcut
Date: Fri, 4 Jun 2004 01:03:38 +0900
Message-ID: <13383d7a.0406030759.217ba315@posting.google.com>
> I can use up and down once I click on `File' - but I can't use
> left/right to go between edit and file.
>
> I also still can't figure out how to make Alt+F drop down file.
> Inside your example, I'd like to be able to press Alt+F, Down, Enter
> in that sequence to open a file...

Hmmm.... On my environment (Vine-2.6/GNOME), that sequence works.
What is your environment? Doesn't your window manager (or an other
application) carry off the key press?

I'm unfortunately using windows...

so I can get the Alt+F to drop down the file menu automatically by
telling the menu itself by invoking #popup with the right
coordinates... and then the arrow buttons work, but I have to put all
the code in there to handle that, any way to make that automatic?

also, I want to be able to say type Alt+F for a file-menu drop and
then push Alt+O for the open to go in my application.

Even if this isn't done automatically by the os/windowmanager, it
should be pretty easy to do. I just have to know when I'm `in' the
file menu (ie know when it's being dropped down) to know that Alt+O
maps to file_menu->open.

Sorry for any confusion my previous lack of proper expounding may have
caused, and thanks for your help.

Hi,

···

From: mhm26@drexel.edu (matt)
Subject: Re: TkMenubar + Keyboard Shortcut
Date: Sat, 5 Jun 2004 04:08:40 +0900
Message-ID: <13383d7a.0406041105.716c190b@posting.google.com>

I'm unfortunately using windows...

On windows version of Tcl/Tk, it seems that menubutton bindings
which expected on TkMenubar class don't work properly.
But 'menu' option of root/toplevel widget looks like working.
Please try to use the 'menu' option.

e.g.
---------------------------------------------------------------------
menubar = TkMenu.new(Tk.root)

Tk.root[:menu] = menubar # use 'menu' option

mfile = TkMenu.new(menubar, :tearoff=>false)
medit = TkMenu.new(menubar, :tearoff=>false)

menubar.add(:cascade, :menu=>mfile, :label=>'File', :underline=>0)
menubar.add(:cascade, :menu=>medit, :label=>'Edit', :underline=>0)

mfile.add(:command, :label=>'Open', :underline=>0, :command=>proc{p 'Open'})
mfile.add(:command, :label=>'Quit', :underline=>0, :command=>proc{exit})

medit.add(:command, :label=>'Copy', :underline=>0, :command=>proc{p 'Copy'})
medit.add(:command, :label=>'Paste', :underline=>0, :command=>proc{p 'Paste'})

txt = TkText.new.pack

Tk.mainloop
---------------------------------------------------------------------
--
                                  Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)