I have 2 files created, one a .pyx file with a class named AndorCamersSDK which has a function named LiveAcquisition(). The second file, a .py file with a Class AndorCameraGUI which makes use of Tkinter to create a GUI. This class has function LivePlot(), and RepeatPlot().Inside LiveAcquisition() I am acquiring N number of frames and after acquiring each frame I need to display it using LivePlot() and RepeatPlot(). Without the display, just acquiring and storing for 300 frames takes 6.2 for execution, which is fine by me. But When I start displaying even for 100 frames it takes 54sec. I need to acquire and display within 6 sec for 300 frames. How do I solve this?
File 1: .pyx code ; Present inside class AndorCameraSDK
def LiveAcquisition(self):
for i in range(no_of_frames):
data[i,:,:] = PyArray_NewFromDescr(<PyTypeObject *> np.ndarray, np.dtype('<H'), 2,dims, strides,pBuf, np.NPY_C_CONTIGUOUS, None)
if (i==0):
self.master.LivePlot(data[i,:,:])
elif (i==2) or (i==15) or (i ==65) or (i ==96):
self.master.RepeatPlot(data[i,:,:])
else:
pass
File 2 : .py code; Below functions are present inside a class named AndorCameraGUI
def LivePlot(self,image):
self.count = 0
self.fig = Figure(figsize = (4, 5))
self.fig.patch.set_facecolor('xkcd:light grey') # When this is removed a white color is seen in the background of the figure
self.a = self.fig.add_subplot(111)
self.a.set_xlim([0, self.image_width/int(self.HBin)])
self.a.set_ylim([0, self.image_height/int(self.VBin)])
image = image.transpose()
self.a.imshow(image,'gray')
self.canvas = FigureCanvasTkAgg(self.fig,self.master)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side =LEFT)
self.toolbar = NavigationToolbar2TkAgg(self.canvas,self.master)
self.toolbar.update()
self.canvas._tkcanvas.pack(side = LEFT)# change this to TOP so thee the navigation toolbar on the left down
def RepeatPlot(self,image):
image = image.transpose()
self.a.imshow(image,'gray')
self.canvas.draw()
Related
I am trying to create a small python app with Tkinter which involves collecting data in several lists, like this:
def main_process():
list1 = []
list2 = []
list3 = []
#Data collection process
#Resulting lists ready
The data collection process takes about 10 seconds, so I wanted to make a "Loading Screen" that works side-by-side the data collection process, without one following the other. For the status bar, I thought of introducing a variable n with value starting from 0, and increasing its value as and when each resultant lists get ready.
I attempted to create a function loading_screen(n) which will be called before the data processing, with n being the aforementioned variable containing a numeric value. And as the data_processing occurs, I shall run the loading_screen function to introduce the updated values of n, like so:
def main_process():
def loading_screen(n):
root = Tk()
root.title('Stock Market App')
root.geometry('800x300')
status_label = Label(root, text = n)
status_label.pack()
loading_screen(0)
# list1 Ready
n += 10
root.after(0, lambda: loading_screen(n))
# list2 ready
n += 10
root.after(0, lambda: loading_screen(n))
# And so on...
But it ended up showing me the loading screen after all the data processing has occurred. Can somebody please help me on this?
Thanks.
Putting function inside a function is not a good idea, better to create a class.
Then create two separate Tk windows.
Also, after is able to pass parameters so lambda is not necessary.
I've made a few small adjustments to conform to your question. The windows will now sit side by side.
Is this what you were looking for?
import tkinter as tk
class main_process:
def loading_screen( self, n ):
self.status_label[ 'text' ] = '{}'.format( n )
self.root.deiconify()
self.status_label.focus()
self.root.update()
# insert processing here
def __init__( self, x ):
self.root = tk.Tk()
self.root.withdraw()
self.root.title('Stock Market App')
self.root.geometry( f'700x300+{x}+240')
self.status_label = tk.Label( self.root, font = 'Helvetica 20 normal')
self.status_label.pack()
self.root.update()
screen_1 = main_process( 0 )
screen_1.root.after( 10, screen_1.loading_screen, 1 )
screen_2 = main_process( 705 )
screen_2.root.after( 10, screen_2.loading_screen, 2 )
screen_2.root.mainloop()
Hi you can remove the gui like this
Labelone.destroy()
.
.
.
Loading_screen.place(...)
#you data collection code
Loading_screen.destroy()
Labelone.place(...)
.
.
.
So your data collection is going background and loading gui is place so user sees loading while python is collecting data
I have been searching stackoverflow for a solution to the issue of an interactive mpl figure when streaming data to it. I've gotten close with the below example, but when I plot this no matter what mods I make to the code I'm unable to interact with the figure window. What concept am I missing that would allow me to stream data to this window AND drag the window around? As you can see it opens up and plots, but if I grab the frame to move it to a different location it crashes and most of the time is stuck in place.
I'm using Python 2.7, Paycharm and Windows 10.
Here is a helpful example I'm working with.
Example-from-documentation
Is the problem because I'm using plt.show()? My test code consists of 3 files, a datagen, data consumer (plotter) and a top level file (test bench) instantiating and starting the data generator and plotting module. I am just appending 62bytes of sine wave data to the end of an array and plotting it so it looks like it is scrolling by.
Test bench:
NB_DataGen -> NB_Plotter (receives 62 bytes of data and plots).
MODULE1: DATA PLOTTING MODULE
# This is the no blitting data plot module built out as a threaded module.
#
#
# Notes:
# 1. Bug in frame rate code
# 2. Going to try to remove queue from plotter and just have a direct access call for
# direct writes to plot. Queue seems to be bogging down window and I can't drag it
# around.
#
try:
import Queue as queue
except:
import queue
import numpy as np
from matplotlib import pyplot as plt
import time
import threading
import matplotlib
print(matplotlib.__version__)
class BlitManager:
def __init__(self, canvas, animated_artists=()):
"""
Parameters
----------
canvas : FigureCanvasAgg
The canvas to work with, this only works for sub-classes of the Agg
canvas which have the `~FigureCanvasAgg.copy_from_bbox` and
`~FigureCanvasAgg.restore_region` methods.
animated_artists : Iterable[Artist]
List of the artists to manage
"""
self.canvas = canvas
self._bg = None
self._artists = []
for a in animated_artists:
self.add_artist(a)
# grab the background on every draw
self.cid = canvas.mpl_connect("draw_event", self.on_draw)
def on_draw(self, event):
"""Callback to register with 'draw_event'."""
cv = self.canvas
if event is not None:
if event.canvas != cv:
raise RuntimeError
self._bg = cv.copy_from_bbox(cv.figure.bbox)
self._draw_animated()
def add_artist(self, art):
"""
Add an artist to be managed.
Parameters
----------
art : Artist
The artist to be added. Will be set to 'animated' (just
to be safe). *art* must be in the figure associated with
the canvas this class is managing.
"""
if art.figure != self.canvas.figure:
raise RuntimeError
art.set_animated(True)
self._artists.append(art)
def _draw_animated(self):
"""Draw all of the animated artists."""
fig = self.canvas.figure
for a in self._artists:
fig.draw_artist(a)
def update(self):
"""Update the screen with animated artists."""
cv = self.canvas
fig = cv.figure
# paranoia in case we missed the draw event,
if self._bg is None:
self.on_draw(None)
else:
# restore the background
cv.restore_region(self._bg)
# draw all of the animated artists
self._draw_animated()
# update the GUI state
cv.blit(fig.bbox)
# let the GUI event loop process anything it has to do
cv.flush_events()
#
# Main Class
#
class NB_Plotter4(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.i = 0
# thread loop flag
self.thread_event = threading.Event()
self.thread_event.set() # set thread by default
# create plot objects
self.fig = plt.figure()
self.ax1 = self.fig.add_subplot(1,1,1)
self.ax1.grid()
self.line, = self.ax1.plot([], lw=3)
self.text = self.ax1.text(0.8, 0.5, "")
self.x_new = np.linspace(0.0, 200.0, num=1000)
self.y_total = np.empty(1000, dtype=float)
#set limits
self.ax1.set_xlim(self.x_new.min(), self.x_new.max())
self.ax1.set_ylim([-1.1, 1.1])
# start timer for frame counter
self.t_start = time.time()
#self.bm = BlitManager(self.fig.canvas, [self.line, self.text])
self.bm = BlitManager(self.fig.canvas, [self.line])
plt.show(block=False)
plt.pause(0.1)
#
# main thread loop
#
def Write(self, data):
# need to grab y-data here from queue
self.y_ndata = data
self.y_total = np.concatenate([self.y_total[62:], self.y_ndata])
self.i = self.i + 1
#
# Over-ride thread run method
#
def run(self):
while self.thread_event.is_set():
self.line.set_data(self.x_new, self.y_total)
tx = 'Mean Frame Rate:\n {fps:.5f}FPS'.format(fps=((self.i + 1) / (time.time() - self.t_start)))
self.text.set_text(tx)
self.bm.update()
MODULE2: DATA GENERATION MODULE
# This is the no blitting data gen module. This module is intended to produce data
# in 62 byte blocks resulting in sine wave data blocks. This is initally meant to
# spoof my DR500 USB payload size so I can' drive some real time plotting.
#
#
# Notes:
#
#
#
try:
import Queue as queue
except:
import queue
import numpy as np
import threading
import time
#
# Main Class
#
# For the 62 byte class the rounding in the x vector produces some small errors. This shouldn't
# be a big problem since the resolution is so high.
#
class NB_DataGen2(threading.Thread):
def __init__(self, Plotter):
threading.Thread.__init__(self)
self.y_data = np.empty(62, dtype=float)
self.x_data = np.linspace(0.0, np.pi/62.0, num=62)
self.offset_val = self.x_data[1]
self.Plotter_Handle = Plotter
self.inc_cnt = 0.0
self.first_it_flag = 0 # first iteration flag
# thread loop flag
self.thread_event = threading.Event()
self.thread_event.set() # set thread by default
#
# Produce 62 byte packet of sine wave data
# - produce next 62 byte chunk of sine wave data
def Get62ByteSine(self, debug=False):
# hit for iterations > 0
if(self.first_it_flag > 0):
# gen
self.x_data = self.x_data + (np.pi / 62.0) + self.offset_val
self.y_data = np.sin(self.x_data)
if(debug == True):
print(self.y_data)
return self.y_data
# hit for iterations < 1 -> (first iteration)
else:
# first iteration
self.x_data = self.x_data
self.y_data = np.sin(self.x_data)
if (debug == True):
print(self.y_data)
self.inc_cnt = self.inc_cnt + 1.0
# flip first run flag
self.first_it_flag = 1
return self.y_data
#
# Ignore / Not in use
#
# Used to check the error from the last value in one block (62 byte block)
# and the first value of the next block. the difference in the two should
# match the offset value roughly. Enable print funcitons in the above
# Get62ByteSine function for this to work.
#
def CheckError(self):
self.Get62ByteSine(True)
self.Get62ByteSine(True)
self.Get62ByteSine(True)
# print offset
print(self.offset_val)
#
# Kill thread
#
def KillThread(self):
self.thread_event.clear()
#
# main thread loop
#
def run(self):
while self.thread_event.is_set():
self.Plotter_Handle.Write(self.Get62ByteSine())
time.sleep(1)
MODULE3: TOP LEVEL TEST BENCH
# This is the no blitting test bench top module
#
#
# Notes:
#
#
#
from NB_DataGen2 import NB_DataGen2
from NB_Plotter4 import NB_Plotter4
#
# Testbench Class
#
class NB_TestBench(object):
def __init__(self):
# create data/plot objects (DUTs) - obj's under test
self.Plotter = NB_Plotter4()
self.DataGen = NB_DataGen2(self.Plotter)
def Start(self):
self.DataGen.start()
self.DataGen.isDaemon()
self.Plotter.start()
self.Plotter.isDaemon()
# Run test bench
NB = NB_TestBench()
NB.Start()
Long story short - I'm trying to run this code to plot incoming data and be able to drag the window around or just generally interact with it via the mouse. Does anyone see where I went wrong?
I really don't now why I can't call the method setTRSKey from inside my for loop. Am I missing something? This makes no sense to me at all. Pycharm declares it as an unsolved reference
Here is the code:
import math
import nuke
originNode = nuke.selectedNode()
world_matrix = originNode['world_matrix'] # this is an iArray Knob with 16 fields
mResult = nuke.math.Matrix4() # Matrix to copy iArray to
# Ask user for Frame Range operation
ret = nuke.getFramesAndViews('Frame range', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame()))
if ret != None:
nuke.nodeCopy("%clipboard%") # creating node duplicate
originNode.setSelected(False)
newNode = nuke.nodePaste("%clipboard%") # creating origin node duplicate
newNode['translate'].clearAnimated()
newNode['translate'].setValue(0)
newNode['translate'].setAnimated()
newNode['rotate'].clearAnimated()
newNode['rotate'].setValue(0)
newNode['rotate'].setAnimated()
newNode['scaling'].clearAnimated()
newNode['scaling'].setValue(0)
newNode['scaling'].setAnimated()
frange = nuke.FrameRange(ret[0]) # convert to frange object
for frame in frange:
for i in xrange(0, 16):
mResult[i] = world_matrix.valueAt(frame)[i]
mResult.transpose() # row become columns and vice versa
mTranslate = nuke.math.Matrix4(mResult)
mTranslate.translationOnly()
mRotate = nuke.math.Matrix4(mResult)
mRotate.rotationOnly()
mScale = nuke.math.Matrix4(mResult)
mScale.scaleOnly()
translate = (mTranslate[12], mTranslate[13], mTranslate[14])
rotateRad = mRotate.rotationsZXY()
rotate = (math.degrees(rotateRad[0]), math.degrees(rotateRad[1]),
math.degrees(rotateRad[2])) # convert from radiants to defrees
scale = (mScale.xAxis().x, mScale.yAxis().y, mScale.zAxis().z)
setTRSKey(frame, translate, rotate, scale)
else:
print "User canceled the operation"
def setTRSKey(frame, translate, rotate, scale):
print type(translate(0))
newNode['translate'].setValueAt(translate(0), frame, 0)
newNode['translate'].setValueAt(translate(1), frame, 1)
newNode['translate'].setValueAt(translate(2), frame, 2)
edit: Example with classes where loadDataFromScript is called before defining
class Connecthor(QtWidgets.QDialog, Ui_Dialog):
#
allowedNodes = ["Read", "Write", "Merge", "Keymix", "ChannelMerge", "Roto", "RotoPaint", "Copy", "Shuffle", "PostageStamp", "Camera", "Camera2", "ScanlineRender", "Connector", "ReadGeo", "ReadGeo2", "BackdropNode"]
script_path = os.path.dirname(os.path.realpath(__file__))
#constructor
def __init__(self, parent=None):
super(Connecthor, self).__init__(parent)
self.setupUi(self)
self.setFixedSize(self.size())
#self.setWindowOpacity(0.95)
popupmenu = QtWidgets.QMenu(self.btn_settings)
#popupmenu.addAction("save links for script", self.writeListDictToJson)
#popupmenu.addAction("import links from json", self.readJsonToDict)
popupmenu.addAction("save links for script (manual)", self.saveDatatoScript)
popupmenu.addAction("settings", self.opensetting)
self.btn_settings.setMenu(popupmenu)
self.btn_settings.setIcon(QtGui.QIcon(os.path.join(iconpath, "settings.png")))
self.btn_addSelectedNodes.setIcon(QtGui.QIcon(os.path.join(iconpath, "add.png")))
self.btn_addSelectedNodes.clicked.connect(self.addSelectedNodes)
# #Loading test Json
#self.readJsonToDict()
self.loadDataFromScript()
In Python you must define functions before they are called. Move your setTRSKey definition above the for loop. Generally speaking, function definitions are one of the very first things in the file after imports, though this is not always the case.
I have a data project that produces a number of plots with the same name only in different directories. Looking at these plots helps to see if anything funky is going on with the data, but it would be a pain try to open them all one by one or to copy them all to one directory, rename them, and then open up my standard image viewer.
Knowing some wxPython GUI programming I decided to whip up an app that would take in a list of directories to these images and I can slide show them with some arrow buttons. I can then add to this list as more plots come in.
I got the app running properly, but now when I am loading in around 23 ~3 MB images my program memory usage reaches near 10 GB.
The code is below, but in short I load them up all as wxPython Images, before displaying, and this is where the memory climbs. Switching between the images via stacks doesn't seem to make the memory climb further. I think it might be me holding onto no longer needed resources, however the usage seems disproportionate to the size and number of images.
Is someone able to point out a flaw in my method?
```
class Slide(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Slide Show")
self.display = wx.GetDisplaySize()
self.image_list = None
self.current = None # holds currently displayed bitmap
# stacks that hold the bitmaps
self.future = []
self.past = []
self.left = wx.BitmapButton(self, id=101, size=(100,-1), bitmap=wx.ArtProvider.GetBitmap(wx.ART_GO_BACK))
self.left.Enable(False)
self.right = wx.BitmapButton(self, id=102, size=(100,-1), bitmap=wx.ArtProvider.GetBitmap(wx.ART_GO_FORWARD))
self.right.Enable(False)
self.open = wx.BitmapButton(self, id=103, size=(100,-1), bitmap=wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN))
# Testing code
#png = wx.Image("set001_fit_001_1.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
#image = wx.ImageFromBitmap(png)
#image = image.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
#png = wx.BitmapFromImage(image)
# make empty image slot
self.img = wx.StaticBitmap(self, -1, size=(self.display[0]/1.4, self.display[1]/1.4))
## Main sizers
self.vertSizer = wx.BoxSizer(wx.VERTICAL)
# sub sizers
self.buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
# place buttons together
self.buttonSizer.Add(self.left, flag=wx.ALIGN_CENTER)
als.AddLinearSpacer(self.buttonSizer, 15)
self.buttonSizer.Add(self.right, flag=wx.ALIGN_CENTER)
# place arrows and open together
self.vertSizer.Add(self.img, flag=wx.ALIGN_CENTER)
self.vertSizer.Add(self.open, flag=wx.ALIGN_CENTER)
als.AddLinearSpacer(self.vertSizer, 15)
self.vertSizer.Add(self.buttonSizer, flag=wx.ALIGN_CENTER)
als.AddLinearSpacer(self.vertSizer, 15)
self.Bind(wx.EVT_BUTTON, self.onOpen, id=103)
self.Bind(wx.EVT_BUTTON, self.onLeft, id=101)
self.Bind(wx.EVT_BUTTON, self.onRight, id=102)
self.SetSizer(self.vertSizer)
self.vertSizer.Fit(self)
def onOpen(self, evt):
print("Opening")
openFileDialog = wx.FileDialog(self, "Open Image List", "", "", "List (*.ls)|*.ls", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if openFileDialog.ShowModal() == wx.ID_CANCEL:
return
fileName = str(openFileDialog.GetPath())
print(fileName)
# put image list in a python list
image_list = []
f = open(fileName, 'r')
for line in f:
image_list.append(line.rstrip())
f.close()
print(image_list)
# convert every image to wx Image
png_list = []
for image in image_list:
png = wx.Image(image, wx.BITMAP_TYPE_ANY)
png_list.append(png)
# store pngs
print(image_list[::-1])
png_list = png_list[::-1]
for png in png_list[:-1]:
self.future.append(png)
# display first png
self.current = png_list[-1] # put into current buffer
png = self.current.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
png = wx.BitmapFromImage(png)
self.img.SetBitmap(png)
self.Refresh()
self.right.Enable(True)
def onLeft(self, evt):
# put current image into future stack and grab a new current image from past stack
self.future.append(self.current)
self.current = self.past.pop()
png = self.current.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
png = wx.BitmapFromImage(png)
self.img.SetBitmap(png)
self.Refresh()
if len(self.past) <= 0:
self.left.Enable(False)
self.right.Enable(True)
def onRight(self, evt):
# put current image into past stack and load in a new image from future stack
self.past.append(self.current)
self.current = self.future.pop()
png = self.current.Scale(self.display[0]/1.4, self.display[1]/1.4, wx.IMAGE_QUALITY_HIGH)
png = wx.BitmapFromImage(png)
self.img.SetBitmap(png)
self.Refresh()
if len(self.future) <= 0:
self.right.Enable(False)
self.left.Enable(True)
```
Loading them as needed would probably be the best way to reduce memory usage. Or perhaps keeping the current, next and previous images in memory to help speed up switching between views. Or maybe use a caching implementation to keep the N most recently viewed images (plus the next in the sequence) in memory. Then you can fiddle with the size of N to see what works well and is a reasonable compromise between memory and speed.
Another possible improvement would be to not scale the image each time you need to display it, just scale it once when it is read and keep that one in memory (or the cache). You may also want to experiment with pre-converting them to wx.Bitmaps too, as image to bitmap conversions is not a trivial operation.
Well, while I don't consider myself an experienced programmer, especially when it comes to multimedia applications, I had to do this image viewer sort of a program that displays images fullscreen, and the images change when the users press <- or -> arrows.
The general idea was to make a listbox where all the images contained in a certain folder (imgs) are shown, and when someone does double click or hits RETURN a new, fullscreen frame is generated containing, at first, the image selected in the listbox but after the user hits the arrows the images change in conecutive order, just like in a regular image viewer.
At the beginning, when the first 15 - 20 images are generated, everything goes well, after that, although the program still works an intermediary, very unpleasant and highly unwanted, effect appears between image generations, where basically some images that got generated previously are displayed quickly on the screen and after this the right, consecutive image appears. On the first apparitions the effect is barelly noticeble, but after a while it takes longer and longer between generations.
Here's the code that runs when someone does double click on a listbox entry:
def lbclick(self, eve):
frm = wx.Frame(None, -1, '')
frm.ShowFullScreen(True)
self.sel = self.lstb.GetSelection() # getting the selection from the listbox
def pressk(eve):
keys = eve.GetKeyCode()
if keys == wx.WXK_LEFT:
self.sel = self.sel - 1
if self.sel < 0:
self.sel = len(self.chk) - 1
imgs() # invocking the function made for displaying fullscreen images when left arrow key is pressed
elif keys == wx.WXK_RIGHT:
self.sel = self.sel + 1
if self.sel > len(self.chk) - 1:
self.sel = 0
imgs() # doing the same for the right arrow
elif keys == wx.WXK_ESCAPE:
frm.Destroy()
eve.Skip()
frm.Bind(wx.EVT_CHAR_HOOK, pressk)
def imgs(): # building the function
imgsl = self.chk[self.sel]
itm = wx.Image(str('imgs/{0}'.format(imgsl)), wx.BITMAP_TYPE_JPEG).ConvertToBitmap() # obtaining the name of the image stored in the list self.chk
mar = itm.Size # Because not all images are landscaped I had to figure a method to rescale them after height dimension, which is common to all images
frsz = frm.GetSize()
marx = float(mar[0])
mary = float(mar[1])
val = frsz[1] / mary
vsize = int(mary * val)
hsize = int(marx * val)
panl = wx.Panel(frm, -1, size = (hsize, vsize), pos = (frsz[0] / 2 - hsize / 2, 0)) # making a panel container
panl.SetBackgroundColour('#000000')
imag = wx.Image(str('imgs/{0}'.format(imgsl)), wx.BITMAP_TYPE_JPEG).Scale(hsize, vsize, quality = wx.IMAGE_QUALITY_NORMAL).ConvertToBitmap()
def destr(eve): # unprofessionaly trying to destroy the panel container when a new image is generated hopeing the unvanted effect, with previous generated images will disappear. But it doesn't.
keycd = eve.GetKeyCode()
if keycd == wx.WXK_LEFT or keycd == wx.WXK_RIGHT:
try:
panl.Destroy()
except:
pass
eve.Skip()
panl.Bind(wx.EVT_CHAR_HOOK, destr) # the end of my futile tries
if vsize > hsize: # if the image is portrait instead of landscaped I have to put a black image as a container, otherwise in the background the previous image will remain, even if I use Refresh() on the container (the black bitmap named fundal)
intermed = wx.Image('./res/null.jpg', wx.BITMAP_TYPE_JPEG).Scale(frsz[0], frsz[1]).ConvertToBitmap()
fundal = wx.StaticBitmap(frm, 101, intermed)
stimag = wx.StaticBitmap(fundal, -1, imag, size = (hsize, vsize), pos = (frsz[0] / 2 - hsize / 2, 0))
fundal.Refresh()
stimag.SetToolTip(wx.ToolTip('Esc = exits fullscreen\n<- -> arrows = quick navigation'))
def destr(eve): # the same lame attempt to destroy the container in the portarit images situation
keycd = eve.GetKeyCode()
if keycd == wx.WXK_LEFT or keycd == wx.WXK_RIGHT:
try:
fundal.Destroy()
except:
pass
eve.Skip()
frm.Bind(wx.EVT_CHAR_HOOK, destr)
else: # the case when the images are landscape
stimag = wx.StaticBitmap(panl, -1, imag)
stimag.Refresh()
stimag.SetToolTip(wx.ToolTip('Esc = exits fullscreen\n<- -> arrows = quick navigation'))
imgs() # invocking the function imgs for the situation when someone does double click
frm.Center()
frm.Show(True)
Thanks for any advice in advance.
Added later:
The catch is I'm trying to do an autorun presentation for a DVD with lots of images on it. Anyway it's not necessarely to make the above piece of code work properly if there are any other options. I've already tried to use windows image viewer, but strangely enough it doesn't recognizes relative paths and when I do this
path = os.getcwd() # getting the path of the current working directory
sel = listbox.GetSelection() # geting the value of the current selection from the list box
imgname = memlist[sel] # retrieving the name of the images stored in a list, using the listbox selection, that uses as choices the same list
os.popen(str('rundll32.exe C:\WINDOWS\System32\shimgvw.dll,ImageView_Fullscreen {0}/imgsdir/{1}'.format(path, imgname))) # oepning the images up with bloody windows image viewer
it opens the images only when my program is on the hard disk, if it's on a CD / image drive it doesn't do anything.
There's an image viewer included with the wxPython demo package. I also wrote a really simple one here. Either one should help you in your journey. I suspect that you're not reusing your panels/frames and instead you're seeing old ones that were never properly destroyed.