How would i go about setting up a Tkinter Text widget to do something similar to IDLE's entry? For example:
>>> Entry goes here!
However, i know how to insert them at the beginning of each line, but how would i go about making it non deletable, so that you cannot delete the >>>? I have searched around on google about this, but to no avail.
If the solution only has to be "Good Enough", the technique I would use is this:
When you insert the prompt, remember the index of the end of the prompt.
Add a binding to the widget for the events you care about (eg: <BackSpace> and <Delete> and <<Cut>>)
In this binding you can look at the index of the insertion cursor and selection, and if it's prior to the saved index, ignore the event (ie: do a return "break").
This should work more-or-less OK, though it allows you to insert characters prior to the prompt. Rewriting all the bindings that alter a text widget is a fairly daunting task, but just tracking deletes isn't too hard.
To solve the problem perfectly would require you write a little tcl code to intercept the low level insert and delete commands of the actual widget. It's possible, though it requires a decent understanding of the underlying tcl code. For an example, see this answer: https://stackoverflow.com/a/11180132/7432
Related
When I try to select all of the text in a file, I receive a notification that says:
(Ctrl + A) was pressed. Waiting for second key of chord...
Here is a screenshot of my "select all" keyboard shortcuts. How can I use Ctrl + A to select all text instead of getting a chord notification?
You have another key binding that begins with Ctrl+A, something like this:
A sequence of multiple keystrokes pressed one after another (rather than simultaneously) is called a "chord".
You might have accidentally created it, or might have recently installed an extension that adds the problematic binding. To find it, do like I have done in the screenshot and type "ctrl a" into the Keyboard Shortcuts search box (that tab can be opened by typing Ctrl+K then Ctrl+S). Then look for a binding that begins with Ctrl+A but has something else after it (in my case, another Ctrl+A, but it could be almost anything).
When you find the offending binding, right-click on it, and either remove or change it. Then Ctrl+A alone will resume working.
Note: This question and its answer pertain to Visual Studio Code, which is different from Visual Studio. See this question for information about the equivalent situation in Visual Studio.
You might be in a situation where you want to keep the chorded keybindings that are causing you the problem with your original keybinding. A potential workaround to this issue is turning your original keybinding into a chord as well. For example, you could having a 'stop' character that exits your chord. For example, "Ctrl+A ." where "." is your stop character.
So if for some reason you really liked "Ctrl+A" as the beginning keystroke for a bunch of chorded keybindings, then rebinding all current "Ctrl+A" keybindings to "Ctrl+A ." would free up that keystroke for any manner of other, chorded keybindings.
I was in a situation where Ctrl+x did not work and was considered the start of a keychord. Every time I pressed Ctrl+x, instead of cutting the selected text, the editor told me that it was waiting for the second key of the chord.
Looking at "Preferences->Keyboard shortcuts" did not help. Searching for Ctrl+X in the list showed that only the "Cut" command was mapped to this key.
I had to edit the file $HOME/.config/Code/User/keybindings.json (under Linux) and search for CTRL+x. It turned out another command was mapped to a keychord starting with this key combination. I am not sure know how I got in this situation.
In my case, reloading VS Code with extensions disabled fixed it, so I knew it was an extension. Took a while, but eventually figured out it was https://github.com/phsantos/nano-id-generator.
I have been working on text editor for writing stories. I am using Python, GTK+ 3 and GtkSourceView 3. The main point of the editor is folding certain regions. While there is no - not yet? - built-in support for folding in GTK TextView / SourceView, I have been using tags with invisible=True and SourceView's source marks to implement the feature.
Source code available here: https://github.com/mkoskim/mawe
The core editor (SourceBuffer and SourceView) is located here: https://github.com/mkoskim/mawe/blob/master/gui/gtk/SceneView.py
https://github.com/mkoskim/mawe/blob/master/gui/gtk/SceneBuffer.py
For testing purposes, you can clone the repo, and run the app with:
mawe$ ./mawe.py test/test.txt
Now, the application keeps frequently and randomly crashing to errors like this:
(mawe.py:10556): Gtk-WARNING **: /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtktextbtree.c:4034: byte index off the end of the line
(mawe.py:10556): Gtk-ERROR **: Byte index 1362 is off the end of the line
Trace/breakpoint trap
There is no other error or warning logs. I have been googling the error without any success.
Other symptoms seem to be:
Crashes happen even if the editor is idling
Today I figured out that strangely I can get the crash very quickly by moving mouse over the hidden section :o
I can't be 100% sure, but I think this is related to invisible regions.
Question: Does anyone happen to know if this is some known bug?
Question: Does anyone have any ideas where I could look for possible solutions? Any ideas what can cause the crash, and what I could explore more deeply?
Update: I made some more extensive testing with tags. No other properties seem to react to mouse moves, but when turning invisibility on, mouse moves across the region crash the application. I have been searching for reports mouse events crashing gtktextbtree, but without success so far. Looks like this applies to several v3.x GTK versions.
UPDATE: I think I have almost found a workaround for this: filtering out motion-notify events from GtkSource.View seems working, like this:
def filter_event(widget, event, *args):
# Allow these
if event.type == Gdk.EventType.KEY_PRESS: return False
if event.type == Gdk.EventType.KEY_RELEASE: return False
# Block these
if event.type == Gdk.EventType.LEAVE_NOTIFY: return True
if event.type == Gdk.EventType.MOTION_NOTIFY: return True
# Print & allow the rest
print(event)
return False
self.text.connect("event", filter_event)
Application still crashes, if you press mouse button near the hidden lines, but seemingly it does not crash to mouse movements anymore.
UPDATE: More investigations. Although blocking mouse events will prevent crashes, it also causes quirks, e.g. it is not possible to use mouse to place cursor, select areas, DnD, ... Also, mouse cursor can disappear because it is not updated correctly every time. I am pretty sure there is a bug in algorithm converting mouse/window coordinates to buffer positions (when there is larger hidden blocks in the text), and thus any mouse event can crash the application.
UPDATE: I have been trying to create simple test case for the subject. Good things: hiding seems to be working. Bad things: Can't yet reproduce the problem. The test script can be found here:
https://github.com/mkoskim/mawe/blob/master/gui/gtk/test/hidecrash/hidecrash.py
UPDATE: Trying to figure it out - test case works, editor does not work. The difference to test case is at least that editor puts hidden tags in event loop(*). Trying to make a test case for that...
(*) There is definitely many different solutions to implement folding with the current Gtk SourceView/TextView. I chose the approach to use "markup" language and applying the folding while editing, as it works with undo/redo. I have tried also other solutions, like:
Cut folded scene & insert a widget to text buffer, containing the text itself. Idea: "text [part chosen for folding] text" -> "text [anchor + widget with cut text] text" - Sadly, it does not work with undo/redo.
Cut text, give it an ID, and place a specifially marked part containing the ID in the buffer. Idea "text [part chosen for folding] text" -> "text [ID w/ hidden + protected tags] text" - does not work, because cut'n'paste nor undo/redo do not apply tags, so user can destroy the marks.
Plain marks: It is just unbelievably hard to try to keep marks with the folding indicators. You would need something like "[char][mark][char]" with protected tags and such to make sure that you don't loose the mark somewhere.
Anyways, I'll keep investigating.
UPDATE: Still can't reproduce the problem in my test script, but found something possibly interesting: folding the last scene does not cause the crash - only when folding scenes that follow another scene (folded or not).
I have a fix to the problem. I just don't understand why it works, and why I can't reproduce the problem with test script. Here is the snippet that performs the folding:
fold_start = at.copy()
fold_start.forward_to_line_end()
fold_start.forward_char() # Comment this line -> crash
fold_end = self.scene_end_iter(end)
self.apply_tag(self.tag_fold_hide, fold_start, fold_end)
at is derived at insert-text or delete-range callback and pointing to the line start. fold_end is TextIter to either next scene mark or end of file. If we look the buffer content, it is something like this:
<mark 1><at>Scene 1 heading<eol>
Line
Line
<mark 2>Scene 2 heading
Applying hide tag from <eol> to <mark 2> causes crash. Applying tag from <eol + 1> to <mark 2> works as intended. If folded to the end of file (<mark 2> == buffer.get_end_iter()), folding works. In certain cases it also works, if there is just line feed to be hidden, but not in every case.
As said, I don't understand why this works and why I can't reproduce the problem with simpler script, but I keep investigating more, although now when having a fix, it is not that urgent.
OK, so yesterday I did so, that both the visible and invisible parts are formatted with similar font descriptions. I can't still reproduce this problem with simple test script, but it seems that if visible and hidden part are too far from themselves, something goes wrong with the offset calculations. So far I know that:
The error message, like Byte index 1362 is off the end of the line
Trace/breakpoint trap is about 5-7 bytes off from the length of the part that was hidden.
When the visible and invisible parts are "close enough" to each other in terms of font size, padding and weight, the error does not appear. In my working example, I format the invisible part with the exactly same font, weight, size and so on, and the program does not crash anymore.
I recently made a simple notepad-like text editor but now I want to implement things like syntax highlighting certain words and automatic indentation as you type. How could I do this dynamically as the user types. So far everything I've done is event-based so I'm guessing I need to have some sort of loop that constantly checks the contents of the textbox as the user is typing? Is tkinter not suited for this? Appreciate it if you steer me in the right direction as to how I can implement this.
Tkinter is quite well suited to this sort of thing. It's possible to make a very smart text editor if you're willing to put in some effort.
This answer shows how to get the text widget to fire an event whenever something in the text widget changes. It's a little complicated, but fairly foolproof.
If you want something simpler, you can simply bind on <Any-KeyRelease> which will fire an event whenever the user releases a key. You can then use the information in the event object to decide what to do. It won't handle the case where you cut and paste with the mouse, for example, and your binding will fire for arrow keys and other non-inserting keys, which is why I recommend the more complicated solution.
This answer shows an example of using a binding on <space> to do do a simple spellcheck, and also shows a fairly simplistic implementation of a toolbar with a "bold" button.
So I currently have a ScrolledPanel that contains a number of TextCtrls that are placed in a vertical BoxSizer programmatically. The reason I'm doing this instead of just appending lines to one big scrolled TextCtrl is so that I can also add other controls in between the TextCtrl, such as images or stylized expand/contract folding stuff.
However, this particular implementation is causing a problem - namely that it is impossible for the user to select text across multiple TextCtrls. Is there a way to do this that will be fast, clean, idiomatic, and not especially kludgy? Is my best bet to write a pointer-location text selection algorithm that essentially reinvents the wheel for the text selection stuff of the underlying native libraries, or is there an easier way to embed other controls inside a multiline scrollable TextCtrl, or even select text across multiple TextCtrls natively?
I would stay away from trying to reimplement text selection controls if at all possible, since that is bound to turn very messy very fast. Another way you could tackle this issue would be to use a single multi-line textctrl widget with the other widgets tacked on over it. This is also messy, but less so.
You can place the other widgets over the textctrl simply by placing them directly over the same position as the textctrl, so long as the other widgets have the same parent as the textctrl. This should work, so long as you don't overlap with the vscrollbar (or, better yet, remove it entirely with style=wx.TE_NO_VSCROLLBAR).
The next thing you'll need to do is pre-fill and space your textctrl so that the user has control of text only right after the position of each widget. You should have each line of text with a different spacing setting, set with the spacing options of wx.TextAttr (the more generic versions of double-spacing, etc), which you calculate based on the particular widget spacing you've given your app. This is necessary to force the user to type only exactly where you want them to.
Next, you'll need to set up a binding to the textctrl newline character that recalculates the spacing needed for each line. Once you've figured out how to handle spacing, this shouldn't be too difficult.
Finally, after you select the text, just reset everything to the same spacing, or whatever else suits your fancy, so that you don't get awkward linebreaks when you paste it back in elsewhere.
I know this is a complicated answer, but it's a complicated issue you raised. This is, I believe, the most efficient way to solve it, and avoids all the bugs that would arise from completely overhauling the textctrl, but it does involve messing around with auto-correcting linebreaks and spacings, which can be a little tricky at first.
Beginner python learner here. I have a question that I have tried to Google but I just can't come up with the proper way to ask in just a few words (partly because I don't know the right terminology.)
How do I get python to detect other widgets? For example, if I wanted a script to check and see when I click my mouse if that click put focus on an entry widget on a (for example) website. I've been trying to get it to work in Tkinter and I can't figure out even where to begin.
I've seen this:
focus_displayof(self)
Return the widget which has currently the focus on the
display where this widget is located.
But the return value for that function seems to be some ambiguous long number I can't decipher, plus it only works in its own application.
Any direction would be much appreciated. :)
Do you mean inside your own GUI code, or some other application's/website's?
Sounds like you're looking for a GUI driver, or GUI test/automation driver. There are tons of these, some great, some awful, many abandoned. If you tell us more about what you want that will help narrow down the choices.
Is this for testing, or automation, or are you going to drive the mouse and button yourself and just want something to observe what is going on under the hood in the GUI?
>How do I get Python to detect other widgets?
On a machine, or in a browser? If in a machine, which platform: Linux/Windows (which)/Mac?
If in a browser, which browser (and major version)?
> But the return value for that function seems to be some ambiguous long number I can't decipher
Using longs as resource handles is par for the course, although good GUI drivers also work with string/regex matching on window and button names.
> plus it only works in its own application.
What do you mean, and what are you expecting it to return you? You should be able to look up that GUI object and access its title. Look for a GUI driver that works with window and button names.
Here is one list, read it through and see what sounds useful. I have used AutoIt under Win32, it's great, widely-used and actively-maintained; it can be called from Python (via subprocess).
Here are comparisons by the author of PyWinAuto on his and similar tools. Give a read to his criticisms of its structure from 2010. If none of these is what you want, at least you now have the vocabulary to tell us what would be...