Display the tail of a filename in an entry box

筅森魡賤 提交于 2019-12-22 16:43:34

问题


I regularly find myself writing Tk dialog boxes using ttk::entry widgets to prompt for a filename. I save the user's last input to such a dialog and display it as the default when next displaying it.

After I've populated the widget, if the full filename is longer than the entry box, then it will display the leftmost few characters which are generally the less interesting part of the filename and I'd rather it displayed the rightmost characters.

I found that attempting to use $entryWidget xview immediately didn't work very well - it did nothing, which I assume was because of some race condition - so I have taken to writing

after $N $entryWidget xview moveto 1.0

Is there a better way, and if not, what is a good choice for N? I dislike having magic numbers and as far as I recall, after 0 didn't work properly and neither did after idle.

Here's an example demonstrating the problem

package require Tk

set ent [ttk::entry .ent]
pack $ent -fill both -expand yes

$ent insert end "The quick brown fox jumps over the lazy dog"
after 1000 $ent xview moveto 1.0

set btn [ttk::button .btn -text Dismiss -command exit]
pack $btn -fill both -expand yes

Without the after 1000 at line 5(?) there is no error, and no effect. If I try after 10 there is no effect. If I leave out the after n and do update idletasks; $ent xview moveto 1.0 there is no effect.

"No effect" means that the dialog box displays "The quick brown fox jumps", the remainder of the string is hidden. With the code as above, it displays that initially but after a second (as expected, indeed, as coded) it switches to display "jumps over the lazy dog" with the rest hidden. It's undesirable for the user to be able to see the unscrolled text, but I can't work out how to avoid it other than by choosing a magic number of milliseconds to wait.


回答1:


This is a vastly tricky problem, much more than it appears to be at first. The issue is that it takes the processing of rather a lot of idle events (which take an uncertain but non-zero amount of time) for the content to be comprehended enough for the showing of the end of the data, and this processing happens after the usual events that you bind to for this sort of thing (<Map> and <Configure>).

[EDIT]: It turns out that what you need to do is to postpone the adjustment to the viewing location really late in the drawing process, to the <Expose> event which is where the windowing system asks for things to actually be displayed on the screen. (There's a complex series of events that are choreographed to actually deliver a window to the screen, with <Map> being a notify that the window is to appear, <Configure> being a notify of a change to the size of the window, and <Expose> a request to actually draw something.)

set ent [ttk::entry .ent]
pack $ent -fill both -expand yes
$ent insert end "The quick brown fox jumps over the lazy dog"

bind $ent <Expose> {
    # IMPORTANT! Unregister this event handler!
    bind %W <Expose> {}
    # Reposition the view on the content
    %W xview [%W index end]
}

set btn [ttk::button .btn -text "Dismiss" -command exit]
pack $btn -fill both -expand yes

The tricky bit is that we want to act in response to just the first <Expose> event, rather than every one (as rather a lot are delivered over the life of an application; there's also a built-in handler for this event at the low level of the implementation of the application that actually does the double-buffered drawing). This means that we need to include a de-registration (otherwise the window will be “nailed to the end”).

This code only works for content placed in before the first time a window is shown. To move it after that, call ttk::entry::See $ent end (which is what the ttk::entry binding implementation scripts use for that purpose).




回答2:


end is a valid index, so you could say

$entryWidget xview end

Depending if your entry widget is not in readonly or disabled state, you could:

bind $entryWidget <FocusOut> {%W xview end}

I'm surprised .ent xview end returns an error. This works for me:

$ tclsh
% package req Tk
8.5.10
% entry .e
.e
% pack .e
% .e conf -textvar foo
% set foo {qpowieurpoqwyerpiqyweritqywpeityqwpeitrqiweyrioqwter1234}
qpowieurpoqwyerpiqyweritqywpeityqwpeitrqiweyrioqwter1234
% .e xview end

The entry widget displays 1234 at the end.



来源:https://stackoverflow.com/questions/17231119/display-the-tail-of-a-filename-in-an-entry-box

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!