I'm looking for a predefined tk window like tk_messageBox where a user can input a string in a white line. I couldn't find one in the Tcl / Tk man page (https://www.tcl.tk/man/tcl/TkCmd/contents.htm)...
There's no predefined popup text-entry window. You'll need to make one yourself with a toplevel, an entry and (probably) at least one button. Maybe a label too.
Here's the simplest thing that could work at all:
set foo "This is some text."
toplevel .t
pack [entry .t.e -variable foo]
pack [button .t.b -text "OK" -command {destroy .t}]
bind .t <Return> {.t.b invoke}
focus .t.e
tkwait window .t
puts "The variable contains '$foo'"
You will probably need to customise it further…
Related
I created a gui with many tabs, i would like to add button to the tab1.
However i am not good at tcl, Could someone help how to add button to the TCL gui?
Regards
toplevel .test
wm transient .test.
set pw [ttk::panedwindow .test.pw -orient vertical]
set nb [ttk::notebook $pw.nb]
foreach i {1 2 3 4} {$nb add [frame $nb.f$i] -text tab$i}
set fTkCon [frame $pw.fTkConContainer -container 1]
$pw add $nb
$pw add $fTkCon
pack $pw -fill both -expand
#add button here# ::hwtk::button -text "Text Button" -help "Text only"
In the foreach loop, you created 4 frames ($nb.f1 through $nb.f4). To add a button in tab1, you should normally create the widget as a child of the respective frame. You then need to use a geometry manager to control where the widget will appear. When just starting with GUIs, grid is probably the easiest choice.
ttk::button $nb.f1.b1 -text Button! -command {puts Pressed!}
grid $nb.f1.b1 -padx 5 -pady 5
Note: When doing this in an interactive session, you will probably have to resize the window and move the sash of the paned window to see the button.
I simplified the code a little to make it run:
package require Tk
ttk::notebook .nb
pack .nb
foreach i {1 2 3 4} {
.nb add [button .nb.f$i -text "Button $i"] -text tab$i
}
Notice to add a button to a tab, I exchanged the creation of frame in the notebook add command to creation of a button.
Is it possible to display the widget hint on mouseover of widget ?
Every Tk widget is sent an <Enter> event when the mouse pointer goes over it, and is sent a <Leave> event when the mouse pointer goes elsewhere.
# Make some widgets; the buttons are much larger than the status text
pack [button .b1 -text "First button" -font {Arial 24}]
pack [button .b2 -text "Second button" -font {Arial 24}]
pack [label .l1 -textvariable status -font {Arial 10}]
# Set up some simple bindings
bind .b1 <Enter> {set status "Over the first button"}
bind .b1 <Leave> {set status ""}
bind .b2 <Enter> {set status "Over the second button"}
bind .b2 <Leave> {set status ""}
That's the core of how you do this sort of thing. The other major thing to note is that when you click on a widget, a temporary grab is set so that all (mouse-related) events get sent to that widget until the mouse button is released. If you're wanting to work out what widget the mouse is over and you've not got it directly from the event, the winfo containing command is exactly the right tool.
You can use the tooltip package which should be among the default packages of Tcl.
package require tooltip
pack [label .l -text "Hover your mouse over me!"]
tooltip::tooltip .l "I'm a helpful hint!"
Reference:
wiki
manual
How can I get/show name of an object(variable name) on gui?
This is object name "frame"
set frame [.c1 create rectangle 50 50 200 200 -width 4 -outline "red"]
when i click on this, it will show its name in a text box or with mouse pointer. How can it be possible? please help me.
The easiest way to show a varying string in the GUI is to use a label with the -textvariable option set. Then you can just set a variable and the string will appear.
To respond to a click, a canvas item should have an event handler script bound to it. The most common events to bind to are <ButtonPress> — often written <1> for <ButtonPress-1>, which is the main mouse button — and <Enter> and <Leave>, which handle tracking of what the mouse is over. The current canvas tag tracks the current item (if any).
Combining these:
pack [canvas .c1]
# make some items here...
.c1 create rectangle 50 50 200 200 -width 4 -outline "red"
# ...
pack [frame .f1 -textvariable msg]
.c1 bind all <1> {set msg "Click on %W:[%W finditem current]"}
.c1 bind all <Enter> {set msg "Entered %W:[%W finditem current]"}
.c1 bind all <Leave> {set msg ""}
When you're experimenting with this, be sure to check out entirely transparent items (particularly fully transparent polygons). They're useful for defining hot areas that are invisible to the user, a pretty useful technique especially if they're put on top of several other items that are visible…
I'm not sure exactly what you are doing, or what you want to happen.
I assume that you have created a canvas .c1, that you have successfully displayed it in a toplevel window somewhere and that you want to respond when the user clicks on the border of the rectangle you have created.
In that case, you need to specify a binding for the click on the item
.c1 bind $frame <button-1> {puts stdout "The frame has been clicked"}
This will just print a message on the console, which is enough to prove the mechanism. You'll need to decide how you want to display it.
Alternatively, use the tooltip package from tklib, documented here, via
tooltip::tooltip .c1 -items $frame "The frame has been hovered over"
which will display "The frame has been..." if the user hovers over the border of the frame.
The docs for Ttk::button's -default option state that it's supposed to be used in dialog boxes, however the only dialog box function I know of is tk_dialog, which can't take buttons as arguments but only the button titles.
Does anyone have a working example of a Ttk::button with it's -default option set to active, where upon running the app and the user hitting the enter key this button is invoked? Here are my attempts:
I've attempted to lay out a button directly in the main window:
package require Tk
ttk::button .button -text "text" -default active -command "puts sometext"
bind .button <Return> { .button invoke }
pack .button
Pressing enter does nothing by default, I would first have to tab to select the button and then hitting enter will work.
I've also tried injecting buttons into tk_dialog, thinking the following might work:
package require Tk
tk_dialog .dg "Title" "Question" "" "" \
[ttk::button .button1 -text "Yes" -default disabled] \
[ttk::button .button2 -text "No" -default active]
But that just creates two buttons ".button1" and ".button2", and neither of them are the default-selected one. (this makes sense since the 4th parameter is empty). tk_dialog itself can specify the default button, but I cannot pass custom buttons to it, it only seems to accept strings for the button names.
The reason I'm asking this is because I'm writing a language binding to Tk and have to figure out which settings should be exposed. I've looked at Tkinter for Python, and it doesn't seem to wrap the -default option for buttons. Is this option ever used in Tk, and if so could you give me a proper working example? Thanks.
The -default option is indeed just a display indicator. What it does depends on the theme you are using. On Windows XP and above, the default active button will be bright blue. On other themes it may have a highlighted border or different edge relied. On the old classic theme it was some huge sunken border.
To actually have something happen when you hit either Enter or Escape you must bind the <Return> and <Escape> events to the relevant buttons as mentioned already.
Don't use tk_dialog. Its really old and very useless and the style doesn't conform to any modern windowing system at all.
Here's a snippet of code I use in one app to make dialogs look sensible:
proc ::tkchat::Dialog {w args} {
lappend args -class Dialog
set dlg [eval [linsert $args 0 toplevel $w]]
catch {wm attributes $w -type dialog}
wm transient $dlg [winfo parent $dlg]
wm group $dlg .
return $dlg
}
This shows a few useful things to be done. First, we have a default class for the toplevel so we can allow default configuration options for dialogs. We also set the -type attribute where supported which will set the Extended Window Manager property that lets modern X window managers style the window as a dialog and not some other kind of transient window. We also then mark it as transient for the parent window -- so the window managers know that this toplevel is actually associated with the given parent or owner window (the taskbar can avoid showing it as another application).
This would be used in something like the following:
set dlg [Dialog .options]
wm withdraw $dlg
wm title $dlg "Options"
# ... create child windows and pack / grid them
set b_ok [ttk::button $dlg.ok -text OK -underline 0 -default active \
-command [list [namespace origin EditOptionsClose] $dlg ok $pages]]
set b_cn [ttk::button $dlg.cancel -text Cancel -underline 0 \
-command [list [namespace origin EditOptionsClose] $dlg cancel $pages]]
bind $dlg <Return> [list $b_ok invoke]
bind $dlg <Escape> [list $b_cn invoke]
bind $dlg <Alt-o> [list focus $b_ok]
bind $dlg <Alt-c> [list focus $b_cn]
wm protocol $dlg WM_DELETE_WINDOW [list $b_cn invoke]
wm resizable $dlg 0 0
catch {::tk::PlaceWindow $dlg widget .}
wm deiconify $dlg
tkwait visibility $dlg
focus $b_ok ; grab $dlg
tkwait variable [namespace which -variable _editoptions]
grab release $dlg
destroy $dlg
So quite a lot going on there. We create then withdraw the dialog. This improves the performance as we place lots of children into the toplevel as by being withdrawn we can defer the geometry calculations until we have to map the whole thing. Then create the buttons and everything else and get them placed onto the toplevel. I've shown just the buttons to illustrate the -default option and also the use of -underline to show the accelerator keys.
Then bindings - Return and Escape should always be handled along with the WM_DELETE_WINDOW protocol message (thats the X button provided by the window manager or Alt-F4 on Windows). This one is also then made non-resizable and we place it over the application window using the Tk library helper function tk::PlaceWindow. Finally, we map the window and set the keyboard focus onto the active widget.
The above covers pretty much everything for a well behaved dialog I think.
The documentation (for -default) is poor and out of date.
-default active was only a display option, and did not affect what the key did. Using the old style button, -default active will turn on the sunken relief surrounding the button in the highlight background area, as an indicator that the button was the default. It's also a little confusing in that 'active' has nothing to do with the button state, and everything to do with the highlight.
The highlight background area is no longer supported for ttk:: widgets, and though the configuration options are accepted, they are not used.
If you want the key to do something particular in your dialog, bind it to the main window, rather than to a particular button:
bind . <Return> {.button2 invoke}
As patthoyts said, it is just a display option. On my machine it looks like this (with Tile)
The "Selected" button has currently the focus.
The script I used to create this is simple:
grid [ttk::button .b -default active -text Ok] [ttk::button .c -default disabled -text Cancel] -sticky nesw
grid [ttk::button .b -text Normal] [ttk::button .c -text Selected] -sticky nesw
grid rowconfigure . all -weight 1
grid columnconfigure . all -weight 1
I have been looking through several online resources trying to get my checkbutton to grey out when another button is selected. However, with all of my attempts, I cannot seem to get it to work.
The following is an example at work:
3 checkboxes called chkAll, chkBalanced, and chkFXO. Let's say that when chkAll is selected and in the active state then chkBalanced, and chkFXO are then unchecked. I've tried to use an if-statement that looks at the state of chkAll but it complains about having the state issue in the conditional portion of the block. Should I consider using variables, if so how do I implement them? I know that checkbuttons have a -variable option but I also don't really know how to use it
If you're trying to make an exclusive choice, you should not be using checkbuttons. What you are describing is the behavior of radiobuttons.
To use radiobuttons you create two or more and give them all the same variable. You will then only be able to pick one at a time.
foreach value {chkAll chkBalanced chkFXO} {
radiobutton .rb-$value -text $value -variable myvar \
-justify left -value $value
pack .rb-$value -side top -fill x -anchor w
}
If you're just wanting to have three widgets that present a mutually-exclusive choice, for goodness' sake use radiobuttons for the task. That's what they're there for. That's what users expect. (Even better, put them in a labelframe; that improves the usability for little effort.)
If you've got something else going on and need to “turn on and off” widgets based on a checkbutton, you do this by putting a write trace on the variable referenced by the checkbutton's -variable option. That trace should then enable (change to -state normal) or disable (change to -state disabled) the other widgets when it fires, based on the value of the variable.
checkbutton .cb -variable bools(cb) -text "Foo Bar"
button .other -text "Example extra content"
button .widget -text "Second ordinary button"
# NOTE the ;# at the end; IMPORTANT HACK to discard trace arguments
trace add variable bools(cb) {changed bools(cb) .other .widget;#}
proc changed {varName args} {
upvar "#0" $varName var
foreach w $args {
if {$var} {
$w configure -state normal
} else {
$w configure -state disabled
}
}
}
set bools(cb) 0; # <<< Initialize to known state
pack .cb .other .widget
This sort of thing can get quite complicated, and produce very nice GUIs. You can also mix it in with radiobuttons (with appropriate adjustments as the state variables are no longer boolean). But don't do it just for simple pick-one-from-a group; use a straight collection of checkbuttons for that.