I need to make my own event handler that includes the standard up/down arrow keys' functionalities in a text widget. However, there are some quirks I have to program around somehow.
You might think you could just add/subtract a line and it would go up/down as expected. Well, that's sort of true. But, if you have the word-wrap on or something, you'll go up further than you expected on wrapped lines. Plus, the arrow key might not go up eveningly as it usually does whether or not the word wrap is on (seeing as it will stay on the same character no matter where that character is).
So, how do I simulate the regular functionality in Tkinter?
Here's why I need to reprogram the up arrow key (down also)—this isn't essential to my question, but because people like to ask and come up with alternative approaches, here you go:
I'm making a text editor, and the natural way it does things in a Tkinter Text widget has a bug that I plan to eliminate. The bug is that if you select text with shift-home or something and then try to select further text with shift-up (or shift-down, or control-shift-left or control-shift-right) then it might select or deselect some inappropriate stuff, depending on how you do it. It should be easy enough to fix control-shift-left and control-shift-right, but I have the positioning problems with shift-up and shift-down. I've already reprogrammed home, end, left, right, shift-left and shift-right for similar reasons (and Tkinter is awesome because you actually can reprogram stuff like this).
I'm using Python 3.4.
I'm thinking maybe getting the x,y coordinates of the insert might be helpful. I didn't see anything for that, though (just the mouse coordinates).
I'm not entirely sure what the problem is that you are having. Are you aware you can ask the text widget to calculate an index of the previous line or next line, and to either take wrapped lines into account or ignore the wrapping?
From the tk text widget docs on index modifiers:
+ count ?submodifier? lines
Adjust the index forward by count lines, retaining the same character position within the line. If there are
fewer than count lines after the line containing the current index,
then set the index to refer to the same character position on the last
line of the text. Then, if the line is not long enough to contain a
character at the indicated character position, adjust the character
position to refer to the last character of the line (the newline).
Spaces on either side of count are optional. If the display
submodifier is given, then each visual display line is counted
separately. Otherwise, if any (or no modifier) is given, then each
logical line (no matter how many times it is visually wrapped) counts
just once. If the relevant lines are not wrapped, then these two
methods of counting are equivalent.
You can also use a minus sign to go backwards.
For example:
next_line = the_widget.index("insert +1 display lines")
Related
I am trying to do what the Title says, Configure the Tkinter message so that each tuple in WL_ratios has its own line without being surrounded in brackets. Creating more messages is not an option as the length of WL_ratios can vary, so i have to only use the one.
#(below) is in the __init__ of the class
self.Leaderboardtext = Message(self.LeaderboardFrame,text="",width=100)
self.Leaderboardtext.pack()
#this (below) is in another function in the same class.
WL_ratios = [["james",3]["harrison",2]["jo",1]]
self.Leaderboardtext.configure(text="Leaderboard: {0}".format(WL_ratios))
So far the width=100 is the only thing that is allowing me to get text onto a new line. However this still isnt working because each tuple varies in length so some tuples spread across two lines which isnt what i want. I know you could limit each line by how number of characters but again the tuples vary in character length so i dont think that is an option.
Does anyone have any suggestions that could work?
Just convert each tuple into a string, and add \n there, and that should do it. Alternatively, you could call each value in the tuple separately, and add \n there.
I have a QTextEdit widget which is showing lines of text. I want the user to be able to select a block of text to be acted on. I need to determine the starting and ending line numbers from the complete text that correspond to the selected block.
editor.textCursor().blockNumber() gives me the correct starting line number but I haven't been able to find the line number of the ending postion.
Finding the length of the selection in lines would be fine.
I'm using PySide and Python 2.7
Use QTextCursor::selectionStart and QTextCursor::selectionEnd to get block start and end position (as an int).
Then get copy of the text cursor, use QTextCursor::setPosition to set position to these two, and use QTextCursor::blockNumber to get the line numbers.
There may be a shorter way, considering how QTextCursor has quite a lot of methods, but this should work. You may want to write a helper method, for example one which takes the position and a QTextDocument or QTextCursor, and returns the line number for that position.
I am trying to determine the number of lines displayed on the screen in a wxPython styledtextctrl with word wrapping enabled.
I have seen several answers to visible lines here:
wxPython - StyledTextCtrl get currently visible lines
Get visible lines in Scintilla.NET component
The second one if for C# but since the base is still scintilla I thought it was relevant.
The problem with these solutions is while they give the lines, they do so assuming that word wrapping is not enabled. If it is enabled, and some of the lines are wrapped, then the following scintilla function returns the value if wrapping were not enabled:
LinesOnScreen()
So my question is is there any way to get the number of lines on the screen given that word wrapping is enabled?
I assume what you want is the number of document lines, rather than the number of display lines. So if wrapping is enabled, the former will be less than the latter if any lines are wrapped.
As you've already discovered, LinesOnScreen() will give the number of visible display lines. But there is currently no built-in facility to get the number of visible document lines, so it will need to be calculated.
A complete solution could be quite complex, especially if you need to take into account things like line-folding and annotations. But a very basic solution would go something like this:
index = editor.GetFirstVisibleLine()
lines = editor.LinesOnScreen() + index
count = 0
while index < lines:
index += editor.WrapCount(index)
count += 1
But note that this does not attempt to deal with partial lines at the top and bottom of the screen (which is left as an exercise for the reader).
Writing long docstrings and long comments is annoying because of the 80-characters width limit.
For example, I write something like:
def fun(self):
"""Return some thing
This function do some complex work and return something that need a
long sentence to describe
"""
And then I found I need to insert something in the third line of docstring. After inserting, the width is much longer than 80 characters, so I manually break it. However, after breaking, the length of forth line is much less than 80, and I have to merge the forth and fifth line, and break it at some proper place so that every line is not too short and too long. If there are more lines, this job gets more annoying.
Similar problem occurs when I found I have to delete something in the third line. Is there any trick, or plugin of PyCharm that deals with this problem? Since I'm using vim plugin in PyCharm, tricks for vim are also great.
Edit -> Fill Paragraph
Merges a paragraph, i.e. a text region without a blank line between.
If you want it to leave text alone you need a blank line between it and the text where the focus is
I'm using wx.TextCtrl.SetStyle() in my code, but it's changing the style of all the text!
Here's my code:
# Get all the words in my TextCtrl
words = self.GetValue().split(" ")
# Find out what the farthest uneditable word is.
farthest_uneditable = (len(words) // length_constants["words_per_block"]) * length_constants["words_per_block"]
# Use this word knowledge to calculate the actual farthest uneditable character is
farthest_position = 0
for word in range(farthest_uneditable):
farthest_position += len(words[word]) + 1
# Make all the uneditable text (everything from the beginning to farthest_uneditable) have a grey background
self.SetStyle(0, farthest_position, wx.TextAttr(wx.NullColour, (84, 84, 84)))
I've tested this code and made sure my farthest_position isn't at the end of my TextCtrl (It's been in the expected position each time). For some reason though, all of the text in my TextCtrl box is getting a grey background.
From the wxPython 2.8 documentation. The last paragraph explains where your problem is:
"
**wxTextCtrl::GetRange
virtual wxString GetRange(long from, long to) const**
Returns the string containing the text starting in the positions from and up to to in the control. The positions must have been returned by another wxTextCtrl method.
Please note that the positions in a multiline wxTextCtrl do not correspond to the indices in the string returned by GetValue because of the different new line representations (CR or CR LF) and so this method should be used to obtain the correct results instead of extracting parts of the entire value. It may also be more efficient, especially if the control contains a lot of data."