Ruby/Tk : How to show tooltips (please correct my ugly imple

Could someone please help me with the following?

I would like to add kind of a “show tooltips” function to my
application,
which means that some piece of text should be shown when the mourse
moves
over a certain area. In my case, the “hot spot” area is a set of
TkLabel.
When the mouse moves over such a label, a window should appear and show
some text, and when the mouse leaves the label area, the window should
disappear (this is different to “usual” tooltips, which appear and
disappear on buttons, not on text labels, but the idea is the same).

The text to be displayed, although different for each label, is
static for the lifetime of the application.

I found a solution which goes like this:

require ‘tk’
class TestForm
@hw=nil
@root = TkRoot.new() { title(“rtktest:TestForm”) }
@field1 = TkLabel.new(@root, :text => “field1”).pack();
@field1.bind(“Enter”,
proc {|e| puts(“Entering field1”)
@hw=TkToplevel.new()
helptext=TkLabel.new(@hw,:text=>“This is an example
helptext”).pack();
}
)
@field1.bind(“Leave”,
proc {|e| puts(“Leaving field1”)
@hw.destroy
@hw=nil
}
)
end
TestForm.new
Tk.mainloop

I don’t like this code for various reasons:

First, TkToplevel has a full window decoration, but a
tooltip would look better without a border etc.

Secondly, a TkLabel is not suitable for multiline text.
I would prefer something like a TkText, which formats
text automatically according to window size; but
TkText allows the user to edit the text and I would
like to have a widget which just displays multiline
text, but disallows editing.

Does someone know a better way how to create my tooltip window?

Finally, is it a good solution to pass the handle
of my tooltip window via the class variable (@hw)
from the creation procedure to the destroy procedure?

Every type of critics wellcome…

Ronald

From: Ronald F. [email protected]
Subject: Ruby/Tk : How to show tooltips (please correct my ugly
implementation)
Date: Mon, 7 Aug 2006 18:35:19 +0900
Message-ID: [email protected]

I would like to add kind of a “show tooltips” function to my
application,
which means that some piece of text should be shown when the mourse
moves
over a certain area. In my case, the “hot spot” area is a set of
TkLabel.

Please see “tkballoonhelp.rb” in “ext/tk/sample” directory
of Ruby source archive.

From: Ronald F. [email protected]
Subject: Re: Ruby/Tk : How to show tooltips (please correct my ugly
implementation)
Date: Mon, 7 Aug 2006 19:45:21 +0900
Message-ID: [email protected]

tried to adapt it to my case (the example uses a timer to
show and hide the tooltip, while I am using Enter and Leave
events - but these seem only minor differences, aren’t they?).

Hmm… Then you have to give attention the position of the
toplevel widget. If it is placed under the mouse cursor,
you’ll see the flicker of the toplevel widget.

what it actually does. (In particular, I did not understand
the reason for the variables @path and @epath).

@path is a widget path which used on many of Tcl/Tk commands
except geometry manager commands.
@epath is used for geometry manager commands.
Those are useful for mega-widget class (e.g. a class which includes
TkComposite module).
Usually, a mega-widget is constructed on a base frame.
Please think about a mega-widget which is a text widget with
scrollbars.
Many of Tcl/Tk commands are called for the text widget,
but when it is placed by a geometry manager, the path of the base
frame must be used.

Could you please show me what I did wrong?

Where is `initialize’ method?
When did you set the value of @self, @frame and @label?
On your code, @self is an uninitialized instance variable.
So, “parent = @self” means “parent = nil”.
And then, TkWinfo.toplevel(parent) means TkWinfo.toplevel(nil).
Ruby/Tk passes an empty string for a nil to the Tk interpreter.
Therefore, TkWinfo.toplevel(nil) is same as TkWinfo.toplevel(“”).
An empty string is not a widget path.
That is the reason why you get an error.

Hidetoshi NAGAI wrote as [email protected] on 07. Aug 2006:

TkLabel.
Please see “tkballoonhelp.rb” in “ext/tk/sample” directory
of Ruby source archive.

Arigatou Hidetoshi-san.

I studied the tkballoonhelp.rb and in particular I read about
the functions overrideredirect and transient, but I must admit
that I did not fully understand how it works. Nevertheless I
tried to adapt it to my case (the example uses a timer to
show and hide the tooltip, while I am using Enter and Leave
events - but these seem only minor differences, aren’t they?).
I used part of the logic in tkballoonhelp, well knowing that
it is a bit dangerous to just copy some code without knowing
what it actually does. (In particular, I did not understand
the reason for the variables @path and @epath).

Here is my solution:

class TestForm
@hw=nil
@root = TkRoot.new() { title(“rtktest:TestForm”) }
@field1 = TkLabel.new(@root, :text => “field1”).pack();
@field1.bind(“Enter”,
proc {|e| puts(“Entering field1”)
parent=@self
@hw=TkToplevel.new()
@hw.withdraw
@hw.overrideredirect(true)
@hw.transient(TkWinfo.toplevel(parent))
@epath = @frame.path
helptext=TkLabel.new(@hw,:text=>“This is an example
helptext”).pack();
@path = @label
@hw.deiconify
@hw.raise
}
)

}

def epath
@epath
end

When the label receives the focus, I get the error message
“bad window path name”, so this might be due to my misunderstanding
(and misuse) of @path/@epath.

Could you please show me what I did wrong?

Ronald

From: Ronald F. [email protected]
Subject: Re: Ruby/Tk : How to show tooltips (please correct my ugly
implementation)
Date: Tue, 8 Aug 2006 15:45:10 +0900
Message-ID: [email protected]

I see the flicker, because as soon as the toplevel widget
(my help-tooltip) is displayed, the underlying text field
looses focus and the tooltip is destroyed. Did I understand
this correct?

Yes. You are right. :slight_smile:

This means that other Tk classes (such as the geometry manager)
expect those variables to exist? Because in the example, I
haven’t seen any actual use for them.

Those important definition is done in TkWindow#initialize.
So, if you want to create a new widget class,
the class should inherit TkWindow (or some subclass of TkWindow).
TkWindow#initialize parse arguments of new' method in general rules of Ruby/Tk, and calls create_self’ method to create
a widget on the Tk interpreter.
The rule makes definition of a new widget class easier.

The only unsolved problem is that I am still using a TkLabel
for the balloon text. As I mentioned in my original posting,
I am looking for a widget which I can give an arbitrary size,
and which formats multi-line text (i.e. arranging for line
breaks automatically).

Please try TkMessage class.

editable   |   not editable

-------------±---------------
TkEntry | TkLabel
TkText | TkMessage

BTW, I’ll do presentation about achivement of Ruby/TkORCA project
the day after tomorrow.
By using Ruby/TkORCA framework, you can make your Ruby/Tk application
a network GUI application.
For example,

  1. Make a Ruby/Tk application (e.g. “app.rb”) which works on the
    local window system. You can use any helper libraries or programs
    for your application, if such helpers never draws on the display
    or can embed its drawings on Tk’s container widgets.

  2. Try “tkorca.rb app.rb”. It shows a mother window on your
    local window system, and load your application (“app.rb”)
    in a daughter (a sandbox). The mother can check and control
    the daughter includes the daughter’s window management
    (the mother works the window manager for the daughter also).
    If the application does not work on the daughter,
    you have to change some parameters of the mother, or add some
    wrapper operations for the daughter, or modify the source of
    application. But probably, amount of modification will not
    so much.

  3. Start server (e.g. “tkorca_daemon app.rb app2.rb …”).
    Then your application is a public-use network GUI application.
    Clients who connects with a kind of VNCviewr can see and use
    your application by same view and control as you tested at Step2.
    Of course, there is no native window manager, and each client
    can see and access his own mother and daughters only.
    You can get logs about connections, and can do just-on-time checks
    and controls of the running application.
    (For example, you can show an emergency dialog box on the client’s
    window independently of the status of the application.)

I think, the cost of each step is,
Step1 => 1.0,
Step2 => 0.5 (or less),
Step3 => + alpha.
The total is “1.5+alpha”.
Probably, you can make “Hello, World” netowork GUI application
in only 5 minutes or less. :slight_smile:
When based on Ruby/TkORCA, a network GUI application will require
lower cost and get faster development than other frameworks.
Maybe… :wink:

Hidetoshi NAGAI wrote as [email protected] on 07. Aug 2006:

From: Ronald F. [email protected]
Subject: Re: Ruby/Tk : How to show tooltips (please correct my ugly
implementation)
Date: Mon, 7 Aug 2006 19:45:21 +0900
Message-ID: [email protected]

tried to adapt it to my case (the example uses a timer to
show and hide the tooltip, while I am using Enter and Leave
events - but these seem only minor differences, aren’t they?).

Hmm… Then you have to give attention the position of the
toplevel widget. If it is placed under the mouse cursor,
you’ll see the flicker of the toplevel widget.

I see the flicker, because as soon as the toplevel widget
(my help-tooltip) is displayed, the underlying text field
looses focus and the tooltip is destroyed. Did I understand
this correct?

This means that on creation of the tooltip toplevel widget,
I need to specify that it is located a few pixel off the
mouse cursor. I have used the algorith in the tkballonhelp
example for this.

what it actually does. (In particular, I did not understand
the reason for the variables @path and @epath).

@path is a widget path which used on many of Tcl/Tk commands
except geometry manager commands.
@epath is used for geometry manager commands.

This means that other Tk classes (such as the geometry manager)
expect those variables to exist? Because in the example, I
haven’t seen any actual use for them.

Could you please show me what I did wrong?

Where is `initialize’ method?
When did you set the value of @self, @frame and @label?
On your code, @self is an uninitialized instance variable.

You are right! Two mistakes made in one here. First, I had
intended to use “self”, not “@self”. Second, I now realize
that the parent is not my class, but the field for the tooltip,
so it must be parent=@field1.

Also, I forgot to rename the variables @frame and @label (copied
from the balloon example) to @hw and @field1 (which are used in
my version). Thank you for pointing this out.

So this example works now. Thank you very much for helping.

The only unsolved problem is that I am still using a TkLabel
for the balloon text. As I mentioned in my original posting,
I am looking for a widget which I can give an arbitrary size,
and which formats multi-line text (i.e. arranging for line
breaks automatically). The closest thing I have found so far,
was a TkText, but this is a text entry field, and I don’t want
the user to allow to edit the displayed text. Do you have
a suggestion of what Tk widget I could use for this?

Ronald