Click to See Complete Forum and Search --> : help with python and qt


nouse66
08-05-2003, 04:42 AM
I'm trying to pipe the output of a shell command to a qt widget to show the output in real time. Can some one help me with this?

Here's the code I came up with that doesn't work (It runs the command and then shows the output when it's finished):
-----------------------------------------------------------------

import sys, os
from qt import *

class Form1(QMainWindow):
def __init__(self,parent = None,name = None,fl = 0):
QMainWindow.__init__(self,parent,name,fl)
self.statusBar()

if not name:
self.setName("Form1")


self.setCentralWidget(QWidget(self,"qt_central_widget"))

self.textEdit1 = QTextEdit(self.centralWidget(),"textEdit1")
self.textEdit1.setGeometry(QRect(30,9,411,351))

self.pushButton1 = QPushButton(self.centralWidget(),"pushButton1")
self.pushButton1.setGeometry(QRect(310,379,121,41) )

self.languageChange()

self.resize(QSize(600,480).expandedTo(self.minimum SizeHint()))
self.clearWState(Qt.WState_Polished)

self.connect(self.pushButton1,SIGNAL("clicked()"),self.pushButton1_clicked)


def languageChange(self):
self.setCaption(self.__tr("Form1"))
self.pushButton1.setText(self.__tr("pushButton1"))


def pushButton1_clicked(self):
self.textEdit1.setText(os.popen('emerge sync').read())

def __tr(self,s,c = None):
return qApp.translate("Form1",s,c)

def main(args):
global output
app = QApplication(sys.argv)
win = Form1()
win.show()
app.connect(app, SIGNAL('lastWindowClosed()'), app, SLOT('quit()'))
app.exec_loop()

if __name__ == '__main__':
main(sys.argv)

x_Ray
08-05-2003, 03:13 PM
The read() call reads the output into a string until the command is done, then returns the string. If you want it in real time, you'll want to try something more like.


buf = os.popen(command)
for line in buf:
textEdit.insert(line)
buf.close()


Thats not quite gonna work though, as it will block the gui
until the command finishes its run, then display everything
pretty much all at once.

To get around that, I created a Worker thread, which runs the commands for us, so as to not block the gui. It puts the outputs into a Queue which is checked frequently from the main gui thread. Maybe a little overkill, but it works...;)


#!/usr/bin/python

from qt import *
import threading
import Queue
import os


class WorkerThread(threading.Thread):

def __init__(self, jobsQueue, resultsQueue):
threading.Thread.__init__(self)
self.setDaemon(True)
self.mJobsQueue = jobsQueue
self.mResultsQueue = resultsQueue
self.start()

def startJob(self, callable, *args):
self.mJobsQueue.put((callable, args))

def run(self):
while 1:
callable, args = self.mJobsQueue.get()
self.mResultsQueue.put((callable(*args)))


class Main(QMainWindow):

def __init__(self, parent=None, name=None):
QMainWindow.__init__(self, parent, name)
vbox = QVBox(self)
self.edit = QTextEdit(vbox, 'edit')
button = QPushButton('Start', vbox, 'button')
self.connect(button, SIGNAL('clicked()'), self.slotStart)
self.setCentralWidget(vbox)

self.resultsQueue = Queue.Queue()
self.jobsQueue = Queue.Queue()
self.outputQueue = Queue.Queue()

self.worker = WorkerThread(self.jobsQueue, self.resultsQueue)

self.outputTimer = QTimer(self)
self.connect(self.outputTimer, SIGNAL('timeout()'), self.slotCheckOutput)
self.resultsTimer = QTimer(self)
self.connect(self.resultsTimer, SIGNAL('timeout()'), self.slotCheckResult)


def slotStart(self):
self.worker.startJob(functDoJob, 'emerge -s foo', self.outputQueue)
self.resultsTimer.start(500, False)
self.outputTimer.start(50, False)


def slotCheckOutput(self):
try:
line = self.outputQueue.get_nowait()
self.edit.insert(line)
except:
pass

def slotCheckResult(self):
try:
if self.outputQueue.empty():
result = self.resultsQueue.get_nowait()
print result
self.outputTimer.stop()
self.resultsTimer.stop()
except:
pass


def functDoJob(*args):
task, queue, = args
buf = os.popen(task)
while 1:
line = buf.readline()
if line == '': break
queue.put(line)
buf.close()
return 'job_done'

if __name__=="__main__":
import sys
app = QApplication(sys.argv)
app.connect(app, SIGNAL('lastWindowClosed()'), app, SLOT('quit()'))
win = Main()
win.show()
app.exec_loop()

nouse66
08-05-2003, 03:41 PM
thanks x_ray, that works great.

do you know if there's a better widget to use for the output though? i really dont need to save every bit of compiler output on the screen. i want to see if it's working and qtextedit was the only thing i could come up with.

and to get the std_error output along with std_out i just need to switch popen with popen4, right?

nouse66
08-06-2003, 03:01 AM
well, i found out that if i add:
self.textEdit1.setVScrollBarMode(QTextEdit.AlwaysO ff)

it looks like what i had in mind. but will this store all of the output in memory even though only some is visible? i dont think i want that...

nouse66
08-30-2003, 08:03 PM
does anyone know why the output from emerge comes out scrambled like this? :

-------------------------------------------------------------------
]1;]2;Started emerge on: Aug 30, 2003 16:57:18]1;]2; *** emerge --buildpkgonly --buildpkg /tmp/openbox-2.3.0-6.tbz2Calculating dependencies

!!! Binary package '/tmp/openbox-2.3.0-6.tbz2' does not exist.
!!! Please ensure the tbz2 exists as specified.

]1;]2; *** terminating.]1;]2;rxvt
-------------------------------------------------------------------

bwkaz
09-01-2003, 02:36 PM
Because emerge thinks it's outputting to a terminal, but it's not. Those are the terminal escape sequences to do things like bold text, colors, cursor movement, and other stuff like that.

nouse66
09-01-2003, 06:25 PM
Originally posted by bwkaz
Because emerge thinks it's outputting to a terminal, but it's not. Those are the terminal escape sequences to do things like bold text, colors, cursor movement, and other stuff like that.

do you know how to strip that out? or how to get qt to handle it?

bwkaz
09-01-2003, 08:07 PM
They all start with the ESC key (ASCII code 27 decimal, or 033 octal). You could just strip out everything between '\033' and ';', but that might not catch everything.

Or you could grab a VT100 reference, figure out what each of the codes is trying to do, and edit the textview's contents to match (that's the only way to interpret them).

nouse66
09-01-2003, 10:25 PM
Originally posted by bwkaz
They all start with the ESC key (ASCII code 27 decimal, or 033 octal). You could just strip out everything between '\033' and ';', but that might not catch everything.

Or you could grab a VT100 reference, figure out what each of the codes is trying to do, and edit the textview's contents to match (that's the only way to interpret them).

i think i found a way...
------------------------------------------------------
identity = string.maketrans('','')
line = buf.readline()
crap = line.translate(identity, string.printable)
line = line.translate(identity, crap)

-------------------------------------------------------
seems like a lot of overhead though.

bwkaz
09-02-2003, 06:31 PM
Yeah, translate to printable might work... then again, if it also keeps the [2; (for example) in there, then you won't want to use it...

nouse66
09-02-2003, 06:56 PM
Originally posted by bwkaz
Yeah, translate to printable might work... then again, if it also keeps the [2; (for example) in there, then you won't want to use it...

yeah, it does leave some stuff behind like that.

do you know how to make the range of characters '\033' through ';' ?

bwkaz
09-02-2003, 09:56 PM
I don't remember offhand how good the support for regular expressions in Python and/or Qt is, but if you can replace the regex \033[^;]*; with nothing, then you should be set (the [^;]* part matches "any sequence of any character that isn't semicolon").

nouse66
09-02-2003, 11:43 PM
ok here's what i came up with...
i created this regex object:
regex = re.compile(r'\033[^;]*;')

and then each line is run through this:
line = regex.sub("",line)
crap = line.translate(identity, string.printable)
line = line.translate(identity, crap)

and it seems to do the trick.

the regex alone did not remove all of the junk (i still see little box characters) so for now i'm stuck doing two replace functions.

thanks,
aaron