wxpython start multiple timers within a for loop - python

I want to create and start multiple timers in a for loop. My approach has been as follows:
import wx
trials = range(1, 3)
timers = range(7)
name = 'timer'
class TimersClass(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
panel = wx.Panel(self)
self.button1 = wx.Button(panel, label = 'Go')
self.Bind(wx.EVT_BUTTON, self.Timers, self.button1)
def Timers(self, event):
for trial in trials:
for timer in timers:
setattr(self, name + str(timer) + '_' + 'iteration' + str(trial), wx.Timer(self))
print name + str(timer) + '_' + 'iteration' + str(trial)
eval(name + str(timer) + '_' + 'iteration' + str(trial) + '.Start(' + str(timer * 1000, ) + ', OneShoot = True)')
self.Bind(wx.EVT_TIMER, self.Hi)
def Hi(self, event):
print 'Hi, bastard!'
app = wx.App()
frame = TimersClass(None)
frame.Center()
frame.Show()
app.MainLoop()
But the self.timers objects appear not to be created:
Traceback (most recent call last):
File "Escritorio/iteration_timers.py", line 24, in Timers
eval(name + str(timer) + '_' + 'iteration' + str(trial) + '.Start(' + str(timer * 1000, ) + ', OneShoot = True)')
File "", line 1, in
NameError: name 'timer0_iteration1' is not defined
Someone knows why this code doesn't run, or have an alternative approach?
Thanks a lot!!

I recommend using a reasonable structure within the class to store the timers (rather than creating a bunch of class attributes with complicated encoded names). Here's an example:
import wx
trial_range = range(1, 3)
timer_range = range(7)
class TimersClass(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
panel = wx.Panel(self)
self.button1 = wx.Button(panel, label = 'Go')
self.Bind(wx.EVT_BUTTON, self.BuildTimers, self.button1)
self.timers = {} # a structure to hold the timers
def BuildTimers(self, event):
for trial in trial_range:
for timer in timer_range:
new_timer = wx.Timer(self)
new_timer.Start(1 + timer*1000, oneShot=True)
key = (trial, timer)
self.timers[key] = new_timer # to keep the timer in the class
new_timer.mykey = key #optional: to know the key of the timer via the event (see Hi())
self.Bind(wx.EVT_TIMER, self.Hi)
def Hi(self, event):
print "timer:",
print event.GetEventObject().mykey
app = wx.PySimpleApp()
frame = TimersClass(None)
frame.Center()
frame.Show()
app.MainLoop()
When this runs it produces:
timer: (1, 0)
timer: (2, 0)
timer: (1, 1)
timer: (2, 1)
timer: (1, 2)
# etc

Related

Refresh a grid with GridTableBase Class

I am trying to dynamically load a wxGrid with a pandas Dataframe depending on what table is selected in the combobox. I can get the grid to load on intialization, but can't figure out how to get refresh the GridTableClass and grid. Right now I am trying to test with a random Dataframe.
class PageOne(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#wx.StaticText(self, -1, "This is a PageOne object", (20,20))
class PageTwo(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#wx.StaticText(self, -1, "This is a PageTwo object", (40, 40))
class PageThree(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
#wx.StaticText(self, -1, "This is a PageThree object", (60, 60))
class DataTable(gridlib.GridTableBase):
def __init__(self, data):
gridlib.GridTableBase.__init__(self)
self.data = data
#self.colnames = colnames
#Store the row and col length to see if table has changed in size
self._rows = self.GetNumberRows()
self._cols = self.GetNumberCols()
self.odd=gridlib.GridCellAttr()
self.odd.SetBackgroundColour((217,217,217))
self.even=gridlib.GridCellAttr()
self.even.SetBackgroundColour((255,255,255))
def GetAttr(self, row, col, kind):
attr = [self.even, self.odd][row % 2]
attr.IncRef()
return attr
def GetNumberRows(self):
return len(self.data)
def GetNumberCols(self):
return len(self.data.columns) + 1
def IsEmptyCell(self, row, col):
return False
def GetValue(self, row, col):
#if col == 0:
# return None #self.data.index[row]
return self.data.iloc[row, col-1]
def SetValue(self, row, col, value):
self.data.iloc[row, col - 1] = value
def GetColLabelValue(self, col):
if col == 0:
return None
#pass
#return 'Index' if self.data.index.name is None else self.data.index.name
return self.data.columns[col - 1] #[col-1]
#return None
#---------------------------------------------------------------------------
class DataGrid(gridlib.Grid):
def __init__(self, parent, data): # data
gridlib.Grid.__init__(self, parent, - 1) #,colnames,-1 # data
#data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
#data.reset_index(drop=True, inplace=True)
table = DataTable(data)
print ("passed")
# The second parameter means that the grid is to take ownership of the
# table and will destroy it when done. Otherwise you would need to keep
# a reference to it and call it's Destroy method later.
self.SetTable(table, True)
self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnCellRightClick)
def OnCellRightClick(self, event):
print ("OnCellRightClick: (%d,%d)\n" % (event.GetRow(), event.GetCol()))
#-------------------------------------------------------------------------------
class MainFrame(wx.Frame):
def __init__(self, parent, data): # (self, parent, data):
wx.Frame.__init__(self, parent, -1, "Varkey Foundation") #, size=(640,480))
#Create a panel
self.p = wx.Panel(self)
self.Maximize(True)
#Create blank dataframe
data = pd.DataFrame() #pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD')
#data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
#data.reset_index(drop=True, inplace=True)
self.data = DataTable(data)
self.nb = wx.Notebook(self.p)
self.p.SetBackgroundColour( wx.Colour( 0, 0, 0 ) ) # 38,38,38
self.nb.SetBackgroundColour(wx.Colour(58, 56, 56) )
#self.SetBackgroundColour( wx.Colour( 255, 255, 56 ) )
#create the page windows as children of the notebook
self.page1 = PageOne(self.nb)
self.page2 = PageTwo(self.nb)
self.page3 = PageThree(self.nb)
# add the pages to the notebook with the label to show on the tab
self.nb.AddPage(self.page1, "Data")
self.nb.AddPage(self.page2, "Analyze")
self.nb.AddPage(self.page3, "Change Log")
#Create the grid and continue layout
self.grid = DataGrid(self.page1, data)
#grid.SetReadOnly(5,5, True)
#CreateFonts
self.b_font = wx.Font(14,wx.ROMAN,wx.NORMAL,wx.BOLD, True)
self.lbl_font = wx.Font(14,wx.ROMAN,wx.NORMAL,wx.NORMAL, True)
self.cb_font = wx.Font(11,wx.SCRIPT,wx.ITALIC,wx.NORMAL, True)
self.h_font = wx.Font(18,wx.DECORATIVE,wx.ITALIC,wx.BOLD, True)
#Create Title bmp
ico = wx.Icon('varkey_bmp.bmp', wx.BITMAP_TYPE_ICO) #'varkey_frame.bmp'
self.SetIcon(ico)
#Page 1 sizers and widgets
self.title = wx.StaticText(self.page1,label="TITLE",style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE)
self.title.SetForegroundColour((255,255,255))
self.title.SetFont(self.h_font)
self.p1_sizer = wx.BoxSizer(wx.VERTICAL)
self.p1_sizer.Add(self.title,0,wx.EXPAND,5)
self.p1_sizer.Add(self.grid,3,wx.EXPAND | wx.ALL ,25)
#self.p1_sizer.Add(self.btn_new,-0,wx.ALIGN_CENTER,5)
self.page1.SetSizer(self.p1_sizer)
#Page 2 sizers and widgets
self.analyze_grid = gridlib.Grid(self.page2)
self.analyze_grid.CreateGrid(0, 10)
self.p2_sizer = wx.BoxSizer(wx.VERTICAL)
self.p2_sizer.Add(self.analyze_grid,1,wx.EXPAND)
self.page2.SetSizer(self.p2_sizer)
#Page 3 sizers and widgets
self.log_grid = gridlib.Grid(self.page3)
self.log_grid.CreateGrid(0, 9)
self.log_grid.EnableEditing(False)
self.p3_sizer = wx.BoxSizer(wx.VERTICAL)
self.p3_sizer.Add(self.log_grid,1,wx.EXPAND)
self.page3.SetSizer(self.p3_sizer)
#Create widgets for top sizer
#Insert Image
self.staticbitmap = wx.StaticBitmap(self.p)
self.staticbitmap.SetBitmap(wx.Bitmap('varkey_logo2.jpg'))
self
self.lbl_user = wx.StaticText(self.p,label="Username:")
self.lbl_password = wx.StaticText(self.p,label="Password:")
self.lbl_interaction = wx.StaticText(self.p,label="Interaction:")
self.lbl_table = wx.StaticText(self.p,label="Table:")
#SetForground colors
self.lbl_user.SetForegroundColour((255,255,255))
self.lbl_password.SetForegroundColour((255,255,255))
self.lbl_interaction.SetForegroundColour((255,255,255))
self.lbl_table.SetForegroundColour((255,255,255))
#Set Fonts
self.lbl_user.SetFont(self.lbl_font)
self.lbl_password.SetFont(self.lbl_font)
self.lbl_interaction.SetFont(self.lbl_font)
self.lbl_table.SetFont(self.lbl_font)
self.tc_user =wx.TextCtrl(self.p,value='cmccall95',size = (130,25))
self.tc_password =wx.TextCtrl(self.p,value='Achilles95', style=wx.TE_PASSWORD | wx.TE_PROCESS_ENTER,size = (130,25))
#self.tc_password.Bind(wx.EVT_TEXT_ENTER,self.onLogin)
self.tc_user.SetFont(self.cb_font)
self.tc_password.SetFont(self.cb_font)
self.btn_login = wx.Button(self.p,label="Login", size=(105,30))
self.btn_login.SetBackgroundColour(wx.Colour(198, 89, 17))
self.btn_login.SetFont(self.b_font)
self.btn_login.Bind(wx.EVT_BUTTON, self.onLogin) #connect_mysql
self.btn_logout = wx.Button(self.p,label="Logout",size=(105,30))
self.btn_logout.SetBackgroundColour(wx.Colour(192,0,0))
self.btn_logout.SetFont(self.b_font)
#self.btn_logout.Bind(wx.EVT_BUTTON, self.onLogout)
self.combo_interaction = wx.ComboBox(self.p, size = (160,25),style = wx.CB_READONLY | wx.CB_SORT | wx.CB_SORT)
#self.combo_interaction.Bind(wx.EVT_COMBOBOX, self.onComboInteraction)
self.combo_table = wx.ComboBox(self.p, size = (160,25),style = wx.CB_READONLY | wx.CB_SORT | wx.CB_SORT)
#self.combo_table.Bind(wx.EVT_COMBOBOX, self.onHideCommands)
self.combo_interaction.SetFont(self.cb_font)
self.combo_table.SetFont(self.cb_font)
#self.combo_table.Bind(wx.EVT_COMBOBOX ,self.OnComboTable)
self.btn_load = wx.Button(self.p,label="Load Table", size=(105,30))
self.btn_load.SetBackgroundColour(wx.Colour(31, 216, 6))
self.btn_load.SetFont(self.b_font)
#self.btn_load.Bind(wx.EVT_BUTTON, self.onLoadData)
self.btn_load.Bind(wx.EVT_BUTTON, self.test_return)
self.lc_change = wx.ListCtrl(self.p,-1,style = wx.TE_MULTILINE | wx.LC_REPORT | wx.LC_VRULES)
self.lc_change.InsertColumn(0,"User ID")
self.lc_change.InsertColumn(1,"Status")
self.lc_change.InsertColumn(2,"Description")
self.lc_change.InsertColumn(3,"Date/Time")
#Set column widths
self.lc_change.SetColumnWidth(0, 75)
self.lc_change.SetColumnWidth(1, 75)
self.lc_change.SetColumnWidth(2, 450)
self.lc_change.SetColumnWidth(3, 125)
#Create Filler text
self.lbl_filler = wx.StaticText(self.p,label="",size = (125,20))
#Create FlexGridSizers(For top half)
self.left_fgs = wx.FlexGridSizer(3,4,25,15)
self.left_fgs.AddMany([(self.lbl_user,1,wx.ALIGN_LEFT | wx.LEFT,15),(self.tc_user,1,wx.EXPAND),(self.lbl_interaction,1,wx.ALIGN_RIGHT|wx.RIGHT, 10),(self.combo_interaction,1,wx.EXPAND),
(self.lbl_password,1,wx.ALIGN_LEFT| wx.LEFT,15),(self.tc_password,1,wx.EXPAND),(self.lbl_table,1,wx.ALIGN_RIGHT|wx.RIGHT, 10),(self.combo_table),
(self.btn_login,2,wx.EXPAND),(self.btn_logout,1,wx.EXPAND),(self.lbl_filler,1,wx.EXPAND),(self.btn_load,1)])
#Create Top Sizer
self.top_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.top_sizer.Add(self.left_fgs,proportion = 1, flag = wx.ALL|wx.EXPAND,border = 30)
self.top_sizer.Add(self.staticbitmap,2,wx.TOP | wx.RIGHT, border = 40) #30
self.top_sizer.Add(self.lc_change,2,wx.RIGHT|wx.EXPAND ,30)
#create Bottom Sizer
self.bottom_sizer = wx.BoxSizer(wx.VERTICAL)
self.bottom_sizer.Add(self.nb,proportion = 5, flag = wx.LEFT |wx.RIGHT | wx.EXPAND,border = 30)
self.mainsizer = wx.BoxSizer(wx.VERTICAL)
self.mainsizer.Add(self.top_sizer,proportion = 0, flag = wx.ALL|wx.EXPAND,border = 5)
self.mainsizer.Add(self.bottom_sizer,proportion = 1,flag = wx.ALL|wx.EXPAND,border = 5)
#self.mainsizer.Add(self.status_sizer,proportion =0,flag = wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, border = 15)
self.p.SetSizerAndFit(self.mainsizer)
def test_reload(self, event):
data = pd.DataFrame() #pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD')
data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
#data.reset_index(drop=True, inplace=True)
#self.data = DataTable(data)
self.table.data = self.data
self.grid.Refresh()
#Some more functions.......
if __name__ == '__main__':
import sys
app = wx.App()
frame = MainFrame(None, sys.stdout) # (None, sys.stdout)
frame.Show(True)
app.MainLoop()
I've tried many different variations of the function and can't understand how this should work. From my understanding, I should the table and then call the grid to refresh.
def test_reload(self, event):
data = pd.DataFrame() #pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD')
data = pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD'))
self.table.data = self.data
self.grid.Refresh()
I managed to find a solution. Hopefully this helps someone else out.
To reload the grid, I first create new data. Then I destroy the grid, create a new grid, and insert it in place of the old grid. You must then call Layout(). The Freeze() and Thaw() methods are to prevent screen flickering.
def test_reload(self, event):
self.Freeze()
#Create new data
data = pd.DataFrame(np.random.randint(0,100,size=(40000, 5)),columns=list('EFGHD'))
#Destroy and create grid with new data assigned
self.grid.Destroy()
self.grid = DataGrid(self.page1, data)
#Insert grid into existing sizer
self.p1_sizer.Insert(1,self.grid,1,wx.RIGHT| wx.LEFT|wx.EXPAND, 20)
self.p1_sizer.Layout()
self.Thaw()
I'm sure there is a better method out there, but this works and is instant.

How do I make my wxPython scrolledPanel scroll to the bottom of the window?

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)

Check Time Control and change color in listrCtrl

In the part of the code included between ################ Code ######### I try to do a control with if but doesn't work.
I would like that when the variable 'ts' is equal to the variable 'prova' the line(item) in the same list ctrl becomes red. For all item which I insert in the ctrl list. Thanks so much!
import wx
import wx.gizmos as gizmos
import time
import datetime
from datetime import timedelta
class CWindow(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, style = wx.DEFAULT_FRAME_STYLE & ~ wx.CLOSE_BOX ^ wx.MAXIMIZE_BOX ^ wx.RESIZE_BORDER, size=(600,500))
dataCorrente = datetime.datetime.now()
self.Panel = wx.Panel(self, -1)
self.index = 0
self.CTesto = wx.TextCtrl(self.Panel, 1, pos=(10,40), style=wx.TE_PROCESS_ENTER)
self.CTesto.Bind(wx.EVT_TEXT_ENTER,self.add_line)
self.list_ctrl = wx.ListCtrl(self.Panel, pos=(10,90),size=(-1,300),style=wx.LC_REPORT|wx.BORDER_SUNKEN)
self.list_ctrl.InsertColumn(0, 'Name')
self.list_ctrl.InsertColumn(1, 'Time START')
self.list_ctrl.InsertColumn(2, 'Time FINISH', width=100)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
self.led = gizmos.LEDNumberCtrl(self.Panel, -1, pos = (350,25), size = (200,50), style = gizmos.LED_ALIGN_CENTER)
self.led.SetBackgroundColour("#c0c0c0")
self.led.SetForegroundColour("black")
self.OnTimer(None)
self.timer = wx.Timer(self, -1)
self.timer.Start(1000)
self.Bind(wx.EVT_TIMER, self.OnTimer)
style = gizmos.LED_ALIGN_CENTER
def OnTimer(self, event):
current = time.localtime(time.time())
global ts
ts = time.strftime("%H:%M:%S", current)
self.led.SetValue(ts)
#print (ts) # In Loop it's OK
############################################################################################################################
if ts == prova:
self.list_ctrl.SetItemBackgroundColour(self.index, wx.RED)
############################################################################################################################
def add_line(self,event):
val = str(self.CTesto.GetValue())
if val== '':
msg = wx.MessageDialog(self, "Error", "Error", wx.OK| wx.ICON_ERROR)
msg.ShowModal()
msg.Destroy()
else:
dataCorrente = datetime.datetime.now()
oraAttuale =(dataCorrente.strftime("%H:%M:%S"))
plus = (datetime.datetime.strptime(oraAttuale, "%H:%M:%S") + datetime.timedelta(minutes=1))
global plus2
plus2 = plus.strftime("%H:%M:%S")
self.list_ctrl.InsertItem(self.index, val)
self.list_ctrl.SetItem(self.index, 1, oraAttuale)
self.list_ctrl.SetItem(self.index, 2, str(plus2))
self.index += 1
InsVal = (val + " - " + oraAttuale + " - " + plus2 + '\n')
self.CTesto.Clear()
print (InsVal)
prova = InsVal[-9:]
app = wx.App()
frame = CWindow(None, -1, "Example")
frame.Show()
frame.Center()
app.MainLoop()
repr() is your friend in this question.
print(repr(self.prova)) would reveal that it contains a newline character, so that needs to be stripped off.
Also note that the ListCtrl index is zero based, so to apply the colour, you have to use index - 1.
With these minor adjustments your code works, as I hope you planned it to.
import wx
import wx.gizmos as gizmos
import time
import datetime
from datetime import timedelta
class CWindow(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, style = wx.DEFAULT_FRAME_STYLE & ~ wx.CLOSE_BOX ^ wx.MAXIMIZE_BOX ^ wx.RESIZE_BORDER, size=(600,500))
dataCorrente = datetime.datetime.now()
self.Panel = wx.Panel(self, -1)
self.index = 0
self.prova = {}
self.ts = ""
self.CTesto = wx.TextCtrl(self.Panel, 1, pos=(10,40), style=wx.TE_PROCESS_ENTER)
self.CTesto.Bind(wx.EVT_TEXT_ENTER,self.add_line)
self.list_ctrl = wx.ListCtrl(self.Panel, pos=(10,90),size=(-1,300),style=wx.LC_REPORT|wx.BORDER_SUNKEN)
self.list_ctrl.InsertColumn(0, 'Name')
self.list_ctrl.InsertColumn(1, 'Time START')
self.list_ctrl.InsertColumn(2, 'Time FINISH', width=100)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
self.led = gizmos.LEDNumberCtrl(self.Panel, -1, pos = (350,25), size = (200,50), style = gizmos.LED_ALIGN_CENTER)
self.led.SetBackgroundColour("#c0c0c0")
self.led.SetForegroundColour("black")
self.OnTimer(None)
self.timer = wx.Timer(self, -1)
self.timer.Start(1000)
self.Bind(wx.EVT_TIMER, self.OnTimer)
style = gizmos.LED_ALIGN_CENTER
def OnTimer(self, event):
current = time.localtime(time.time())
self.ts = time.strftime("%H:%M:%S", current)
self.led.SetValue(self.ts)
############################################################################################################################
if self.ts in self.prova:
self.list_ctrl.SetItemBackgroundColour(self.prova.pop(self.ts), wx.RED)
############################################################################################################################
def add_line(self,event):
val = str(self.CTesto.GetValue())
if val== '':
msg = wx.MessageDialog(self, "Error", "Error", wx.OK| wx.ICON_ERROR)
msg.ShowModal()
msg.Destroy()
else:
dataCorrente = datetime.datetime.now()
oraAttuale =(dataCorrente.strftime("%H:%M:%S"))
plus = (datetime.datetime.strptime(oraAttuale, "%H:%M:%S") + datetime.timedelta(minutes=1))
plus2 = plus.strftime("%H:%M:%S")
if plus2 in self.prova:
msg = wx.MessageDialog(self, "Duplicated Time", "Error", wx.OK| wx.ICON_ERROR)
msg.ShowModal()
msg.Destroy()
return
self.list_ctrl.InsertItem(self.index, val)
self.list_ctrl.SetItem(self.index, 1, oraAttuale)
self.list_ctrl.SetItem(self.index, 2, str(plus2))
self.index += 1
InsVal = (val + " - " + oraAttuale + " - " + plus2 + '\n')
self.CTesto.Clear()
self.prova[plus2] = self.index -1
app = wx.App()
frame = CWindow(None, -1, "Example")
frame.Show()
frame.Center()
app.MainLoop()
Edit:
If you want to test for all of the entries, turning them red as they occur, you will have to change the nature of prova.
One way would be to make prova a dictionary and use the edited code above.
This provides a method to prevent duplicate entries and a simple method for deleting entries in the dictionary prova reducing the amount of checking required. In this way the code can run continuously for days without hitting duplicates. The dictionary entries are the Finish time and the listctrl's index value, used to perform the highlighting.
The act of deleting the dictionary entry (pop), returns the index number for the highlight.

WxPython BitmapButton not clickable

So, I am trying to make this program for a project I was assigned. The code is still a draft and I really didn't know anything about wxPython when I was assigned this project.
Anyway. What this program does, is create an application that manages photo albums. I got it to create/remove folders and be able to change its root directory and move the program files elsewhere. I also got it to generate bitmap buttons for each 'album' and place them in a FlexGridSizer.
My problem is that these Bitmap Buttons are unclickable.
class RightPanel(wx.Panel):
global path
def __init__(self, parent):
a = wx.GetDisplaySize()
width = 3 * a[0] / 4
height = 3 * a[1] / 4
wx.Panel.__init__(self, parent=parent,
size=(3*width/4, height),
style=wx.EXPAND)
self.SetBackgroundColour('dark grey')
self.widgetSizer = wx.BoxSizer(wx.VERTICAL)
class MasterPanel(wx.Panel):
global delete, CurrentDirg, locale
delete = False
a = wx.GetDisplaySize()
width = 3 * a[0] / 4
height = 3 * a[1] / 4
id = {}
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.MasterPanel = wx.Panel(self,
wx.ID_ANY,
size=(self.width, self.height),
)
self.SetBackgroundColour('light grey')
self.sizer = wx.BoxSizer(wx.VERTICAL)
splitter1 = wx.SplitterWindow(self)
splitter2 = wx.SplitterWindow(splitter1)
left_pt = LeftPanelTop(splitter2)
left_pb = LeftPanelBottom(splitter2)
self.rightP = RightPanel(splitter1)
self.boxsizer2 = wx.BoxSizer(wx.VERTICAL)
splitter2.SetSashGravity(0.5)
splitter2.SplitHorizontally(left_pt, left_pb)
splitter1.SplitVertically(splitter2, self.rightP)
splitter1.SetSashGravity(0.5)
self.gSizer = wx.FlexGridSizer(0, 5, 10, 10)
self.dir_search()
self.boxsizer2.Add(self.gSizer, 1, wx.EXPAND|wx.ALL)
self.rightP.SetSizer(self.boxsizer2)
self.boxsizer2.Layout()
self.sizer.Add(splitter1, 1, wx.EXPAND)
self.SetSizer(self.sizer)
def dir_search(self):
global path, delete
try:
if self.id != {} or delete == True:
sizer = self.gSizer
for i in sizer.GetChildren():
sizer.Hide(0)
sizer.Remove(0)
self.boxsizer2.Layout()
self.gSizer.Layout()
self.id = {}
with open('albums.dir', mode='r', buffering=1) as alb:
names = alb.readlines()
for i in range(len(names)):
names[i] = names[i].rstrip('\n')
paths = [path + '\\' + i for i in names]
counter = 0
for i in paths:
self.dirimcreate(i, counter)
counter += 1
print(self.id)
except Exception as E:
print(E)
sizer = self.gSizer
while sizer.GetChildren():
sizer.Hide(0)
sizer.Remove(0)
self.boxsizer2.Layout()
def dirimcreate(self, path, counter):
pic = wx.Image('input.ico', wx.BITMAP_TYPE_ANY)
pic = pic.Scale(self.width / 10, self.width / 10, wx.IMAGE_QUALITY_HIGH)
pic = pic.ConvertToBitmap()
self.saasda = wx.BitmapButton(self.rightP,
wx.ID_ANY,
pic,
size=(self.width / 10, self.width / 10),
style=wx.NO_BORDER
)
self.saasda.Bind(wx.EVT_BUTTON, self.chdir)
self.saasda.SetDefault()
self.saasda.myname = self.saasda.GetId()
self.id[self.saasda.GetId()] = path
self.gSizer.Add(self.saasda, 0, wx.ALL, 5)
self.boxsizer2.Layout()
def chdir(self, event):
self.Info(message='You clicked a button')
This is what the result looks like.
Thank you in advance.
I found the solution!
It seems that the code for the MasterPanel class included a size parameter in the init, which created an invisible panel that covered everything else, rendering it unclickable.

graphing in wxpython using matplotlib

I'd like to create a live graph within a split-window in wxPython (using matplotlib?) --
So far I have the code that deals with logic: I'm creating a PID controller, and I'm looking to add a live graph (lets say 1 second delay between samples, with pseudo/random samples for now)
my code is here so far (below) - please advise
import wx
import matplotlib as mpl
mpl.use('WXAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
# global constants
Kp = 10
Ki = 2
Kd = 1
# functions used
def AttentionBox( self, message ):
dialog = wx.MessageDialog(self, message, 'Attention!', wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
def StatusBar( self, message=None):
statusMessage = "PID constants( " + str(Kp)+","+str(Ki)+","+str(Kd)+" ): "
self.statusbar.SetStatusText( statusMessage + message )
class PIDFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title="PID Flow Controller", size=(1000,550))
# split the screen
self.sp = wx.SplitterWindow(self)
self.p1 = wx.Panel(self.sp, style = wx.SUNKEN_BORDER)
self.p2 = wx.Panel(self.sp, style = wx.SUNKEN_BORDER)
self.sp.SplitVertically(self.p1, self.p2, 860)
self.statusbar = self.CreateStatusBar()
StatusBar(self, "System Idle")
# define Temperature and Flow Control
wx.StaticBox(self.p2, -1, "System Control", pos=(5, 5), size=(100, 240))
wx.StaticText(self.p2, -1,"Target (litres/min):", pos=(15, 100))
self.Heater = wx.CheckBox(self.p2, -1 , "Heater", pos=(20,35))
self.Chiller = wx.CheckBox(self.p2, -1 , "Chiller", pos=(20,65))
self.TargetFlow = wx.SpinCtrl(self.p2, -1, "100", pos=(15,120), size=(80, 20), min=0, max=350)
self.ActivateButton = wx.Button(self.p2, -1, "Activate",pos=(20,180))
self.ActivateButton.Bind(wx.EVT_BUTTON, self.ActivateSystem)
self.StopButton = wx.Button(self.p2, -1, "Stop", pos=(20,215))
self.StopButton.Bind(wx.EVT_BUTTON, self.StopSystem)
############################################ BUTTONS ######################################################
def ActivateSystem(self, event):
if( self.Heater.GetValue() and self.Chiller.GetValue() ):
StatusBar(self,"Target Flow: " + str(self.TargetFlow.GetValue()) + " litres/min" )
self.Heater.SetValue(0)
self.Chiller.SetValue(0)
AttentionBox( self, "Heater and Chiller? Not Possible - Neither Activated" )
elif( self.Heater.GetValue() ):
StatusBar(self,"Heater Active. Target Flow: " + str(self.TargetFlow.GetValue()) + " litres/min" )
elif( self.Chiller.GetValue() ):
StatusBar(self,"Chiller Active. Target Flow: " + str(self.TargetFlow.GetValue()) + " litres/min" )
else:
StatusBar(self,"Target Flow: " + str(self.TargetFlow.GetValue()) + " litres/min" )
def StopSystem(self, event):
StatusBar(self, "System Idle" )
self.Heater.SetValue(0)
self.Chiller.SetValue(0)
self.TargetFlow.SetValue(0)
############################################ GRAPHING ######################################################
app = wx.App(redirect=False)
frame = PIDFrame(None, -1)
frame.Show()
app.MainLoop()

Categories

Resources