I have been using python 3.4 and tkinter to create an application to parse logs and format data and display results in a text widget. I would like to highlight text that is located at a known position on each line in the text window. I have seen similar highlighting questions regarding highlighting text in text widgets on this site and it has been very helpful.
My problem is that I don't need to search for the string or characters to highlight. I have the locations that I want to highlight and it could be any character in that location including white space. For example: I would like to highlight positions 0, 20, 40 on each line (eg: index 1.0, 1.20, 1.40, 2.0, 2.20, etc).
Since it is large files being written to the textbox I have to do this for the entire scrollable text window, so I need to maintain the textbox line number position.
When referring to a location in a text widget, you can append modifiers to indicate relative positioning. For example, given the position "1.0", the next position can be identified as "1.0+1c" (or "1.0+1char"). So, to highlight a single character at a given offset, make the start of the range the offset, and the end of the range one character greater.
Here's a quick hack that takes one or more "positions" and highlights that position on each line:
def highlight(text, tag, *positions):
last_line = int(text.index("end-1c").split(".")[0])
for linenumber in range(1, last_line+1):
line = text.get("%s.0" % linenumber, "%s.0 lineend-1c" % linenumber)
line_length = len(line)
for pos in positions:
if pos <= line_length:
start = "%s.%s" % (linenumber, pos)
end = start + "+1c"
text.tag_add(tag, start, end)
usage:
text = Text(...)
text.tag_configure("highlight", ...)
...
highlight(text, "highlight", 0, 20, 40)
Related
I'm trying to create a chart somewhat along the lines of the Multi-Line Tooltip example, but I'd like to format the string that is being printed to have some text added at the end. I'm trying to modify this part:
# Draw text labels near the points, and highlight based on selection
text = line.mark_text(align='left', dx=5, dy=-5).encode(
text=alt.condition(nearest, 'y:Q', alt.value(' '))
)
Specifically, rather than 'y:Q' I want something along the lines of 'y:Q' + " suffix". I've tried doing something like this:
# Draw text labels near the points, and highlight based on selection
text = line.mark_text(align='left', dx=5, dy=-5).encode(
text=alt.condition(nearest, 'y:Q', alt.value(' '), format=".2f inches")
)
Alternatively, I've tried:
# Draw text labels near the points, and highlight based on selection
y_fld = 'y'
text = line.mark_text(align='left', dx=5, dy=-5).encode(
text=alt.condition(nearest, f"{y_fld:.2f} inches", alt.value(' '))
)
I think I see why those don't work, but I can't figure out how to intercept the value of y and pass it through a format string. Thanks!
I think the easiest way to do this is to calculate a new field using transform_calculate to compute the label that you want.
Using the example from the documentation, I would change the text chart like this:
text = line.mark_text(align='left', dx=5, dy=-5).encode(
text=alt.condition(nearest, 'label:N', alt.value(' '))
).transform_calculate(label='datum.y + " inches"')
That leads to this chart:
If you want more control, you could change the dataset with pandas beforhand. Be sure to set the type to Nominal (and not Quantitative) otherwise you would get NaNs in the tooltips.
With PyQt4 based QTreeView, I've created 2 xml tree widgets. From both the trees, want to compare selected items and highlight the difference. For e.g.,
Left String : "CompareString"
Right String : "ComPareStringRight"
The observations of the diff :
Left[0:2] is same as Right[0:2]
Left[3:3] differs with Right[3:3]
Left[4-12] is same as Right[4-12]
Right[13-17] is not present in Left
Now, want to set colors according to :
matching characters - default
Differing characters - Orange
Added characters - Green
Deleted characters - Red
How can I implement this? Unable to find any reference implementation to pick up from. Pls suggest a way forward.
class QCustomDelegate (QItemDelegate):
global showDiffPaint
def paint (self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex):
column = indexQModelIndex.column()
if showDiffPaint == 1:
QItemDelegate.paint(self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex)
else:
QItemDelegate.paint(self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex)
After digging, found it useful to convert text into html, and present as below.
However, found bugs due to " and < and > characters display. which I think I need to escape somehow...
options = QStyleOptionViewItemV4(option)
doc = QTextDocument()
doc.setHtml(txt1)
doc.setTextWidth(option.rect.width())
style = QApplication.style()
style.drawControl(QStyle.CE_ItemViewItem, options, painter)
ctx = QAbstractTextDocumentLayout.PaintContext()
textRect = style.subElementRect(QStyle.SE_ItemViewItemText,
options)
painter.translate(textRect.topLeft())
painter.setClipRect(textRect.translated(-textRect.topLeft()))
doc.documentLayout().draw(painter, ctx)
I have a QTextEdit window with words and letters displayed in several colors. I want to be able to retrieve the color of each part of the text when processing the contents of the window. My attempt so far has been to save the entire contents as an html file and then parse through that to extract only the text with the color information. This is very cumbersome and difficult. I would much prefer to process the text using the QTextCursor if I could retrieve the color of the text at the cursor position. I have searched for the appropriate function but have not found one.
Is there a function to retrieve the color (or the format) at the QTextCursor position?
Or alternatively is there a way to retrieve each contiguous section of words and/or characters that have the same color (or format) with the format information?
Well I have found a way to do what I wanted. Here is the relevant code:
QTextCursor tc = qte->textCursor();
tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
while(tc.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor))
{
QTextCharFormat tcf = tc.charFormat();
int bg = tcf.background().color().rgb();
int fg = tcf.foreground().color().rgb();
printf("bg=%x fg=%x\n", bg, fg);
}
any comments or improvements are welcome.
[Corrected above]: I originally had
QColor bg = tcf.background().color().rgb();
QColor fg = tcf.foreground().color().rgb();
but with .rgb() on the end, it converts QColor to int.
My task is a variation of a multiple object tracking task. There are 7 circles on the screen. It randomly selects 3 circles to change the color (red, green, blue) briefly to indicate to the participant to track these circles. After the color change, all the circles will change to the same color and the circles will move for a period of time. When the circles stop moving, a response prompt will appear, where the participant is to select one of the three colored circles ('select the red/green/blue circle'). I am having difficulty inserting which color circle to select into the formatted string. I keep getting the error message: unsupported operand type(s) for %: 'TextStim' and 'list'
I'm not sure if I need to or how to convert these lists, so any help would be much appreciated!
n_targets = 7 #seven locations
circles = [] #setting up the circle stimuli
for i in range(n_targets):
tmp = visual.Circle(win,radius = 27,units = 'pix',edges = 32,fillColor='white',lineColor = 'black',lineWidth = 1, pos=(posx[i],posy[i]))
circles.append(tmp)
cols = ['blue','red','green'] #3 colors the circles will change to
targets = random.sample(circles,3) #randomly select 3 of the 7 circles
TrialTarget = random.sample(targets, 1) #select 1 of the 3 circles to be the target for the trial
#code for movement would go here (skipping since it is not relevant)
#at end of trial, response prompt appears and ask user to select target and is where error occurs
ResponsePrompt = visual.TextStim(win, text = "Select the %s circle") %TrialTarget
In this line, you are trying to create a formatted string from a TextStim object and a Circle stimulus object rather than a string object and another string object:
ResponsePrompt = visual.TextStim(win, text = "Select the %s circle") %TrialTarget
i.e. ResponsePrompt is clearly a visual.TextStim, as you are creating it as one, and I think TrialTarget is a visual.Circle stimulus, as you randomly sample it from a list of Circles.
I'm guessing that you actually want to incorporate the colour label into the prompt text. So to fix both problems (the type incompatibility and the formatting syntax), you need to actually get one of the elements of cols, called say trialColour, and use something like this:
ResponsePrompt = visual.TextStim(win, text = "Select the %s circle" % trialColour)
i.e. here trialColour is actually a string, and the formatting operation is brought inside the brackets so it applies directly to the text string "Select the %s circle"
That should hopefully fix your immediate problem. You might also want to investigate using random.shuffle() to shuffle lists in place instead of random.sample().
Trying to get the start and end point of each line within a text pane:
The text pane contains (note target is the end of each line not including the blank space line):
(blank space line)
MVESMKKVAGMDVELTVEERN000TAQEGDHGSHVYTKQKEENKGGEDKLKMIREYRQMVETELKLICCDILDVLDKHDDDDDKVFYYKMKGDYHRYLAEFATGNDRKEAAENSLVAYKAASDIAMTELPPTHPIRLGLALNFSVFYYEILNSPDRACRLAKAAFDDAIAELDTLSEESYKDS00000VQVGQQRSDMQGDGKKKAAAEEQNKEALQDVEDENQtarget
MVESMKKVAGMDVELTVEERN000TAQEGDHGSHVYTKQKEENKGGEDKLKMIREYRQMVETELKLICCDILDVLDKHDDDDDDVFYYKMKGDYHRYLAEFATGNDRKEAAENSLVAYKAASDIAMTELPPTHPIRLGLALNFSVFYYEILNSPDRACRLAKAAFDDAIAELDTLSEESYKDS00000VQVGQQRSDMQGDGKKKAAAEEQNKEALQDVEDENQtarget
MVESMKKVAGMDVELTVEERN000TAQEGDHGSHVYTKQKEENKGGEDKLKMIREYRQMVETELKLICCDILDVLDKHDDDDDDDFYYKMKGDYHRYLAEFATGNDRKEAAENSLVAYKAASDIAMTELPPTHPIRLGLALNFSVFYYEILNSPDRACRLAKAAFDDAIAELDTLSEESYKDS00000VQVGQQRSDMQGDGKKKDDDDDDDEEQNKEALQDVEDENQtarget
//This is what I have
Element root = jTextPane1.getDocument().getDefaultRootElement();
Element one = root.getElement(0);
while (one !=null){
int one1 = one.getStartOffset();
int two1 = one.getEndOffset();
System.out.println(one1);
System.out.println(two1);
one = root.getElement(two1);
}
This is what I get (1st and 2nd element) and then hangs:
0
1
1
232
You mix model and view. Document is just model but amount of rows depends on view (width of content).
Use javax.swing.text.Utilities.getRowStart()/getRowEnd()
See an example of the code usage http://java-sl.com/tip_row_column.html