Hello!
I am trying to redirect the stdout following the example in http://www.blog.pythonlibrary.org/2009/01/01/wxpython-redirecting-stdout-stderr/. My code has some loops, and I would like the function to redirect stdout each time the loop is repeated, as it happens when running the code with the command line. However, it seems that in this example the stdout is only redirected when the whole function is finished. How can I redirect the stdout in a "real time" mode? I attach my code.
Cheers!

Dani

Attachments
#!/usr/bin/python
# WipGUI.py

import wx, os, shutil, fnmatch, Image, ImageEnhance, sys, textwrap, re
import wx.lib.intctrl

class RedirectText(object):
	def __init__(self,aWxTextCtrl):
		self.out=aWxTextCtrl

	def write(self,string):
		self.out.WriteText(string)

ID_HELP = 1
ID_ABOUT = 2
ID_GO = 3

class Wip(wx.Frame):
	def __init__(self, parent, id, title):
		wx.Frame.__init__(self, parent, id, title, size=(750,525))
		
#Define menus
		menubar = wx.MenuBar()
	#Define file menu
		file = wx.Menu()
		quit = wx.MenuItem(file, 1, '&Quit\tCtrl+Q')
		file.AppendItem(quit)
		self.Bind(wx.EVT_MENU, self.OnQuit, id=1)
	#Define help menu
		helpMenu = wx.Menu()
		helpMenu.Append(ID_HELP, '&Help')
		helpMenu.Append(ID_ABOUT, '&About')
		self.Bind(wx.EVT_MENU, self.OnAboutBox, id=ID_ABOUT)
		
#Append menus
		menubar.Append(file, '&File')
		menubar.Append(helpMenu, '&Help')
		self.SetMenuBar(menubar)
#Define main panel
		panel = wx.Panel(self, -1)
		vbox1 = wx.BoxSizer(wx.VERTICAL)
	#Define buttons
		#Define button to select the pictures folder
		hbox1 = wx.BoxSizer(wx.HORIZONTAL)
		self.picsFolder = wx.Button(panel,-1,"Select your picture directory",size=(200,30))
		self.DirPathTextBox=wx.TextCtrl(panel,-1,"",size=(400,-1))
		self.Bind(wx.EVT_BUTTON, self.SelDir, self.picsFolder)
		hbox1.Add(self.picsFolder, 0, wx.ALL , 5)
		hbox1.Add(self.DirPathTextBox, 0, wx.ALL , 5)

		#Define the button to select the watermark file
		hbox2 = wx.BoxSizer(wx.HORIZONTAL)
		mask ='*.png'
		self.markFile = wx.Button(panel,-1,"Select your watermark file",size=(200,30))
		self.Bind(wx.EVT_BUTTON, self.SelFile, self.markFile)
		self.FilePathTextBox=wx.TextCtrl(panel,-1,"",size=(400,-1))
		hbox2.Add(self.markFile, 0, wx.ALL , 5)
		hbox2.Add(self.FilePathTextBox, 0, wx.ALL , 5)
		
		#Define a text box to select desired size
		hbox3 = wx.BoxSizer(wx.HORIZONTAL)
		self.pxText = wx.StaticText(panel, -1,'Desired size of the longest picture side in pixels: ', pos=(300, 170), size=(321,30))
		self.px = wx.lib.intctrl.IntCtrl(panel, -1, value=1024, pos=wx.Point(10, 90), size=(45, 30))
		hbox3.Add(self.pxText, 0, wx.ALL , 5)
		hbox3.Add(self.px, 0, wx.ALL , 0)
		
		#Define the button to start processing
		hbox4 = wx.BoxSizer(wx.HORIZONTAL)
		go = wx.Button(panel, -1, 'Go', size=(100, 30))
		hbox4.Add(go, 0, wx.ALL , 5)
		self.Bind(wx.EVT_BUTTON, self.WaterMark, go)

		#Redirect text widgets
		hbox5 = wx.BoxSizer(wx.HORIZONTAL)
		log = wx.TextCtrl(panel, wx.ID_ANY, size=(600,200),style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
		hbox5.Add(log, 0, wx.ALL , 5)

		# redirect text here
		redir=RedirectText(log)
		sys.stdout=redir
		sys.stderr=redir

		#Merge sizers
		vbox1.Add(hbox1, 0, wx.ALIGN_LEFT | wx.ALL, 5)
		vbox1.Add(hbox2, 0, wx.ALIGN_LEFT | wx.ALL, 5)
		vbox1.Add(hbox3, 0, wx.ALIGN_LEFT | wx.ALL, 5)
		vbox1.Add(hbox4, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
		vbox1.Add(hbox5, 0, wx.ALIGN_CENTER | wx.ALL, 5)

		panel.SetSizer(vbox1)
		self.Centre()
		self.Show(True)

	def OnQuit(self, event):
		self.Close()

	def OnAboutBox(self, event):
		info = wx.AboutDialogInfo()
		info.SetIcon(wx.Icon('icons/exit.png', wx.BITMAP_TYPE_PNG))
		info.SetName('Watermark Image Processing')
		info.SetVersion('1.0b')
		description = open('docs/info.txt').read()
		info.SetDescription(description)
		info.SetCopyright('(C) 2010 Acrocephalus Soft')
		info.SetWebSite('http://www.acrocephalus.net')
		license = open('docs/licence.txt').read()
		info.SetLicence(license)
		info.AddDeveloper('Daniel Valverde')
		info.AddDocWriter('Daniel Valverde')
		info.AddArtist('Daniel Valverde')
		info.AddTranslator('Daniel Valverde')
		wx.AboutBox(info)

	def SelDir(self,event): 
		dialog = wx.DirDialog(None, "Select your picture directory",style=wx.DD_DEFAULT_STYLE | wx.DD_CHANGE_DIR)
		if dialog.ShowModal() == wx.ID_OK:
			self.dirname=dialog.GetPath()
			self.DirPathTextBox.write(self.dirname)
		dialog.Destroy

	def SelFile(self,event): 
		markFile = wx.FileDialog(None, "Select your watermark file",style=wx.FD_OPEN, wildcard="PNG files (*.png)|*.png")
		if markFile.ShowModal() == wx.ID_OK:
			self.markFile=markFile.GetPath()
			self.FilePathTextBox.write(self.markFile)
		markFile.Destroy
	
	def WaterMark(self, event):
		cwd = os.getcwd()
		markFile=self.markFile
		px = self.px.GetValue()
		#Create a Backup directory
		if not os.path.exists('Backup'):
			os.mkdir('Backup')
		#Create a Resized directory
		if not os.path.exists('Resized'):
			os.mkdir('Resized')
		#Create a marked directory
		if not os.path.exists('Watermarked'):
			os.mkdir('Watermarked')
		#Copy images to backup folder
		for file in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			shutil.copy2(file, 'Backup/%s' % file)
			print 'Copying ' + file + ' to Backup/'
		#Image processing    
		for file in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			print 'Resizing ' + file
		# Open the image
			img = Image.open(file)
		#Get actual image size and convert it to float
			width, height = img.size
			width = float(width)
			height = float(height)
		#Resize landscape images
			if width > height:
				resizeFactor = width/int(px*2)
				img = img.resize((int(width/resizeFactor),int(height/resizeFactor)))
				width, height = img.size
				img = img.resize((int(width/2),int(height/2)), Image.ANTIALIAS)
		#Resize portrait images
			elif width<height:
				resizeFactor = height/int(px*2)
				img = img.resize((int(width/resizeFactor),int(height/resizeFactor)))
				width, height = img.size
				img = img.resize((int(width/2),int(height/2)), Image.ANTIALIAS)
		#Resize square images
			else:
				img = img.resize((int(px*2),int(px*2)))
				width, height = img.size
				img = img.resize((int(px),int(px)), Image.ANTIALIAS)
		#Save resized image
			img.save(file)
		#Copy pictures to a Resized directory
		for filename in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			shutil.copy2(filename, 'Resized/%s' % filename)
#----------------------------------------------------------------------------    
		#Add mark
		#Getting the sizes of the base image and the mark
		imgmark = Image.open(markFile)
		markWidth, markHeight = imgmark.size
		for filename in fnmatch.filter(os.listdir(cwd),'*.jpg'):
		# Open the image
			img = Image.open(filename)
		#Get actual image size and convert it to float
			width, height = img.size
			baseim = Image.open(filename)
			logoim = Image.open(markFile) #transparent image
			baseim.paste(logoim,(int(width)-int(markWidth)-20,int(height)-int(markHeight)-10),logoim)
			baseim.save(filename, 'JPEG')
#----------------------------------------------------------------------------    
		#Recover EXIF data
		try:
			os.system('jhead -te Backup/*jpg *.jpg')
		except:
			print w.fill('You don\'t have JHEAD installed, so WIP cannot recover the EXIF data. You can download and install it from http://www.sentex.net/ ~mwandel/jhead/')
		for filename in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			shutil.move(filename, 'Watermarked/%s' % filename)
		def Done():
			dial = wx.MessageDialog(None, 'Watermarking finished', 'Info', wx.OK | wx.CENTRE)
			dial.ShowModal()
		Done()
app = wx.App()
Wip(None, -1, 'Watermark Image Processing 1.0b')
app.MainLoop()

Hello!
I like your solution. However, there are a couple of issues. First of all, it is not a "real time" redirection, as it only sends the stdout to the console when the function has finished. Then, is it possible to embed the console inside the main frame? I attach the fill code.
Cheers!

Dani

Attachments
#!/usr/bin/python
# WipGUI.py

import wx, os, shutil, fnmatch, Image, ImageEnhance, sys, textwrap, re
import wx.lib.intctrl

class RedirectText(object):
	def __init__(self,aWxTextCtrl):
		self.out=aWxTextCtrl

	def write(self,string):
		self.out.WriteText(string)

ID_HELP = 1
ID_ABOUT = 2
ID_GO = 3

class Wip(wx.Frame):
	def __init__(self, parent, id, title):
		wx.Frame.__init__(self, parent, id, title, size=(750,525))
		
#Define menus
		menubar = wx.MenuBar()
	#Define file menu
		file = wx.Menu()
		quit = wx.MenuItem(file, 1, '&Quit\tCtrl+Q')
		file.AppendItem(quit)
		self.Bind(wx.EVT_MENU, self.OnQuit, id=1)
	#Define help menu
		helpMenu = wx.Menu()
		helpMenu.Append(ID_HELP, '&Help')
		helpMenu.Append(ID_ABOUT, '&About')
		self.Bind(wx.EVT_MENU, self.OnAboutBox, id=ID_ABOUT)
		
#Append menus
		menubar.Append(file, '&File')
		menubar.Append(helpMenu, '&Help')
		self.SetMenuBar(menubar)
#Define main panel
		panel = wx.Panel(self, -1)
		vbox1 = wx.BoxSizer(wx.VERTICAL)
	#Define buttons
		#Define button to select the pictures folder
		hbox1 = wx.BoxSizer(wx.HORIZONTAL)
		self.picsFolder = wx.Button(panel,-1,"Select your picture directory",size=(200,30))
		self.DirPathTextBox=wx.TextCtrl(panel,-1,"",size=(400,-1))
		self.Bind(wx.EVT_BUTTON, self.SelDir, self.picsFolder)
		hbox1.Add(self.picsFolder, 0, wx.ALL , 5)
		hbox1.Add(self.DirPathTextBox, 0, wx.ALL , 5)

		#Define the button to select the watermark file
		hbox2 = wx.BoxSizer(wx.HORIZONTAL)
		mask ='*.png'
		self.markFile = wx.Button(panel,-1,"Select your watermark file",size=(200,30))
		self.Bind(wx.EVT_BUTTON, self.SelFile, self.markFile)
		self.FilePathTextBox=wx.TextCtrl(panel,-1,"",size=(400,-1))
		hbox2.Add(self.markFile, 0, wx.ALL , 5)
		hbox2.Add(self.FilePathTextBox, 0, wx.ALL , 5)
		
		#Define a text box to select desired size
		hbox3 = wx.BoxSizer(wx.HORIZONTAL)
		self.pxText = wx.StaticText(panel, -1,'Desired size of the longest picture side in pixels: ', pos=(300, 170), size=(321,30))
		self.px = wx.lib.intctrl.IntCtrl(panel, -1, value=1024, pos=wx.Point(10, 90), size=(45, 30))
		hbox3.Add(self.pxText, 0, wx.ALL , 5)
		hbox3.Add(self.px, 0, wx.ALL , 0)
		
		#Define the button to start processing
		hbox4 = wx.BoxSizer(wx.HORIZONTAL)
		go = wx.Button(panel, -1, 'Go', size=(100, 30))
		hbox4.Add(go, 0, wx.ALL , 5)
		self.Bind(wx.EVT_BUTTON, self.WaterMark, go)

		#Merge sizers
		vbox1.Add(hbox1, 0, wx.ALIGN_LEFT | wx.ALL, 5)
		vbox1.Add(hbox2, 0, wx.ALIGN_LEFT | wx.ALL, 5)
		vbox1.Add(hbox3, 0, wx.ALIGN_LEFT | wx.ALL, 5)
		vbox1.Add(hbox4, 0, wx.ALIGN_RIGHT | wx.ALL, 5)

		panel.SetSizer(vbox1)
		self.Centre()
		self.Show(True)

	def OnQuit(self, event):
		self.Close()

	def OnAboutBox(self, event):
		info = wx.AboutDialogInfo()
		info.SetIcon(wx.Icon('icons/exit.png', wx.BITMAP_TYPE_PNG))
		info.SetName('Watermark Image Processing')
		info.SetVersion('1.0b')
		description = open('docs/info.txt').read()
		info.SetDescription(description)
		info.SetCopyright('(C) 2010 Acrocephalus Soft')
		info.SetWebSite('http://www.acrocephalus.net')
		license = open('docs/licence.txt').read()
		info.SetLicence(license)
		info.AddDeveloper('Daniel Valverde')
		info.AddDocWriter('Daniel Valverde')
		info.AddArtist('Daniel Valverde')
		info.AddTranslator('Daniel Valverde')
		wx.AboutBox(info)

	def SelDir(self,event): 
		dialog = wx.DirDialog(None, "Select your picture directory",style=wx.DD_DEFAULT_STYLE | wx.DD_CHANGE_DIR)
		if dialog.ShowModal() == wx.ID_OK:
			self.dirname=dialog.GetPath()
			self.DirPathTextBox.write(self.dirname)
		dialog.Destroy

	def SelFile(self,event): 
		markFile = wx.FileDialog(None, "Select your watermark file",style=wx.FD_OPEN, wildcard="PNG files (*.png)|*.png")
		if markFile.ShowModal() == wx.ID_OK:
			self.markFile=markFile.GetPath()
			self.FilePathTextBox.write(self.markFile)
		markFile.Destroy
	
	def WaterMark(self, event):
		cwd = os.getcwd()
		markFile=self.markFile
		px = self.px.GetValue()
		#Create a Backup directory
		if not os.path.exists('Backup'):
			os.mkdir('Backup')
		#Create a Resized directory
		if not os.path.exists('Resized'):
			os.mkdir('Resized')
		#Create a marked directory
		if not os.path.exists('Watermarked'):
			os.mkdir('Watermarked')
		#Copy images to backup folder
		for file in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			shutil.copy2(file, 'Backup/%s' % file)
			print 'Copying ' + file + ' to Backup/'
		#Image processing    
		for file in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			print 'Resizing ' + file
		# Open the image
			img = Image.open(file)
		#Get actual image size and convert it to float
			width, height = img.size
			width = float(width)
			height = float(height)
		#Resize landscape images
			if width > height:
				resizeFactor = width/int(px*2)
				img = img.resize((int(width/resizeFactor),int(height/resizeFactor)))
				width, height = img.size
				img = img.resize((int(width/2),int(height/2)), Image.ANTIALIAS)
		#Resize portrait images
			elif width<height:
				resizeFactor = height/int(px*2)
				img = img.resize((int(width/resizeFactor),int(height/resizeFactor)))
				width, height = img.size
				img = img.resize((int(width/2),int(height/2)), Image.ANTIALIAS)
		#Resize square images
			else:
				img = img.resize((int(px*2),int(px*2)))
				width, height = img.size
				img = img.resize((int(px),int(px)), Image.ANTIALIAS)
		#Save resized image
			img.save(file)
		#Copy pictures to a Resized directory
		for filename in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			shutil.copy2(filename, 'Resized/%s' % filename)
#----------------------------------------------------------------------------    
		#Add mark
		#Getting the sizes of the base image and the mark
		imgmark = Image.open(markFile)
		markWidth, markHeight = imgmark.size
		for filename in fnmatch.filter(os.listdir(cwd),'*.jpg'):
		# Open the image
			img = Image.open(filename)
		#Get actual image size and convert it to float
			width, height = img.size
			baseim = Image.open(filename)
			logoim = Image.open(markFile) #transparent image
			baseim.paste(logoim,(int(width)-int(markWidth)-20,int(height)-int(markHeight)-10),logoim)
			baseim.save(filename, 'JPEG')
#----------------------------------------------------------------------------    
		#Recover EXIF data
		try:
			os.system('jhead -te Backup/*jpg *.jpg')
		except:
			print w.fill('You don\'t have JHEAD installed, so WIP cannot recover the EXIF data. You can download and install it from http://www.sentex.net/ ~mwandel/jhead/')
		for filename in fnmatch.filter(os.listdir(cwd),'*.jpg'):
			shutil.move(filename, 'Watermarked/%s' % filename)
		def Done():
			dial = wx.MessageDialog(None, 'Watermarking finished', 'Info', wx.OK | wx.CENTRE)
			dial.ShowModal()
		Done()
app = wx.App(redirect=True)
Wip(None, -1, 'Watermark Image Processing 1.0b')
app.MainLoop()

I've just tested, and to me they are both in real time.

import time
import wx

class Frame(wx.Frame):
    def __init__(self):

        super(Frame, self).__init__(None, -1, 'Output to widget in realtime')

        panel = wx.Panel(self, -1)
 
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        btn = wx.Button(panel, -1, 'Print RT')
        text = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.TE_READONLY)
        self.text = text

        sizer.Add(btn, 0, wx.ALL, 10)
        sizer.Add(text, 1, wx.EXPAND|wx.ALL, 10)

        panel.SetSizer(sizer)

        self.Bind(wx.EVT_BUTTON, self.onbutton, btn)

    def onbutton(self, event):
        self.textoutput('Something like this?\n')
        for i in range(1, 11):
            self.textoutput('%s printed...\n' % i)
            print '%s printed...' % i
            time.sleep(1)

    def textoutput(self, text):
        self.text.AppendText(text)
 
if __name__ == '__main__':
    app = wx.PySimpleApp(redirect=True)
    frame = Frame()
    frame.Show()
    app.MainLoop()

Cheers and Happy coding.

Thank you! I may be some problem with my computer, as it does not print the info in real time.
Cheers!

Dani

Make the window smaller so that You can see the output in separate window and main window same time, before clicking the button. You do start application from file manager, not from IDLE, don't you?

Yes, I start the app from file manager (Nautilus). When I click the go button the app frame turns grey.
Cheers!

Dani

Edited 6 Years Ago by acrocephalus: n/a

Tried it in Ubuntu myself and the app behaves differently. Does not update realtime like in Windows XP

Everything appears in the end, see captured screenshots after pushing the button.
I had time to save one screen shot and take other without prints coming up.

Attachments Kuvakaappaus-1.png 310.95 KB Kuvakaappaus-2.png 305.98 KB Kuvakaappaus.png 305.76 KB
This article has been dead for over six months. Start a new discussion instead.