I'm making a wx app in which a button is supposed to go into a looped animation when clicked. The background color is what's being animated on the button. It runs fine for a couple of minutes but then the app starts to become unresponsive after a couple of minutes and even crashes the computer sometimes.
It's important for the application's use that the animation be able to run for very long periods of time. I'm using a timer to perform the animation. I've tried routinely clearing the dc, using different frame rates and double buffering and I get the same result every time.
My code is below:
import wx
import os
# begin wxGlade: extracode
# end wxGlade
class LbDisplay(wx.Frame):
sixon = False
sevenon = False
eighton = False
nineon = False
tenon = False
elevenon = False
ID_TIMER = 1
Speed = 1
red = 255
anim = 'down'
def __init__(self, *args, **kwds):
# begin wxGlade: LbDisplay.__init__
kwds["style"] = wx.NO_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE
wx.Frame.__init__(self, *args, **kwds)
self.timer = wx.Timer(self, LbDisplay.ID_TIMER)
self.button_6 = wx.Button(self, -1, "")
self.button_7 = wx.Button(self, -1, "")
self.button_8 = wx.Button(self, -1, "")
self.button_9 = wx.Button(self, -1, "")
self.button_10 = wx.Button(self, -1, "")
self.button_11 = wx.Button(self, -1, "")
self.button_11.Bind(wx.EVT_BUTTON, self.close)
self.button_6.Bind(wx.EVT_BUTTON, self.change_six)
self.Bind(wx.EVT_TIMER, self.blink, id=LbDisplay.ID_TIMER)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.__set_properties()
self.__do_layout()
# end wxGlade
def __set_properties(self):
# begin wxGlade: LbDisplay.__set_properties
self.SetTitle("LbDisplay")
# end wxGlade
def __do_layout(self):
# begin wxGlade: LbDisplay.__do_layout
self.SetMinSize(wx.GetDisplaySize())
grid_sizer_1 = wx.GridSizer(6, 1, 0, 0)
grid_sizer_1.Add(self.button_6, 0, wx.EXPAND, 0)
grid_sizer_1.Add(self.button_7, 0, wx.EXPAND, 0)
grid_sizer_1.Add(self.button_8, 0, wx.EXPAND, 0)
grid_sizer_1.Add(self.button_9, 0, wx.EXPAND, 0)
grid_sizer_1.Add(self.button_10, 0, wx.EXPAND, 0)
grid_sizer_1.Add(self.button_11, 0, wx.EXPAND, 0)
self.SetSizer(grid_sizer_1)
grid_sizer_1.Fit(self)
self.Layout()
# end wxGlade
def change_six(self, e):
if LbDisplay.sixon == False:
LbDisplay.sixon = True
self.timer.Start(LbDisplay.Speed)
else:
self.button_6.SetBackgroundColour(wx.Colour(223, 220, 217, 0))
self.timer.Stop()
LbDisplay.sixon = False
def close(self,e):
os._exit(True)
def blink(self,e):
if LbDisplay.anim == 'down':
LbDisplay.red -= 1
self.button_6.SetBackgroundColour(wx.Colour(LbDisplay.red,0,0))
if LbDisplay.red <= 56:
LbDisplay.anim = 'up'
if LbDisplay.anim == 'up':
LbDisplay.red += 1
self.button_6.SetBackgroundColour(wx.Colour(LbDisplay.red,0,0))
if LbDisplay.red >= 255:
LbDisplay.anim = 'down'
def OnPaint(self, e):
self.dc = wx.PaintDC(self)
# end of class LbDisplay
if __name__ == "__main__":
app = wx.PySimpleApp(0)
wx.InitAllImageHandlers()
LbDisplay = LbDisplay(None, -1, "")
app.SetTopWindow(LbDisplay)
LbDisplay.Show()
app.MainLoop()
Any Ideas?
I figured it out on my own. If you'll observe the above code you'll notice that the timer is using a refresh rate of 300fps. I don't even think a GPU can do much more than 60fps, and this is running straight on the cpu. Lol!
Reducing it to 20fps did the trick. Now it can run all day without a hitch.
Related
Problem: I want to be able to force the scrollbar to the bottom when I call createNewRow(). I can see that the self.Scroll(0, self.scrollRange) is occurring in OnKeyTyped() and the scrollbar moves to the bottom of the window but then the scrollbar moves to the top of the window again. I tried to stop this by binding wx.EVT_SCROLLWIN to OnScroll which calls event.Skip() but it appears that this has not worked. I am out of ideas on how to proceed as I don't know enough about eventHandlers and scroll events in wxPython. Any help on how to proceed would be much appreciated. Full code below.
import os
import wx
import datetime as dt
import wx.lib.scrolledpanel as scrolled
class MyFrame(wx.Frame):
width = 1000
height = 600
today = dt.date.today()
today_date = f"{today:%A - %d %B %Y}"
filename = f"Worklog {today_date}"
wxTHICK_LINE_BORDER = 3
def __init__(self, parent=None, title=filename, size=(width,height - 1)):
wx.Frame.__init__(self, parent=parent, title=title, size=size)
self.parent = parent
self.title = title
self.size = size
self.BuildMenuBar()
def BuildMenuBar(self):
# Menu bar
self.menuBar = wx.MenuBar()
self.fileMenu = wx.Menu()
self.NewOpt = wx.MenuItem(self.fileMenu, wx.ID_NEW, '&New\tCtrl+N')
self.OpenOpt = wx.MenuItem(self.fileMenu, wx.ID_OPEN, '&Open\tCtrl+O')
self.SaveOpt = wx.MenuItem(self.fileMenu, wx.ID_SAVE, '&Save\tCtrl+S')
self.QuitOpt = wx.MenuItem(self.fileMenu, wx.ID_EXIT, '&Quit\tCtrl+Q')
self.fileMenu.Append(self.NewOpt)
self.fileMenu.Append(self.OpenOpt)
self.fileMenu.Append(self.SaveOpt)
self.fileMenu.Append(self.QuitOpt)
self.Bind(wx.EVT_MENU, self.OnQuit, self.QuitOpt)
self.menuBar.Append(self.fileMenu, '&File')
self.SetMenuBar(self.menuBar)
def OnQuit(self, e):
self.Close()
class MyPanel(wx.Panel):
def __init__(self,parent):
wx.Panel.__init__(self, parent=parent)
self.parent = parent
self.size = parent.size
panel_colour = wx.Colour(240, 240, 240, 255)
self.SetBackgroundColour(panel_colour)
self.Refresh()
class MyScrolledPanel(scrolled.ScrolledPanel):
def __init__(self, parent):
scrolled.ScrolledPanel.__init__(self, parent=parent, style = wx.TAB_TRAVERSAL | wx.TB_BOTTOM)
self.parent = parent
# self.size = parent.size
self.width = parent.size[0]
self.height = parent.size[1]
scrollpanel_colour = wx.Colour(255, 255, 255, 255)
self.SetBackgroundColour(scrollpanel_colour)
# Call a refresh to update the UI
self.Refresh()
self.SetAutoLayout(True)
self.SetupScrolling()
self.InitUI()
self.Bind(wx.EVT_SCROLLWIN, self.OnScroll, self)
self.Bind(wx.EVT_SIZE, self.OnSize, self)
def OnScroll(self, e):
e.Skip()
def InitUI(self):
vgap = 0
hgap = 0
self.rowList = []
self.n = 0
self.scrollSizer = wx.GridBagSizer(vgap + 10, hgap + 10)
self.row = self.CreateNewRow(self.n)
self.rowList.append(self.row)
print(f"Row List: {self.rowList[-1]}")
self.scrollSizer.Add(self.row[0], pos = (self.i, 0), flag = wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, border = 10)
self.scrollSizer.Add(self.row[1], pos = (self.i, 1), flag = wx.EXPAND | wx.TOP | wx.RIGHT | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL , border = 10)
self.scrollSizer.AddGrowableCol(1)
self.SetSizer(self.scrollSizer)
self.panelSizer = wx.GridBagSizer(vgap, hgap)
self.panelSizer.AddGrowableRow(0)
self.panelSizer.AddGrowableCol(0)
self.panelSizer.Add(self, pos = (0, 0), flag = wx.EXPAND, border = 0) # Add wx.Window not wx.Sizer
self.parent.SetSizer(self.panelSizer)
def CreateNewRow(self, number):
self.i = number
self.txtStr = "%02d" % (self.i+1) + ". "
self.staticText = wx.StaticText(self, wx.ID_ANY, self.txtStr)
#pos = (x, y)
#self.staticText.SetForegroundColour(wx.Colour(0,0,0))
self.control = wx.TextCtrl(self, self.i)
self.control.SetMaxLength(256)
self.text_history_length = 0
self.control.Bind(wx.EVT_TEXT, self.OnKeyTyped, id = self.i)
#self.control = wx.TextCtrl(self, -1, pos = (x + w + 5,y) )
#style = wx.TE_MULTILINE
elems = [self.staticText, self.control]
return elems
def OnSize(self, e):
self.width, self.height = e.GetSize()
self.SetSize((self.width, self.height))
self.OnSizeChange()
self.Refresh()
def OnSizeChange(self):
# Fit child elements
self.scrollSizer.FitInside(self)
# Resize layout
self.Layout()
# Resize scrolling
self.SetupScrolling()
def OnKeyTyped(self, e):
self.text_length = len(e.GetString())
if (self.text_history_length == 1 and self.text_length == 0):
print(f"History length: {self.text_history_length}")
print(f"Text length: {self.text_length}")
self.text_history_length = self.text_length
pass
elif (self.text_history_length == 0 and self.text_length == 1):
print(f"History length: {self.text_history_length}")
print(f"Text length: {self.text_length}")
self.n += 1
self.row = self.CreateNewRow(self.n)
print(f"Action: {self.row}")
print(f"Row List: {self.rowList[-1]}")
self.rowList.append(self.row)
self.scrollSizer.Add(self.row[0], pos = (self.n, 0), flag = wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, border = 10)
self.scrollSizer.Add(self.row[1], pos = (self.n, 1), flag = wx.EXPAND | wx.TOP | wx.RIGHT | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL , border = 10)
self.SetupScrolling()
self.text_history_length = self.text_length
self.rowList[self.n-1][1].Bind(wx.EVT_TEXT, None, id = self.n-1)
self.text_history_length = 0
else:
print(f"History length: {self.text_history_length}")
print(f"Text length: {self.text_length}")
self.text_history_length = self.text_length
self.rowList[-1][1].SetFocus()
self.scrolledPanelChild = self.GetChildren()[-1] # [ scrollPanel ]
self.ScrollChildIntoView(self.scrolledPanelChild)
self.OnSizeChange()
self.scrollRange = self.GetScrollRange(wx.VERTICAL)
print(f"ScrollRange: {self.scrollRange}")
#self.scrollUnits = self.GetScrollPixelsPerUnit()
#print(f"ScrollUnit: {self.scrollUnits}")
#self.scrollThumb = self.GetScrollThumb(wx.VERTICAL)
#print(f"ScrollThumb: {self.scrollThumb}")
self.Scroll(0, self.scrollRange)
def main():
app = wx.App(False)
app.locale = wx.Locale(wx.Locale.GetSystemLanguage())
frame = MyFrame()
panel = MyPanel(frame)
scrolledPanel = MyScrolledPanel(panel)
frame.Show(True)
app.MainLoop()
if __name__ == "__main__":
main()
In :
def OnSizeChange(self):
# Fit child elements
self.scrollSizer.FitInside(self)
# Resize layout
self.Layout()
# Resize scrolling
self.SetupScrolling()
the SetupScrolling() event causes the scrollbar to reset to the top of the page. So if you comment this the Scroll(0, self.scrollRange) will scroll the scrollbar to the bottom of the page. Improvement would be to get this call to happen after SetupScrolling so that it happens anyway. Maybe the call to SetupScrolling is not necessary in anycase and Layout() is enough.
Old question but still. This can be solved using:
wx.CallAfter(self._scrolled_panel.ScrollChildIntoView, new_text) Or calling any of the other scroll methods from the CallAfter.
or
SetupScrolling(scrollIntoView=True, scrollToTop=False)
I am almost done my wxPython soundboard and want to implement one quick feature.
How does one add another panel to a wxPython window, and how do you implement the text, [ NOW PLAYING ] within that panel.
Here is my code so far:
import wx
import os
import pygame
pygame.init()
##SOUNDS##
##SOUNDS##
class windowClass(wx.Frame):
__goliathwav = pygame.mixer.Sound("goliath.wav")
__channelopen = pygame.mixer.Sound("channelopen.wav")
def __init__(self, *args, **kwargs):
super(windowClass,self).__init__(*args,**kwargs)
self.__basicGUI()
def __basicGUI(self):
panel = wx.Panel(self)
menuBar = wx.MenuBar()
fileButton = wx.Menu()
aboutButton = wx.Menu()
exitItem = fileButton.Append(wx.ID_EXIT, 'Exit','status msg...')
aboutItem = aboutButton.Append(wx.ID_ABOUT, "About")
menuBar.Append(fileButton, 'File')
menuBar.Append(aboutButton, 'About this program')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.__quit, exitItem)
self.Bind(wx.EVT_MENU, self.__onmenuhelpabout, aboutItem)
self.__sound_dict = { "Goliath" : self.__goliathwav,
"Goliath2" : self.__channelopen
}
self.__sound_list = sorted(self.__sound_dict.keys())
self.__list = wx.ListBox(panel,pos=(20,20), size=(250,150))
for i in self.__sound_list:
self.__list.Append(i)
self.__list.Bind(wx.EVT_LISTBOX,self.__on_click)
textarea = wx.TextCtrl(self, -1,
style=wx.TE_MULTILINE|wx.BORDER_SUNKEN|wx.TE_READONLY|
wx.TE_RICH2, size=(250,150))
self.usertext = textarea
#self.__list2 = wx.ListBox(panel,pos=(19.5,180), size=(251,21)) #second panel
#for j in self.__sound_list:
# self.__list2.Append(i)
#self.__list2.Bind(wx.EVT_LISTBOX,self.__on_click)
#wx.TextCtrl(panel,pos=(10,10), size=(250,150))
self.SetTitle("Soundboard")
self.Show(True)
def __onmenuhelpabout(self,event):
dialog = wx.Dialog(self, -1, "[Soundboard]") # ,
#style=wx.DIALOG_MODAL | wx.STAY_ON_TOP)
dialog.SetBackgroundColour(wx.WHITE)
panel = wx.Panel(dialog, -1)
panel.SetBackgroundColour(wx.WHITE)
panelSizer = wx.BoxSizer(wx.VERTICAL)
boldFont = wx.Font(panel.GetFont().GetPointSize(),
panel.GetFont().GetFamily(),
wx.NORMAL,wx.BOLD)
lab1 = wx.StaticText(panel, -1, " SOUNDBOARD ")
lab1.SetFont(wx.Font(36,boldFont.GetFamily(), wx.ITALIC, wx.BOLD))
lab1.SetSize(lab1.GetBestSize())
imageSizer = wx.BoxSizer(wx.HORIZONTAL)
imageSizer.Add(lab1, 0, wx.ALL | wx.ALIGN_CENTRE_VERTICAL, 5)
lab2 = wx.StaticText(panel, -1, "Created by youonlylegoonce(cyrex)(Kommander000) for the glory " + \
"of the republic.")
panelSizer.Add(imageSizer, 0, wx.ALIGN_CENTRE)
panelSizer.Add((10, 10)) # Spacer.
panelSizer.Add(lab2, 0, wx.ALIGN_CENTRE)
panel.SetAutoLayout(True)
panel.SetSizer(panelSizer)
panelSizer.Fit(panel)
topSizer = wx.BoxSizer(wx.HORIZONTAL)
topSizer.Add(panel, 0, wx.ALL, 10)
dialog.SetAutoLayout(True)
dialog.SetSizer(topSizer)
topSizer.Fit(dialog)
dialog.Centre()
btn = dialog.ShowModal()
dialog.Destroy()
def __on_click(self,event):
event.Skip()
name = self.__sound_list[self.__list.GetSelection()]
sound = self.__sound_dict[name]
print("[ NOW PLAYING ] ... %s" % name)
pygame.mixer.Sound.play(sound)
def __quit(self, e):
self.Close()
def main():
app = wx.App()
windowClass(None, -1, style=wx.MAXIMIZE_BOX | wx.CAPTION | wx.CENTRE)
app.MainLoop()
main()
Before:
print("[ NOW PLAYING ] ... %s" % name)
input:
self.usertext.SetValue("[ NOW PLAYING ] ... %s" % name)
P.S. Your indentation is a mess
Is it possible to have countdown as per below image either in python or wxpython (Any other library). I have googled but didn't find the same. I have also checked wxpython but it doesn't have same implementation, however it has gauge but that is not what Im looking for. Can anybody please help me to get it done. Thanks.
I'm able to get what I exactly need after googling and little tweaks. My actual requirement is a countdown (timer) with animation. Below is the code that did the trick(Thanks to Andrea Gavana for wonderful work):
Hope it will help someone else looking for the same.
SpeedMeter
My Implementation:
import wx
import wx.lib.buttons
import SpeedMeter as SM
from math import pi, sqrt
class MyFrame(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, -1, "SpeedMeter Demo ;-)",
wx.DefaultPosition,
size=(400,400),
style=wx.DEFAULT_FRAME_STYLE |
wx.NO_FULL_REPAINT_ON_RESIZE)
panel = wx.Panel(self)
self.SpeedWindow = SM.SpeedMeter(panel,
extrastyle=SM.SM_DRAW_HAND |
SM.SM_DRAW_SECTORS |
SM.SM_DRAW_MIDDLE_TEXT |
SM.SM_DRAW_SECONDARY_TICKS |
SM.SM_DRAW_PARTIAL_FILLER |
SM.SM_DRAW_SHADOW
)
# We Want To Simulate A Clock. Somewhat Tricky, But Did The Job
self.SpeedWindow.SetAngleRange(pi/2, 5*pi/2)
intervals = range(0, 13)
self.SpeedWindow.SetIntervals(intervals)
colours = [wx.SystemSettings_GetColour(0)]*12
self.SpeedWindow.SetIntervalColours(colours)
ticks = [str(interval) for interval in intervals]
ticks[-1] = ""
ticks[0] = "12"
self.SpeedWindow.SetTicks(ticks)
self.SpeedWindow.SetTicksColour(wx.BLUE)
self.SpeedWindow.SetTicksFont(wx.Font(11, wx.SCRIPT, wx.NORMAL, wx.BOLD, True))
self.SpeedWindow.SetNumberOfSecondaryTicks(4)
# Set The Colour For The External Arc
self.SpeedWindow.SetArcColour(wx.BLUE)
self.SpeedWindow.SetHandColour(wx.BLACK)
self.SpeedWindow.SetMiddleText("0 s")
self.SpeedWindow.SetMiddleTextColour(wx.RED)
# We Set The Background Colour Of The SpeedMeter OutSide The Control
self.SpeedWindow.SetSpeedBackground(wx.WHITE)
# Set The Colour For The Shadow
self.SpeedWindow.SetShadowColour(wx.Colour(128, 128, 128))
self.SpeedWindow.SetSpeedValue(0.0)
# These Are Cosmetics For our SpeedMeter Control
# Create The Timer For The Clock
self.timer = wx.PyTimer(self.ClockTimer)
self.currvalue = 0
bsizer2 = wx.BoxSizer(wx.VERTICAL)
hsizer2 = wx.BoxSizer(wx.HORIZONTAL)
stattext2 = wx.StaticText(panel, -1, "A Simple Clock", style=wx.ALIGN_CENTER)
button2 = wx.Button(panel, -1, "Stop")
self.stopped = 0
button2.Bind(wx.EVT_BUTTON, self.OnStopClock)
button2.SetToolTip(wx.ToolTip("Click To Stop/Resume The Clock"))
hsizer2.Add(button2, 0, wx.LEFT, 5)
#hsizer2.Add(stattext2, 1, wx.EXPAND)
#hsizer2.Add(self.helpbuttons[1], 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 5)
bsizer2.Add(self.SpeedWindow, 1, wx.EXPAND)
bsizer2.Add(hsizer2, 0, wx.EXPAND)
panel.SetSizer(bsizer2)
self.timer.Start(1000)
def ClockTimer(self):
if self.currvalue >= 59:
self.currvalue = 0
else:
self.currvalue = self.currvalue + 1
self.SpeedWindow.SetMiddleText(str(self.currvalue) + " s")
self.SpeedWindow.SetSpeedValue(self.currvalue/5.0)
def OnStopClock(self, event):
btn = event.GetEventObject()
if self.stopped == 0:
self.stopped = 1
self.timer.Stop()
btn.SetLabel("Resume")
else:
self.stopped = 0
self.timer.Start()
btn.SetLabel("Stop")
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyFrame()
frame.Show()
#frame.Maximize()
app.MainLoop()
Level: Beginner
I am using python v2.7 and wxPython v3.0 and the OS is windows 7.
My GUI app: Well in my GUI app I am reading some values from a server and then based upon number of these values I create panels in my GUI. Then each of these panels will represent the values in form of a staticText. For eg: If I receive from the server 1,2,3 values, then I create 3 panels each displaying 1, 2 and 3 respectively. This works fine till here.
Problem: I want to check the server every 5 seconds to fetch the values and accordingly update my GUI ie. I have to update the staticText on the panels to display the updated values. I don't want to add new panels I just want to update the values in the old panels.
For eg: If I check the server and if the server returns 1, 2, 3 as values then I want to create 3 panels displaying 1, 2, 3 values respectively. Then after 5 seconds when I check the server again then if server gives 4, 5, 6 as values then I just want to update these values on the old panels. Which means now the panels will display 4, 5, 6 instead of 1, 2, 3 respectively. I read some tutorials & posts on SC regarding using threads, I understood some basic facts too. Unfortunately I don't understand how to apply this concept to my problem.
It would be really great if I could get a working example for my this particular problem so that I could apply the same to my rest of the application.
Code: I have created a short sample code for this particular problem. The getLabels() in the class labelsA and the getLabels() in the class labelsB mimics the server by just generating some random values and returning them in a list. Then the list of values returned by getLabels() of the class labelA and the list of values returned by getLabels() of the class labelsB are used by createPanels()A and createPanelsB() respectively to create panels and to display these values. The panel in white background is panelA and the panel with yellow background is the panelB. It would be really great if some one can teach me how to use threading to update the values of these two panels without freezing/blocking my GUI.
Download: The sample code is provided below and can be downloaded from here too to avoid identation problems.
#!/usr/bin/env python
from random import randrange
import wx
import wx.lib.scrolledpanel
class GUI(wx.Frame):
def __init__(self, parent, id, title):
screenWidth = 800
screenHeight = 450
screenSize = (screenWidth, screenHeight)
wx.Frame.__init__(self, None, id, title, size=screenSize)
self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
panelSizer = wx.BoxSizer(wx.HORIZONTAL)
self.sizerA = sizerA = wx.BoxSizer(wx.VERTICAL)
self.panelA = panelA = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
panelA.SetupScrolling()
panelA.SetBackgroundColour('#FFFFFF')
self.sizerB = sizerB = wx.BoxSizer(wx.VERTICAL)
self.panelB = panelB = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
panelB.SetupScrolling()
panelB.SetBackgroundColour('#FFF000')
panelA.SetSizer(sizerA)
panelB.SetSizer(sizerB)
mainSizer.Add(panelA, 15, wx.EXPAND|wx.ALL)
mainSizer.Add(panelB, 15, wx.EXPAND|wx.ALL)
self.SetSizer(mainSizer)
self.createPanelsA()
self.createPanelsB()
def createPanelsA(self):
k = 0
labelObj = labelsA()
locations = labelObj.getLabel()
print locations
for i in locations:
sPanels = 'sPanel'+str(k)
sPanels = wx.Panel(self.panelA)
label = str(k+1)
text = wx.StaticText(sPanels, -1, label)
text.SetFont(self.locationFont)
text.SetForegroundColour('#0101DF')
self.sizerA.Add(sPanels, 0, wx.ALL, 5)
self.sizerA.Add(wx.StaticLine(self.panelA), 0, wx.ALL|wx.EXPAND, 0)
k += 1
def createPanelsB(self):
k = 0
labelObj = labelsB()
locations = labelObj.getLabel()
print locations
for i in locations:
sPanels = 'sPanel'+str(k)
sPanels = wx.Panel(self.panelB)
label = str(k+1)
text = wx.StaticText(sPanels, -1, label)
text.SetFont(self.locationFont)
text.SetForegroundColour('#0101DF')
self.sizerB.Add(sPanels, 0, wx.ALL, 5)
self.sizerB.Add(wx.StaticLine(self.panelB), 0, wx.ALL|wx.EXPAND, 0)
k += 1
################################################
class labelsA():
def getLabel(self):
mylist =[]
i = randrange(10)
for k in range(1,i+1):
mylist.append(k)
return mylist
###############################################
class labelsB():
def getLabel(self):
mylist =[]
i = randrange(10)
for k in range(1,i+1):
mylist.append(k)
return mylist
###############################################
if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()
Thank you very much for your time. Any help will be appreciated.
Here is a demonstration of creating a thread to get info from somewhere every 5 seconds, and also showing how to create StaticTexts as you need them, and how to update them.
#!/usr/bin/env python
from random import randrange
import wx
import wx.lib.scrolledpanel
import time
import threading
from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub
class GUI(wx.Frame):
def __init__(self, parent, id, title):
screenWidth = 800
screenHeight = 450
screenSize = (screenWidth, screenHeight)
wx.Frame.__init__(self, None, id, title, size=screenSize)
self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.sizer = sizer = wx.BoxSizer(wx.VERTICAL)
self.panel = panel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
panel.SetupScrolling()
panel.SetBackgroundColour('#FFFFFF')
panel.SetSizer(sizer)
mainSizer.Add(panel, 15, wx.EXPAND|wx.ALL)
self.SetSizer(mainSizer)
self.text_labels = [] # Stores the labels where server data is displayed
pub.subscribe(self.OnNewLabels, "NEW_LABELS")
def OnNewLabels(self, labels):
locations = labels
print locations
if len(self.text_labels) < len(labels):
new_labels_needed = len(labels) - len(self.text_labels)
label = "(no data)"
for i in range(new_labels_needed):
sPanels = wx.Panel(self.panel)
text = wx.StaticText(sPanels, -1, label)
text.SetFont(self.locationFont)
text.SetForegroundColour('#0101DF')
self.sizer.Add(sPanels, 0, wx.ALL, 5)
self.sizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 0)
self.text_labels.append(text)
self.sizer.Layout()
k = 0
for label in locations:
self.text_labels[k].SetLabel(str(label))
k=k+1
###############################
#
#
def InterfaceThread():
while True:
# get the info from the server
mylist =[]
i = randrange(10)
for k in range(1,i+1):
mylist.append(randrange(10))
# Tell the GUI about them
wx.CallAfter(pub.sendMessage, "NEW_LABELS", labels = mylist)
time.sleep(5)
class ServerInterface():
def __init__(self):
interface_thread = threading.Thread(target = InterfaceThread, args = ())
interface_thread.start()
#############
#
if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
server_interface = ServerInterface()
app.MainLoop()
For the record, I know this question was answered a long time ago, the same result can be achieved with a simple wx.Timer.
Using the code supplied above:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import wx
import wx.lib.scrolledpanel
from random import randrange
class GUI(wx.Frame):
def __init__(self, parent, id, title):
screenWidth = 800
screenHeight = 450
screenSize = (screenWidth, screenHeight)
wx.Frame.__init__(self, None, id, title, size=screenSize)
self.locationFont = locationFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.sizer = sizer = wx.BoxSizer(wx.VERTICAL)
self.panel = panel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
panel.SetupScrolling()
panel.SetBackgroundColour('#FFFFFF')
panel.SetSizer(sizer)
mainSizer.Add(panel, 15, wx.EXPAND|wx.ALL)
self.SetSizer(mainSizer)
self.text_labels = [] # Stores the labels where server data is displayed
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.timer.Start(5000)
def OnNewLabels(self, labels):
locations = labels
print locations
if len(self.text_labels) < len(labels):
new_labels_needed = len(labels) - len(self.text_labels)
label = "(no data)"
for i in range(new_labels_needed):
sPanels = wx.Panel(self.panel)
text = wx.StaticText(sPanels, -1, label)
text.SetFont(self.locationFont)
text.SetForegroundColour('#0101DF')
self.sizer.Add(sPanels, 0, wx.ALL, 5)
self.sizer.Add(wx.StaticLine(self.panel), 0, wx.ALL|wx.EXPAND, 0)
self.text_labels.append(text)
self.sizer.Layout()
k = 0
for label in locations:
self.text_labels[k].SetLabel(str(label))
k=k+1
if len(self.text_labels) > len(labels):
labels_not_needed = len(self.text_labels) - len(labels)
for i in range(labels_not_needed):
self.text_labels[k].SetLabel("-")
k+=1
def OnTimer(self, evt):
# get the info from the server
mylist =[]
i = randrange(10)
for k in range(1,i+1):
mylist.append(randrange(10))
self.OnNewLabels(mylist)
if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()
I am making a frame with a scrollbar and some images inside. The scrollbar works fine when the frame is empty. However, when I add a picture in, the scrollbars seem to get pushed up into the top left corner of the frame. How can I implement my code so that the scrollbars stay where they are after I add pictures?
Working Code;
import wx
import wx.animate
class ScrollbarFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Scrollbar Example', pos = (100, 50), size=(1000, 1000))
self.scroll = wx.ScrolledWindow(self, -1)
self.scroll.SetScrollbars(1, 1, 1000, 1000)
#self.button = wx.Button(self.scroll, -1, "Scroll Me", pos=(50, 20))
#self.Bind(wx.EVT_BUTTON, self.OnClickTop, self.button)
#self.button2 = wx.Button(self.scroll, -1, "Scroll Back", pos=(500, 350))
#self.Bind(wx.EVT_BUTTON, self.OnClickBottom, self.button2)
self.SetBackgroundColour("gray")
imageName = "01 background.png"
gifName = "Jill.gif"
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight()))
gifImage = wx.animate.GIFAnimationCtrl(self, 0, gifName, pos=(160, 74))
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
def update(self, imageName, gifName):
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight()))
gifImage = wx.animate.GIFAnimationCtrl(self, 0, gifName, pos=(100, 100))
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
def OnClickTop(self, event):
self.scroll.Scroll(600, 400)
def OnClickBottom(self, event):
self.scroll.Scroll(1, 1)
app = wx.PySimpleApp()
frame = ScrollbarFrame()
frame.Show()
app.MainLoop()
if you comment out this part:
gifName = "Jill.gif"
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight()))
gifImage = wx.animate.GIFAnimationCtrl(self, 0, gifName, pos=(160, 74))
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
the window displays properly with the scrollbar. But include either (or both) of the image files, and the problem occurs.
If you want your images inside the scrolled window panel, then you have to put your static bipmap and gifImage inside it. So the parent of your images should not be self (the wx.Frame instance) but self.scroll.
Modify the 4 lines indicated:
...................
wx.StaticBitmap(self.scroll, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight())) # <- this one
gifImage = wx.animate.GIFAnimationCtrl(self.scroll, 0, gifName, pos=(160, 74)) # <- this one
# clears the background
gifImage.GetPlayer().UseBackgroundColour(True)
gifImage.Play()
def update(self, imageName, gifName):
backgroundImage = wx.Image(imageName, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(self.scroll, -1, backgroundImage,(10,5),(backgroundImage.GetWidth(), backgroundImage.GetHeight())) # <- this one
gifImage = wx.animate.GIFAnimationCtrl(self.scroll, 0, gifName, pos=(100, 100)) # <- this one
...................
This puts your two images one over the other. If you want to put them separately (column or row), then you should add them to a sizer inserted in your scrolled window