Я мог бы упустить момент, но почему бы вам не использовать нить для этого?Вы не сможете присоединиться к нему в обратном вызове, но вы все равно должны иметь возможность генерировать событие.
TkButton.new :text => 'Hard routine',
:command => proc { Thread.new { hard_routine } }.pack
Tk.mainloop
выполнение тяжелых вещей в вашем обратном вызове считается плохой практикой, поскольку оно блокирует всецикл событий, так что ваш графический интерфейс зависает.