Member Avatar for ampoliros

I am using a Pwm TextDialog (which inherits from ScrolledText which inherits from Text).
It is being used as a real time status pop-up window. A good deal of the status messages use a carriage return ('\r') at the end of the message as a way of conserving vertical space, i.e. percentage done messages.

If I appendtext() the message raw the carriage return gets translated into a period and the output is quite ugly. Doing a replace() of the '\r' to a '\n' makes for an extremely long status box.

I can't find a way to alter the INSERT point without placing any text as well.

The only solution I can find is to parse the output character by character looking for a '\r' and then doing:

for cur_char in list(text_to_output):
    if cr != True and cur_char == '\r'
        cr = True
        continue
    else:
        cr = False
    if cr == True:
        insert(INSERT + " linestart", cur_char)
        cr = False
    else
        insert(INSERT, cur_char)

There must be a more efficient method. Please help.

Thanks,

ampoliros

Can't you .split('\r') and insert with linestart line by line?

find() will locate a character

found = 0
while found > -1:
    found = text_to_output("\r")

You can then use split() and/or replace to create the modified output.

print text_to_output.split("\r")
Member Avatar for ampoliros

Sorry it took me so long to get back... I got pulled over to another project temporarily.

The following code does what I need with one negative side-effect... it deletes the last line after all '\r' chars have been found no matter what. Ideally that last line should still be printed. Who knew that overstrike was so difficult??? The '\r' should really be handled properly by the Text widget (Pmw.TextDialog). The Text widget also needs a method to move the insertion point without placing new text or deleting text at the same time.

def append_status(self, content):
        """Set the contents of the Status Text box."""
        self.pop_status.configure(text_state=NORMAL)
        ptok = content.find('\r')
        # This while loop takes care of Carriage Returns
        while ptok >= 0:
            tok = content[:ptok]      # content up to the cr
            self.pop_status.appendtext(tok)
            content = content[ptok+1] # content after the cr
            self.pop_status.delete(INSERT + " linestart", END)
            ptok = content.find('\r')
        # This if takes care of everything after any-and-all cr's
        if len(content) > 0:
            self.pop_status.appendtext(content)
        self.pop_status.configure(text_state=DISABLED)
Member Avatar for ampoliros

I've continued working on the problem and have come up with a better solution...

In the __init__ method of your class include these lines.

self.status_buf = ''
        self.cr_found = False

Use this loop (or similar) to collect the generated output.

while proc.poll() is None:
                l = proc.stdout.read(40) # force frequent updates
                self.source.append_status_buf(l)
            l = proc.stdout.read()   # read whatever is straggling
            self.source.append_status_buf(l)
            # flush buffer
            while self.source.append_status_buf('') is True:
                pass
            if len(self.source.status_buf) >= 1:
                self.source.append_status(self.source.status_buf)
                self.source.status_buf = ''

Then use these 2 methods to append the output into the Text widget.

def append_status_buf(self, content):
        """Append to the status buffer and output one line."""
        self.status_buf += content
        pos = self.status_buf.find('\r') # look for cr first
        rv = False
        if pos >= 0:
            line = self.status_buf[:pos] # up to but not including the cr
            self.status_buf = self.status_buf[pos+1:] # after the cr
            self.append_status(line)
            self.cr_found = True
            rv = True
        else:
            pos = self.status_buf.find('\n')
            if pos >= 0:
                line = self.status_buf[:pos+1] # up to and including the nl
                self.status_buf = self.status_buf[pos+1:] # after the nl
                self.append_status(line)
                rv = True
        # if no cr or nl, don't update status
        return rv


    def append_status(self, content):
        """Append to the contents of the Status Text box.

        Caller must include newlines."""
        self.pop_status.configure(text_state=NORMAL)
        if self.cr_found == True:
            self.pop_status.delete(INSERT + " linestart", INSERT + " lineend")
            self.cr_found = False
        self.pop_status.appendtext(content)
        self.pop_status.configure(text_state=DISABLED)
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.