Tkinter selecting text by index - python-3.x

I am implementing a search function in python with Tkinter and would like to select the first match it comes to. I have seen many examples with creating a tag_config to highlight the background of the indexed range, however I would like to select the text (the same way one would by clicking at the first index, then shift clicking the last index).
Thus far I have got both the start and end index of the area I need to select, I just don't know the command to "select" the text with that information.
My current code (that uses a highlight approach) is:
def search_command():
word = askstring("Search", "Enter word to search")
length = len(str(word))
pos = textPad.search(word, '1.0', stopindex=END)
row, col = pos.split('.')
endlen = int(col) + length
end = row + '.' + str(endlen)
textPad.tag_add("found", pos, end)
The "found" tag just highlights the background of the text rather than selecting it.
Any help with finding the correct function would be greatly appreciated.

The selection is defined by the "sel" tag. Apply that tag to the range of text you want selected:
textPad.tag_add("sel", pos, end)

Related

How do I extract a series of numbers along with a single letter followed by another series of numbers?

The problem that I'm facing is that I have an entire column that has text separated by _ that contains pixel size that I want to be able to extract but currently can't. For example:
A
Example_Number_320x50_fifty_five
Example_Number_One_300x250_hundred
Example_Number_two_fifty_728x49
I have tried using Substitute function to grab the numbers which works but only grabs the numbers when I need something like: 320x50 instead I'm getting 0, as I'm not sure how to exactly extract something like this. If it was consistent I could easily do LEFT or RIGHT formula's to grab it but as you can see the data varies.
The result that I'm looking for is something along the lines of:
A | B
Example_Number_320x50_fifty_five | 320x50
Example_Number_One_300x250_hundred | 300x200
Example_Number_two_fifty_728x49 | 728x49
Any help would be much appreciated! If any further clarification is needed please let me know and I'll try to explain as best as I can!
-Maykid
I would probably use a Regular Expressions UDF to accomplish this.
First, open up the VBE by pressing Alt + F11.
Right-Click on VBAProject > Insert > Module
Then you can paste the following code in your module:
Option Explicit
Public Function getPixelDim(RawTextValue As String) As String
With CreateObject("VBScript.RegExp")
.Pattern = "\d+x\d+"
If .Test(RawTextValue) Then
getPixelDim = .Execute(RawTextValue)(0)
End If
End With
End Function
Back to your worksheet, you would use the following formula:
=getPixelDim(A1)
Looking at the pattern \d+x\d+, an escaped d (\d) refers to any digit, a + means one or more of \d, and the x is just a literal letter x. This is the pattern you want to capture as your function's return value.
Gosh, K Davis was just so fast! Here's an alternate method with similar concept.
Create a module and create a user defined function like so.
Public Function GetPixels(mycell As Range) As String
Dim Splitter As Variant
Dim ReturnValue As String
Splitter = Split(mycell.Text, "_")
For i = 0 To UBound(Splitter)
If IsNumeric(Mid(Splitter(i), 1, 1)) Then
ReturnValue = Splitter(i)
Exit For
End If
Next
GetPixels = ReturnValue
End Function
In your excel sheet, type in B1 the formula =GetPixels(A1) and you will get 320x50.
How do you create a user defined function?
Developer tab
Use this URL to add Developer tab if you don't have it: https://www.addintools.com/documents/excel/how-to-add-developer-tab.html
Click on the highlighted areas to get to Visual Basic for Applications (VBA) window.
Create module
Click Insert > Module and then type in the code.
Use the user defined function
Note how the user defined function is called.

Splitting a string of a multiline textbox by lines

I want to split the text of a textbox after a specific amount of visible lines.
I've found some codes that "allows that", but all of them consider the lines by the "vbCrLf" parameter, but i want to split using the visible lines of a multiline textbox.
To make it more clear to understand, consider a multiline textbox with the following text:
"The history of textbooks dates back to civilizations of ancient history. For example, Ancient Greeks wrote texts intended for education. The modern textbook has its roots in the standardization made possible by the printing press. Johannes Gutenberg himself may have printed editions of Ars Minor, a schoolbook on Latin grammar by Aelius Donatus. Early textbooks were used by tutors and teachers, who used the books as instructional aids (e.g., alphabet books), as well as individuals who taught themselves."
When i use the Textbox.Linecount function it returns the number 6 because the textbox shows six lines (which depends on the size of the control), but if i use a function like strText = Split(TextBox.Text, vbCrLf) it will return 1, because there is only one vbCrLf. But i need to split the text into two textbox considering the visible lines of the control, something like what happens in page breaks of MS Word.
For a better visual explanation, please look at the attached image.
Example
Firstly, I'm not convinced there is a robust and elegant way to do this, but it was fun to experiment and it might be useful to you.
The following will split the contents of TextBoxInput into TextBoxPage1 and TextBoxPage2 breaking on the line number specified by PAGED_TEXT_BOX_LINES.
It uses the textbox itself to detect natural line breaks and thus implicitly caters for the size of the textbox, the font, etc.
The desired line count is hard coded as a constant - not doing this would require an alternative of calculating the line height of the textbox (requiring calculations based on the font metrics and the textbox's internal line-leading size).
It only handles two "pages". But the concept could be extended simply by repeating the process based on the remainder of text that ends up in TextBoxPage2.
Private Sub CommandButton1_Click()
Const PAGED_TEXT_BOX_LINES As Integer = 5
Dim text As String
Dim i As Long
Dim textLength As Long
Dim curLine As Integer
text = TextBoxInput.text
textLength = Len(text)
TextBoxPage1.SetFocus
'add characters of the input string until the first page textbox
' exceeds maximum line count
For i = 1 To textLength
TextBoxPage1.text = Mid$(text, 1, i)
If TextBoxPage1.LineCount > PAGED_TEXT_BOX_LINES Then
'retreat cursor until we reach previous line, so we can
' detect the word that wrapped
curLine = TextBoxPage1.curLine
Do While TextBoxPage1.curLine = curLine
TextBoxPage1.SelStart = TextBoxPage1.SelStart - 1
Loop
'the remaining text after the SelStart is what
' wrapped, so stop page 1 after SelStart
TextBoxPage1.text = Mid$(text, 1, TextBoxPage1.SelStart)
TextBoxPage2.text = Trim$(Mid$(text, TextBoxPage1.SelStart + 1))
Exit For
End If
Next i
End Sub

How to reverse search in Excel?

I have a text in a worksheet like:
The girl is very beautiful
I want a formula to perform a search from right to left for the word "very", and if found then extract it to some other region of the sheet.
Note: Purpose of doing reverse search is because I want to implement it in my workbook which requires reverse search.
At least, say me how to revert the text like this :
beautiful very is girl The
Then I can do a normal search. I don't know VBA so please give some formula.
VBA Function to reverse the words in text:
Public Function StrReverse(strIn As String, Optional Delimiter As String = " ") As String
'Reverse the words in 'StrIn', split on a "Space" unless 'Delimiter' is specified
Do While InStrRev(strIn, Delimiter) <> 0
StrReverse = StrReverse & Delimiter & Right(strIn, Len(strIn) - InStrRev(strIn, Delimiter))
strIn = Trim(Left(strIn, InStrRev(strIn, Delimiter) - 1))
Loop
StrReverse = Trim(StrReverse & Delimiter & strIn)
If Left(StrReverse, 1) = Delimiter Then StrReverse = Right(StrReverse, Len(StrReverse) - 1)
End Function
For example, if cell A1 contains:
The girl is very beautiful
...then you could enter in another cell:
=StrReverse(A1)
...which would return:
beautiful very is girl The
To add a custom VBA function to a workbook:
Copy the code for the function you want to add to Excel (from above).
In an Excel, workbook, press Alt + F11 to open the VBA Editor (VBE).
Press Alt + I M to insert a new module.
Press Ctrl + V to paste in the code.
Press Alt + F C to return to Excel.
Edit #1:
Added optional delimiter to function above (defaults to a " " space).
Also, FindReverse (below), which allows VBA's (little-known) InStrRev function to be used on worksheets.
Public Function FindReverse(StringCheck As String, StringMatch As String, _
Optional Start As Long = -1) As Long
'Returns the position number of the last occurrence of 'Stringmatch"
'within StringCheck', Optionally specify the position number from the
'end to begin the search. (-1 = Begin at the end)
FindReverse = InStrRev(StringCheck, StringMatch, Start)
End Function
Edit #2:
LOL # Myself ... I'm always telling people not to try to recreate functionality that's already built into MS Office, and it seems that I unwittingly did the same thing -- even giving it the same as the existing VBA Function.
Built-in VBA function:
I realize that it's not identical functionality as the StrReverse function I wrote (above) but I suspect it also could have solved OP's original inquiry...
Nonetheless, I am really surprised that VBA even allows a custom function to have the same name as a built-in function!
How to confuse VBA:

VBA: How to start and end a list, bulleted or numbered, in Word?

I just can't figure out how to get VBA to start a bulleted list in Word.
I've got some code that types out stuff into word, I can get font and paragraph formatting, no problem, but now I want to create a bulleted list. I've found the following code,
ListFormat.ApplyListTemplate ListTemplate:=ListGalleries(wdBulletGallery).ListTemplates(2)
which should create a bulleted list of the second standard type, but all I can determine is to use it with a 'Range' command which causes the entire document to have the list applied to it. What I'd like to do is have it applied just to the new line that I'm having the code type, and then, at some point, be able to turn the list off, to be able to continue without the list being applied.
Thanks!
This link should help you with your query:
VBA - Bullet Points
Basically this code applies it to a selection:
Selection.Range.ListFormat.ApplyBulletDefault
And this code adds it to the selected paragraph number (in this case paragraph 2):
Documents("MyDoc.doc").Paragraphs(2).Range.ListFormat _
.ApplyBulletDefault
This code applies the Bullet points to a range of paragraphs:
Set myDoc = ActiveDocument
Set myRange = myDoc.Range( _
Start:= myDoc.Paragraphs(3).Range.Start, _
End:=myDoc.Paragraphs(6).Range.End)
If myRange.ListFormat.ListType = wdListNoNumbering Then
myRange.ListFormat.ApplyBulletDefault
End If
Assuming you know the text that is being added, you can use the second example. If you don't know how many paragraphs are being added, then each time you create a new one, increment an integer by 1 and use that integer in the third example.
For Example:
Start:= myDoc.Paragraphs(2).Range.Start, _
End:=myDoc.Paragraphs(i).Range.End)

Format individual characters in a single Excel cell with python

I am using xlrd, xlwt, and xlutils on the Windows Vista OS with Python 2.7. I have a set of DNA sequences in an excel worksheet that are 100 characters long, with each sequence in a single cell. I am trying to highlight characters at specific positions within each of these sequences in excel (bold them or change color), but have not found a way to format individual characters within a cell. Applying a style applies it to the entire cell to my knowledge. Therefore I am trying to break the sequences down into individual components where some parts of the sequence will be modified with a style while others won't, and to then collate these back together into a single string in a single cell.
Code:
rb = open_workbook('Mybook', formatting_info=True)
rs = rb.sheet_by_index(0)
wb = copy(rb)
ws = wb.get_sheet(0)
minus35style = xlwt.easyxf('font: bold 1') # style I'd like for just one character
for b in range(0, 368, 1):
rscellin = rs.cell(b,9)
f = rscellin.value
tominus35 = str(f[0:34])
minus35 = str(f[35:36])
ws.write(b, 14, tominus35)
ws.write(b, 14, minus35, minus35style)
wb.save('Mybook')
My problem is that adding a style changes the whole cell, and I want just certain characters to be modified. Additionally, subsequent writing to the same cell overwrites what was there previously. Is there a way to modify individual characters in a single cell, or to add differently formatted text to an existing cell that already has text in it?
Please let me know if you require additional information that I've overlooked. I appreciate your time in advance.
Brett
Recent versions of xlwt include the ability to use Rich Text within a cell. Where normally you would use ws.write, use ws.write_rich_text instead. The first two parameters are the row index and column index, as usual; but the next parameter is a sequence of components. Each component can either be a "naked" text value or a (text, font) pair. The naked text values will use the font from the cell's overall style, which can be specified using the optional fourth parameter.
For the (text, font) pairs, it is simplest to generate fonts using the new easyfont feature, which is kind of like easyxf but only for fonts. Here is an example:
import xlwt
wb = xlwt.Workbook()
ws = wb.add_sheet('Sheet1')
font0 = xlwt.easyfont('')
font1 = xlwt.easyfont('bold true')
font2 = xlwt.easyfont('color_index red')
style = xlwt.easyxf('font: color_index blue')
seg1 = ('bold', font1)
seg2 = ('red', font2)
seg3 = ('plain', font0)
seg4 = ('boldagain', font1)
ws.write_rich_text(2, 5, (seg1, seg2, seg3, seg4))
ws.write_rich_text(4, 1, ('xyz', seg2, seg3, '123'), style)
wb.save('rich_text.xls')
You should be able to adapt the above for your purposes. Note that you still have to write or overwrite the whole cell at once; you can't go back and update only part of a cell later.

Resources