wxpython layout with sizers - python

I'm having difficulty getting my sizers to work properly in wxpython. I am trying to do a simple one horizontal bar at top (with text in it) and two vertical boxes below (with gridsizers * the left one should only be 2 columns!! * inside each). I want the everything in the image to stretch and fit my panel as well (with the ability to add padding to sides and top/bottom).
I have two main issues:
1. I cant get the text in the horizontal bar to be in the middle (it goes to the left)
2. I would like to space the two vertical boxes to span AND fit the page appropriately (also would like the grids to span better too).
Here is my code (with some parts omitted):
self.LeagueInfoU = wx.Panel(self.LeagueInfo,-1, style=wx.BORDER_NONE)
self.LeagueInfoL = wx.Panel(self.LeagueInfo,-1, style=wx.BORDER_NONE)
self.LeagueInfoR = wx.Panel(self.LeagueInfo,-1, style=wx.BORDER_NONE)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
vbox2a = wx.GridSizer(12,2,0,0)
vbox3a = wx.GridSizer(10,3,0,0)
hbox1a = wx.BoxSizer(wx.VERTICAL)
vbox2 = wx.BoxSizer(wx.VERTICAL)
vbox3 = wx.BoxSizer(wx.VERTICAL)
hbox1.Add(self.LeagueInfoU, 1, wx.EXPAND | wx.ALL, 3)
vbox2.Add(self.LeagueInfoL, 1, wx.EXPAND | wx.ALL, 3)
vbox3.Add(self.LeagueInfoR, 1, wx.EXPAND | wx.ALL, 3)
vbox2a.AddMany([this is all correct])
self.LeagueInfoL.SetSizer(vbox2a)
vbox3a.AddMany([this is all correct])
self.LeagueInfoR.SetSizer(vbox3a)
font = wx.Font(20, wx.DEFAULT, wx.NORMAL, wx.BOLD)
self.Big_Header = wx.StaticText(self.LeagueInfoU, -1, 'Testing This')
self.Big_Header.SetFont(font)
hbox1a.Add(self.Big_Header, 0, wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL)
self.LeagueInfoU.SetSizer(hbox1a)
hbox2.Add(vbox2, 0, wx.EXPAND)
hbox2.Add(vbox3, 0, wx.EXPAND)
vbox.Add(hbox1, 0, wx.EXPAND)
vbox.Add(hbox2, 1, wx.EXPAND)
self.LeagueInfo.SetSizer(vbox)

Is this what you're after?
import wx
class Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.panel = wx.Panel(self)
main_sizer = wx.BoxSizer(wx.VERTICAL)
# Title
self.centred_text = wx.StaticText(self.panel, label="Title")
main_sizer.Add(self.centred_text, 0, wx.ALIGN_CENTRE | wx.ALL, 3)
# Grids
content_sizer = wx.BoxSizer(wx.HORIZONTAL)
grid_1 = wx.GridSizer(12, 2, 0, 0)
grid_1.AddMany(wx.StaticText(self.panel, label=str(i)) for i in xrange(24))
content_sizer.Add(grid_1, 1, wx.EXPAND | wx.ALL, 3)
grid_2 = wx.GridSizer(10, 3, 0, 0)
grid_2.AddMany(wx.StaticText(self.panel, label=str(i)) for i in xrange(30))
content_sizer.Add(grid_2, 1, wx.EXPAND | wx.ALL, 3)
main_sizer.Add(content_sizer, 1, wx.EXPAND)
self.panel.SetSizer(main_sizer)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
Frame(None)
app.MainLoop()

something like this??
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,-1,"Test Stretching!!")
p1 = wx.Panel(self,-1,size=(500,100))
p1.SetMinSize((500,100))
p1.SetBackgroundColour(wx.GREEN)
hsz = wx.BoxSizer(wx.HORIZONTAL)
p2 = wx.Panel(self,-1,size=(200,400))
p2.SetMinSize((200,400))
p2.SetBackgroundColour(wx.RED)
p3 = wx.Panel(self,-1,size=(300,400))
p3.SetMinSize((300,400))
p3.SetBackgroundColour(wx.BLUE)
hsz.Add(p2,1,wx.EXPAND)
hsz.Add(p3,1,wx.EXPAND)
sz = wx.BoxSizer(wx.VERTICAL)
sz.Add(p1,0,wx.EXPAND)
sz.Add(hsz,1,wx.EXPAND)
self.SetSizer(sz)
self.Layout()
self.Fit()
a = wx.App(redirect=False)
f = MyFrame()
f.Show()
a.MainLoop()

Here's one way to do it:
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
mainSizer = wx.BoxSizer(wx.VERTICAL)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
leftGridSizer = wx.GridSizer(rows=10, cols=12, vgap=5, hgap=5)
rightGridSizer = wx.GridSizer(rows=10, cols=3, vgap=5, hgap=5)
title = wx.StaticText(self, label="Main title")
mainSizer.Add(wx.StaticText(self), 0, wx.EXPAND) # add a "spacer"
mainSizer.Add(title, 0, wx.CENTER, wx.ALL, 10)
for row in range(1, 11):
for col in range(1, 13):
lbl = "Row%s Col%s" % (row, col)
leftGridSizer.Add(wx.StaticText(self, label=lbl))
hSizer.Add(leftGridSizer, 0, wx.ALL, 20)
for row in range(1, 11):
for col in range(1, 4):
lbl = "Row%s Col%s" % (row, col)
rightGridSizer.Add(wx.StaticText(self, label=lbl))
hSizer.Add(rightGridSizer, 0, wx.ALL, 20)
mainSizer.Add(hSizer)
self.SetSizer(mainSizer)
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Sizers", size=(1600,600))
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
To learn about spanning rows, I recommend looking at the wxPython demo. I think that may only be supported in wx.GridBagSizer and the FlexGridSizer though. You can try the span parameter though. Also, it should be noted that wx.GROW and wx.EXPAND are one and the same. You might also want to check out the wiki for more information: http://wiki.wxpython.org/GridBagSizerTutorial

Related

pass information among panels in wxpython

I have a pretty complicated wxpython app that has nested notebooks and panels. Basically the structure is that in my main frame I have a notebook (let's say notebook 1, in one page of the notebook I have two panels (upper and lower). In the lower panel I have another notebook (lets say notebook 2). So the question is how do I pass information between these two notebooks pages, and to the upper panels.
I know that there are basically three ways of passing information: by event id, by publisher, by .parent and .child. However I am really confused with the difference of these three methods and when to use them.
I have attached my code as below.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime, time
import wx, sys, wx.grid
import xlrd
import pandas as pd
import numpy as np
import wx.lib.scrolledpanel as scrolled
EVEN_ROW_COLOUR = '#CCE6FF'
GRID_LINE_COLOUR = '#ccc'
import pandas as pd
import numpy as np
class ResultTable(wx.grid.PyGridTableBase):
def __init__(self, data=None):
wx.grid.PyGridTableBase.__init__(self)
self.data = data
self.odd=wx.grid.GridCellAttr()
self.odd.SetBackgroundColour("sky blue")
self.odd.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
self.even=wx.grid.GridCellAttr()
self.even.SetBackgroundColour("sea green")
self.even.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
def GetNumberRows(self):
return self.data.shape[0]
def GetNumberCols(self):
return self.data.shape[1]
def GetValue(self, row, col):
return self.data.loc[row][col]
def GetColLabelValue(self, row):
return list(self.data)[row]
def SetValue(self, row, col, value):
pass
def GetAttr(self, row, col, prop):
attr = wx.grid.GridCellAttr()
if row % 2 == 1:
attr.SetBackgroundColour(EVEN_ROW_COLOUR)
return attr
class ResultTablePanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id, style=wx.BORDER_SUNKEN)
grid = wx.grid.Grid(self)
result = pd.DataFrame({'a' : np.random.randn(100), 'b' : np.random.randn(100), 'c' : np.random.randn(100)})
table = ResultTable(result)
grid.SetTable(table)
grid.AutoSize()
grid.AutoSizeColumns(True)
grid.SetGridLineColour(GRID_LINE_COLOUR)
grid.EnableDragGridSize( False )
grid.SetRowLabelSize( 50 )
grid.SetDefaultCellAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE )
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(grid, 1, wx.ALL|wx.EXPAND)
self.SetSizer(sizer)
btn_ID = parent.GetParent().GetParent().topPanel.analysisButton.GetId()
self.Bind(wx.EVT_BUTTON, self.getResult, id = btn_ID)
def getResult(self,e):
"""
This function should get the variables passed by the analysisOrder function,
once the button on the SearchConditionPanel is clicked.
"""
fileName, start_date, end_date = parent.GetParent().GetParent().topPanel.analysisOrder
print "result get as follows:"
print fileName, start_date, end_date
class SearchConditionPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id, style=wx.BORDER_SUNKEN)
# Creat input box for searching time period
nameTitleLable = wx.StaticText(self,-1, label=u"File Name:")
self.fileNameInput = wx.TextCtrl(self,-1, "20170310221612")
dateTitleLable = wx.StaticText(self,-1, label=u"Date range:")
yearLable1 = wx.StaticText(self, label=u"Year:")
monthLable1 = wx.StaticText(self,-1, label=u"Month:")
dayLable1 = wx.StaticText(self,-1, label=u"Day:")
yearLable2 = wx.StaticText(self,-1, label=u"Year:")
monthLable2 = wx.StaticText(self,-1, label=u"Month:")
dayLable2 = wx.StaticText(self,-1, label=u"Day:")
startLable = wx.StaticText(self,-1, label=u"Start Date:")
endLable = wx.StaticText(self,-1, label=u"End Date:")
self.startYearInput = wx.TextCtrl(self,1, "2016")
self.startMonthInput = wx.TextCtrl(self,-1, "10")
self.startDayInput = wx.TextCtrl(self,-1, "30")
self.endYearInput = wx.TextCtrl(self,-1, "2017")
self.endMonthInput = wx.TextCtrl(self,-1, "11")
self.endDayInput = wx.TextCtrl(self,-1, "22")
self.analysisButton = wx.Button(self, -1, label = u'Start')
exportButton = wx.Button(self, -1, label = u'Export')
exportButton.Disable()
## Set up overall layout for the panel
hbox = wx.BoxSizer(wx.HORIZONTAL)
vbox_File_button = wx.BoxSizer(wx.VERTICAL)
hbox_file = wx.BoxSizer(wx.HORIZONTAL)
vbox_date = wx.BoxSizer(wx.VERTICAL)
hbox_button = wx.BoxSizer(wx.HORIZONTAL)
hbox_startDate = wx.BoxSizer(wx.HORIZONTAL)
hbox_endDate = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(vbox_date, 0, wx.ALIGN_LEFT | wx.ALL, 5)
hbox.Add(wx.StaticLine(self, style=wx.LI_VERTICAL), 0, wx.ALL | wx.EXPAND, 5)
hbox.Add(vbox_File_button, 0, wx.ALIGN_LEFT | wx.ALL, 5)
## Setup the layout for the right side
vbox_File_button.Add(hbox_file, 0, wx.ALIGN_LEFT | wx.ALL, 5)
vbox_File_button.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
vbox_File_button.Add(hbox_button, 0, wx.ALIGN_LEFT | wx.ALL, 5)
hbox_file.Add(nameTitleLable, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 10)
hbox_file.Add(self.fileNameInput, 0, wx.ALL | wx.EXPAND, 5)
hbox_button.Add(self.analysisButton, 1, wx.TOP | wx.LEFT, 10)
hbox_button.Add(exportButton, 1, wx.TOP | wx.LEFT, 10)
## Setup the layout for the left side
vbox_date.Add(dateTitleLable, 0, wx.ALL, 5)
vbox_date.Add(hbox_startDate, 0, wx.ALL | wx.EXPAND, 5)
vbox_date.Add(hbox_endDate, 0, wx.ALL | wx.EXPAND, 5)
hbox_startDate.Add(startLable, 0, wx.ALL, 5)
hbox_startDate.Add(yearLable1, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 5)
hbox_startDate.Add(self.startYearInput, 0, wx.ALL, 5)
hbox_startDate.Add(monthLable1, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 5)
hbox_startDate.Add(self.startMonthInput, 0, wx.ALL|wx.EXPAND, 5)
hbox_startDate.Add(dayLable1, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 5)
hbox_startDate.Add(self.startDayInput, 0, wx.ALL|wx.EXPAND, 5)
hbox_endDate.Add(endLable, 0, wx.LEFT | wx.RIGHT, 5)
hbox_endDate.Add(yearLable2, 0, wx.LEFT, 5)
hbox_endDate.Add(self.endYearInput, 0, wx.LEFT | wx.RIGHT, 5)
hbox_endDate.Add(monthLable2, 0, wx.LEFT, 5)
hbox_endDate.Add(self.endMonthInput, 0, wx.LEFT | wx.RIGHT, 5)
hbox_endDate.Add(dayLable2, 0, wx.LEFT, 5)
hbox_endDate.Add(self.endDayInput, 0, wx.LEFT, 5)
self.SetSizer(hbox)
self.Bind(wx.EVT_BUTTON, self.analysisOrder, id=self.analysisButton.GetId())
def analysisOrder(self,e):
fileName_temp = self.fileNameInput.GetValue().strip()
fileName = fileName_temp + '.xls'
start_date = self.startYearInput.GetValue().strip() + '-' + self.startMonthInput.GetValue().strip() + '-' + self.startDayInput.GetValue().strip()
end_date = self.endYearInput.GetValue().strip() + '-' + self.endMonthInput.GetValue().strip() + '-' + self.endDayInput.GetValue().strip()
print "analysis order button called"
return fileName, start_date, end_date
class ResultNotebook(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# Creat notebooks for window layout
result_notebook = wx.Notebook(self)
data_page = ResultTablePanel(result_notebook, -1)
result_notebook.AddPage(data_page, u"Display Data")
# Set up a boxsizer for the tabs
result_notebook_sizer = wx.BoxSizer(wx.HORIZONTAL)
result_notebook_sizer.Add(result_notebook, 1, wx.EXPAND)
self.SetSizer(result_notebook_sizer)
class ModePage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# Localize all the panels
self.topPanel = SearchConditionPanel(self, -1)
self.botPanel = ResultNotebook(self)
#Set up the panels, align and position them in the right place
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self.topPanel, 0, wx.EXPAND | wx.ALL, 5)
vbox.Add(self.botPanel, -1, wx.EXPAND | wx.ALL, 5)
self.SetSizer(vbox)
self.Centre()
self.Show(True)
class FreqPage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# t = wx.StaticText(self, -1, "This is a Frequency Page object", (20,20))
# Localize all the panels
topPanel = SearchConditionPanel(self, -1)
t = wx.StaticText(self, -1, "This is a Frequency Page object")
#Set up the panels, align and position them in the right place
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(topPanel, 0, wx.EXPAND | wx.ALL, 5)
vbox.Add(t, -1, wx.EXPAND | wx.ALL, 5)
self.SetSizer(vbox)
self.Centre()
self.Show(True)
class OrderPage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# Localize all the panels
self.topPanel = SearchConditionPanel(self, -1)
self.botPanel = ResultNotebook(self)
#Set up the panels, align and position them in the right place
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self.topPanel, 0, wx.EXPAND | wx.ALL, 5)
vbox.Add(self.botPanel, -1, wx.EXPAND | wx.ALL, 5)
self.SetSizer(vbox)
self.Centre()
self.Show(True)
class ShopPage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# Creat notebooks for window layout
shop_notebook = wx.Notebook(self)
mode_page = ModePage(shop_notebook)
freq_page = FreqPage(shop_notebook)
shop_notebook.AddPage(mode_page, u"Mode Analysis")
shop_notebook.AddPage(freq_page, u"Frequency Analysis")
# Set up a boxsizer for the tabs
shop_page_sizer = wx.BoxSizer(wx.HORIZONTAL)
shop_page_sizer.Add(shop_notebook, 1, wx.EXPAND)
self.SetSizer(shop_page_sizer)
##**----------------------------------------------------------------------------------**##
##**-------------- Create a windows to display the entire system ---------------------**##
class OrderAnalysis(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(1024, 576))
# self.Maximize(True) # Default display to be maximized
panel = wx.Panel(self, -1)
# Creat notebooks for window layout
main_notebook = wx.Notebook(panel, style=wx.NB_LEFT)
main_notebook.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT,
wx.FONTWEIGHT_NORMAL,
wx.FONTSTYLE_NORMAL))
# create the page windows as children of the notebook
order_page = OrderPage(main_notebook)
shop_page = ShopPage(main_notebook)
# add the pages to the notebook with the label to show on the tab
main_notebook.AddPage(order_page, u"Order Analysis")
main_notebook.AddPage(shop_page, u"Shop Analysis")
# finally, put the notebook in a sizer for the panel to manage
# the layout
sizer = wx.BoxSizer()
sizer.Add(main_notebook, 1, wx.EXPAND)
panel.SetSizer(sizer)
self.Centre()
self.Show(True)
if __name__ == "__main__":
app = wx.App()
OrderAnalysis(None, -1, 'Order Info Analyser')
app.MainLoop()
As you can see, I have a search condition panel and a result panel that are used in different pages. For each specific page, the search condition and result could be different and only for that page. So my question is, what is the best way to pass the search condition (i.e. data and file name) to the corresponding page to display the result (i.e. the "getResult" function inside "ResultTablePanel" doesn't work).
For example, inside the "order page", the search condition panel has user input start and end dates, and the file name. Below the search condition panel is the result panel showing the computed result based on the search condition. Once the "Start" button is clicked, the "start date", "end date" and "file name" variables are passed to the result panel ("ResultTablePanel") within the "order page". Similarly, since the "Mode page" also calls both "ResultTablePanel" and "SearchConditionPanel", it should have its own "start date", "end date" and "file name" variables (note that they can be same or different from the ones inside "order page"), and its own result displayed in "ResultTablePanel".
Thank you in advance for taking time reviewing and answering my question.
================================================================================
Thank you guys for the help, I have figured it out using PubSub and .parent methods combined. I have attached my solution code as follows:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime, time
import wx, sys, wx.grid
import xlrd
import pandas as pd
import numpy as np
import wx.lib.scrolledpanel as scrolled
EVEN_ROW_COLOUR = '#CCE6FF'
GRID_LINE_COLOUR = '#ccc'
import pandas as pd
import numpy as np
from wx.lib.pubsub import pub
class ResultTable(wx.grid.PyGridTableBase):
def __init__(self, data=None):
wx.grid.PyGridTableBase.__init__(self)
self.data = data
self.odd=wx.grid.GridCellAttr()
self.odd.SetBackgroundColour("sky blue")
self.odd.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
self.even=wx.grid.GridCellAttr()
self.even.SetBackgroundColour("sea green")
self.even.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
def GetNumberRows(self):
if self.data.empty:
return 5
else:
return self.data.shape[0]
def GetNumberCols(self):
if self.data.empty:
return 5
else:
return self.data.shape[1]
def GetValue(self, row, col):
if self.data.empty:
return None
else:
return self.data.loc[row][col]
def GetColLabelValue(self, row):
if self.data.empty:
return None
else:
return list(self.data)[row]
def SetValue(self, row, col, value):
pass
def GetAttr(self, row, col, prop):
attr = wx.grid.GridCellAttr()
if row % 2 == 1:
attr.SetBackgroundColour(EVEN_ROW_COLOUR)
return attr
def ResetView(self):
"""Trim/extend the control's rows and update all values"""
self.getGrid().BeginBatch()
for current, new, delmsg, addmsg in [
(self.currentRows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
(self.currentColumns, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
]:
if new < current:
msg = wx.grid.GridTableMessage(
self,
delmsg,
new, # position
current-new,
)
self.getGrid().ProcessTableMessage(msg)
elif new > current:
msg = wx.grid.GridTableMessage(
self,
addmsg,
new-current
)
self.getGrid().ProcessTableMessage(msg)
self.UpdateValues()
self.getGrid().EndBatch()
# The scroll bars aren't resized (at least on windows)
# Jiggling the size of the window rescales the scrollbars
h,w = grid.GetSize()
grid.SetSize((h+1, w))
grid.SetSize((h, w))
grid.ForceRefresh()
def UpdateValues( self ):
"""Update all displayed values"""
msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
self.getGrid().ProcessTableMessage(msg)
class ResultTablePanel(wx.Panel):
def __init__(self, parent, id, page):
wx.Panel.__init__(self, parent, id, style=wx.BORDER_SUNKEN)
self.grid = wx.grid.Grid(self)
self.parent = parent
result = pd.DataFrame({'0' : np.random.randn(100), 'b' : np.random.randn(100), 'c' : np.random.randn(100)})
result = pd.DataFrame()
table = ResultTable(result)
self.grid.SetTable(table)
self.grid.AutoSize()
self.grid.AutoSizeColumns(True)
self.grid.SetGridLineColour(GRID_LINE_COLOUR)
self.grid.EnableDragGridSize( False )
self.grid.SetRowLabelSize( 50 )
self.grid.SetDefaultCellAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE )
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.grid, 1, wx.ALL|wx.EXPAND)
self.SetSizer(sizer)
pub.subscribe(self.getResult, "panelListener")
def getResult(self, message, page):
"""
This function should get the variables passed by the analysisOrder function,
once the button on the SearchConditionPanel is clicked.
"""
result = pd.DataFrame()
if page == "Order" and self.parent.GetParent().GetParent().page_identifier == "Order":
# For test purpose only
result = pd.DataFrame({'0' : np.random.randn(100), 'b' : np.random.randn(100), 'c' : np.random.randn(100)}) ## For test only
print "Update Order page"
table = ResultTable(result)
self.grid.SetTable(table)
self.Refresh()
if page == "Mode" and self.parent.GetParent().GetParent().page_identifier == "Mode":
result = pd.DataFrame({'0' : np.random.randn(1000), 'b' : np.random.randn(1000)}) ## For test only
print "Update Mode page"
table = ResultTable(result)
self.grid.SetTable(table)
self.Refresh()
else:
pass
class SearchConditionPanel(wx.Panel):
def __init__(self, parent, id, pageID):
wx.Panel.__init__(self, parent, id, style=wx.BORDER_SUNKEN)
# Creat input box for searching time period
nameTitleLable = wx.StaticText(self,-1, label=u"File Name:")
self.fileNameInput = wx.TextCtrl(self,-1, "20170310221612")
dateTitleLable = wx.StaticText(self,-1, label=u"Date range:")
yearLable1 = wx.StaticText(self, label=u"Year:")
monthLable1 = wx.StaticText(self,-1, label=u"Month:")
dayLable1 = wx.StaticText(self,-1, label=u"Day:")
yearLable2 = wx.StaticText(self,-1, label=u"Year:")
monthLable2 = wx.StaticText(self,-1, label=u"Month:")
dayLable2 = wx.StaticText(self,-1, label=u"Day:")
startLable = wx.StaticText(self,-1, label=u"Start Date:")
endLable = wx.StaticText(self,-1, label=u"End Date:")
self.startYearInput = wx.TextCtrl(self,1, "2016")
self.startMonthInput = wx.TextCtrl(self,-1, "10")
self.startDayInput = wx.TextCtrl(self,-1, "30")
self.endYearInput = wx.TextCtrl(self,-1, "2017")
self.endMonthInput = wx.TextCtrl(self,-1, "11")
self.endDayInput = wx.TextCtrl(self,-1, "22")
self.analysisButton = wx.Button(self, -1, label = u'Start')
exportButton = wx.Button(self, -1, label = u'Export')
exportButton.Disable()
## Set up overall layout for the panel
hbox = wx.BoxSizer(wx.HORIZONTAL)
vbox_File_button = wx.BoxSizer(wx.VERTICAL)
hbox_file = wx.BoxSizer(wx.HORIZONTAL)
vbox_date = wx.BoxSizer(wx.VERTICAL)
hbox_button = wx.BoxSizer(wx.HORIZONTAL)
hbox_startDate = wx.BoxSizer(wx.HORIZONTAL)
hbox_endDate = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(vbox_date, 0, wx.ALIGN_LEFT | wx.ALL, 5)
hbox.Add(wx.StaticLine(self, style=wx.LI_VERTICAL), 0, wx.ALL | wx.EXPAND, 5)
hbox.Add(vbox_File_button, 0, wx.ALIGN_LEFT | wx.ALL, 5)
## Setup the layout for the right side
vbox_File_button.Add(hbox_file, 0, wx.ALIGN_LEFT | wx.ALL, 5)
vbox_File_button.Add(wx.StaticLine(self), 0, wx.ALL | wx.EXPAND, 5)
vbox_File_button.Add(hbox_button, 0, wx.ALIGN_LEFT | wx.ALL, 5)
hbox_file.Add(nameTitleLable, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 10)
hbox_file.Add(self.fileNameInput, 0, wx.ALL | wx.EXPAND, 5)
hbox_button.Add(self.analysisButton, 1, wx.TOP | wx.LEFT, 10)
hbox_button.Add(exportButton, 1, wx.TOP | wx.LEFT, 10)
## Setup the layout for the left side
vbox_date.Add(dateTitleLable, 0, wx.ALL, 5)
vbox_date.Add(hbox_startDate, 0, wx.ALL | wx.EXPAND, 5)
vbox_date.Add(hbox_endDate, 0, wx.ALL | wx.EXPAND, 5)
hbox_startDate.Add(startLable, 0, wx.ALL, 5)
hbox_startDate.Add(yearLable1, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 5)
hbox_startDate.Add(self.startYearInput, 0, wx.ALL, 5)
hbox_startDate.Add(monthLable1, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 5)
hbox_startDate.Add(self.startMonthInput, 0, wx.ALL|wx.EXPAND, 5)
hbox_startDate.Add(dayLable1, 0, wx.TOP | wx.LEFT | wx.BOTTOM, 5)
hbox_startDate.Add(self.startDayInput, 0, wx.ALL|wx.EXPAND, 5)
hbox_endDate.Add(endLable, 0, wx.LEFT | wx.RIGHT, 5)
hbox_endDate.Add(yearLable2, 0, wx.LEFT, 5)
hbox_endDate.Add(self.endYearInput, 0, wx.LEFT | wx.RIGHT, 5)
hbox_endDate.Add(monthLable2, 0, wx.LEFT, 5)
hbox_endDate.Add(self.endMonthInput, 0, wx.LEFT | wx.RIGHT, 5)
hbox_endDate.Add(dayLable2, 0, wx.LEFT, 5)
hbox_endDate.Add(self.endDayInput, 0, wx.LEFT, 5)
self.SetSizer(hbox)
self.Bind(wx.EVT_BUTTON, self.analysisOrder, id=self.analysisButton.GetId())
self.page_ID = pageID
def analysisOrder(self,e):
fileName_temp = self.fileNameInput.GetValue().strip()
fileName = fileName_temp + '.xls'
start_date = self.startYearInput.GetValue().strip() + '-' + self.startMonthInput.GetValue().strip() + '-' + self.startDayInput.GetValue().strip()
end_date = self.endYearInput.GetValue().strip() + '-' + self.endMonthInput.GetValue().strip() + '-' + self.endDayInput.GetValue().strip()
print "analysis order button called"
pub.sendMessage("panelListener", message=fileName, page = self.page_ID)
return fileName, start_date, end_date
class ResultNotebook(wx.Panel):
def __init__(self, parent, pageID):
wx.Panel.__init__(self, parent)
# Creat notebooks for window layout
result_notebook = wx.Notebook(self)
self.data_page = ResultTablePanel(result_notebook, -1, page = pageID)
result_notebook.AddPage(self.data_page, u"Display Data")
# Set up a boxsizer for the tabs
result_notebook_sizer = wx.BoxSizer(wx.HORIZONTAL)
result_notebook_sizer.Add(result_notebook, 1, wx.EXPAND)
self.SetSizer(result_notebook_sizer)
class ModePage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.page_identifier = "Mode"
# Localize all the panels
self.topPanel = SearchConditionPanel(self, -1, pageID = "Mode")
self.botPanel = ResultNotebook(self, pageID = "Mode")
#Set up the panels, align and position them in the right place
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self.topPanel, 0, wx.EXPAND | wx.ALL, 5)
vbox.Add(self.botPanel, -1, wx.EXPAND | wx.ALL, 5)
self.SetSizer(vbox)
self.Centre()
self.Show(True)
class FreqPage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# t = wx.StaticText(self, -1, "This is a Frequency Page object", (20,20))
# Localize all the panels
topPanel = SearchConditionPanel(self, -1, pageID = "Frequency")
t = wx.StaticText(self, -1, "This is a Frequency Page object")
#Set up the panels, align and position them in the right place
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(topPanel, 0, wx.EXPAND | wx.ALL, 5)
vbox.Add(t, -1, wx.EXPAND | wx.ALL, 5)
self.SetSizer(vbox)
self.Centre()
self.Show(True)
class OrderPage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.page_identifier = "Order"
# Localize all the panels
self.topPanel = SearchConditionPanel(self, -1, pageID = "Order")
self.botPanel = ResultNotebook(self, pageID = "Order")
#Set up the panels, align and position them in the right place
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self.topPanel, 0, wx.EXPAND | wx.ALL, 5)
vbox.Add(self.botPanel, -1, wx.EXPAND | wx.ALL, 5)
self.SetSizer(vbox)
self.Centre()
self.Show(True)
class ShopPage(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# Creat notebooks for window layout
shop_notebook = wx.Notebook(self)
mode_page = ModePage(shop_notebook)
freq_page = FreqPage(shop_notebook)
shop_notebook.AddPage(mode_page, u"Mode Analysis")
shop_notebook.AddPage(freq_page, u"Frequency Analysis")
# Set up a boxsizer for the tabs
shop_page_sizer = wx.BoxSizer(wx.HORIZONTAL)
shop_page_sizer.Add(shop_notebook, 1, wx.EXPAND)
self.SetSizer(shop_page_sizer)
##**----------------------------------------------------------------------------------**##
##**-------------- Create a windows to display the entire system ---------------------**##
class OrderAnalysis(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(1024, 576))
# self.Maximize(True) # Default display to be maximized
panel = wx.Panel(self, -1)
# Creat notebooks for window layout
main_notebook = wx.Notebook(panel, style=wx.NB_LEFT)
main_notebook.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT,
wx.FONTWEIGHT_NORMAL,
wx.FONTSTYLE_NORMAL))
# create the page windows as children of the notebook
order_page = OrderPage(main_notebook)
shop_page = ShopPage(main_notebook)
# add the pages to the notebook with the label to show on the tab
main_notebook.AddPage(order_page, u"Order Analysis")
main_notebook.AddPage(shop_page, u"Shop Analysis")
# finally, put the notebook in a sizer for the panel to manage
# the layout
sizer = wx.BoxSizer()
sizer.Add(main_notebook, 1, wx.EXPAND)
panel.SetSizer(sizer)
self.Centre()
self.Show(True)
if __name__ == "__main__":
app = wx.App()
OrderAnalysis(None, -1, 'Order Info Analyser')
app.MainLoop()
Thank you everyone again! Much appreciated.
I usually recommend using Pubsub for this sort of thing. It's very easy to implement and makes it easy to pass a message to one or more recipients (panels).
Here's a simple example:
import wx
from wx.lib.pubsub import pub
class OtherFrame(wx.Frame):
""""""
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, wx.ID_ANY, "Secondary Frame")
panel = wx.Panel(self)
msg = "Enter a Message to send to the main frame"
instructions = wx.StaticText(panel, label=msg)
self.msgTxt = wx.TextCtrl(panel, value="")
closeBtn = wx.Button(panel, label="Send and Close")
closeBtn.Bind(wx.EVT_BUTTON, self.onSendAndClose)
sizer = wx.BoxSizer(wx.VERTICAL)
flags = wx.ALL|wx.CENTER
sizer.Add(instructions, 0, flags, 5)
sizer.Add(self.msgTxt, 0, flags, 5)
sizer.Add(closeBtn, 0, flags, 5)
panel.SetSizer(sizer)
def onSendAndClose(self, event):
"""
Send a message and close frame
"""
msg = self.msgTxt.GetValue()
pub.sendMessage("panelListener", message=msg)
pub.sendMessage("panelListener", message="test2", arg2="2nd argument!")
self.Close()
class MyPanel(wx.Panel):
""""""
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
pub.subscribe(self.myListener, "panelListener")
btn = wx.Button(self, label="Open Frame")
btn.Bind(wx.EVT_BUTTON, self.onOpenFrame)
def myListener(self, message, arg2=None):
"""
Listener function
"""
print "Received the following message: " + message
if arg2:
print "Received another arguments: " + str(arg2)
def onOpenFrame(self, event):
"""
Opens secondary frame
"""
frame = OtherFrame()
frame.Show()
class MyFrame(wx.Frame):
""""""
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="PubSub Tutorial")
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
And here is some additional information:
https://wxpython.org/Phoenix/docs/html/wx.lib.pubsub.html
https://www.blog.pythonlibrary.org/2013/09/05/wxpython-2-9-and-the-newer-pubsub-api-a-simple-tutorial/
You mention three ways of passing information but I have to confess I don't understand what you are talking about (and I've written many wxWidget applications). One way of handling the situation you describe is for the event handler to call a function in the parent class, which can then relay the information to other functions/classes. Schematically:
class A:
def __init__(self):
B(self)
self.c = C(self)
def a_function(self, *data):
# do something with the data
# you can pass the information to class C here
class B:
def __init__(self, parent):
self.parent = parent
def an_event_handler(self):
data = something
self.parent.a_function(data)
# or use wx.CallAfter for later execution
class C:
pass
Another solution is the MVC concept, where your event handler passes its information to a model class which stores it or processes it further. This model class can raise a custom wx Event, which components of the UI can then handle as necessary to redraw any affected widgets.

wxPython How to make a dynamic scrolled panel

I have a problem: I want to make a password manager for myself .
I have the logic for the en/decoding done and also I have the dynamic adding of passwords done, but if I add too many passwords to my manager then I can't see all of the passwords because my screen is too small.
I wanted to add a scroll bar but the scroll bar didn't work.
Even after several hours of researching the code didn't want to work. This is the code for the PanelTwo:
class PanelTwo(wx.Panel):
#staticmethod
def scale_bitmap(bitmap, width, height):
image = wx.ImageFromBitmap(bitmap)
image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
result = wx.BitmapFromImage(image)
return result
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
self.refr = wx.Button(self,wx.ID_ANY,u"Refresh")
self.refr.Bind(wx.EVT_BUTTON, self.refresh)
self.co = wx.Button(self, wx.ID_ANY, u"Close")
self.co.Bind(wx.EVT_BUTTON, self.close)
self.number_of_pwds = 0
self.frame = parent
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
controlSizer = wx.BoxSizer(wx.HORIZONTAL)
self.widgetSizer = wx.BoxSizer(wx.VERTICAL)
#controlSizer.Add(self.Passest, 0, wx.CENTER | wx.ALL, 5)
controlSizer.Add(self.refr, 0, wx.CENTER | wx.ALL, 5)
controlSizer.Add(self.co, 0, wx.CENTER | wx.ALL, 5)
self.addButton = wx.Button(self, label="Add")
self.addButton.Bind(wx.EVT_BUTTON, self.onAddWidget)
controlSizer.Add(self.addButton, 0, wx.CENTER | wx.ALL, 5)
self.removeButton = wx.Button(self, label="Remove")
self.removeButton.Bind(wx.EVT_BUTTON, self.onRemoveWidget)
controlSizer.Add(self.removeButton, 0, wx.CENTER | wx.ALL, 5)
self.mainSizer.Add(controlSizer, 0, wx.CENTER)
self.mainSizer.Add(self.widgetSizer, 0, wx.CENTER | wx.ALL, 10)
self.SetSizer(self.mainSizer)
The adding and removing of the Pwds is here :
def onAddWidget(self, event):
self.number_of_pwds += 1
label = "Pwd %s" % self.number_of_pwds
name = "Pwd%s" % self.number_of_pwds
new_Text = wx.StaticText(self, label=label, name=name)
self.widgetSizer.Add(new_Text, 0, wx.ALL, 5)
self.frame.fSizer.Layout()
self.frame.Fit()
def onRemoveWidget(self, event):
if self.widgetSizer.GetChildren():
self.widgetSizer.Hide(self.number_of_pwds - 1)
self.widgetSizer.Remove(self.number_of_pwds - 1)
self.number_of_pwds -= 1
self.frame.fSizer.Layout()
self.frame.Fit()
my main Form is here :
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"Passwort Manager",
size=(300,130))
self.panel_one = PanelOne(self)
self.panel_two = PanelTwo(self)
self.panel_three = PanelThree(self)
self.panel_two.Hide()
self.panel_three.Hide()
self.fSizer = wx.BoxSizer(wx.VERTICAL)
self.fSizer.Add(self.panel_one, 1, wx.EXPAND)
self.fSizer.Add(self.panel_two, 1, wx.EXPAND)
self.fSizer.Add(self.panel_three,1,wx.EXPAND)
self.SetSizer(self.fSizer)
self.SetBackgroundColour(Color.White)
def onSwitchPanels(self, event):
if self.panel_one.IsShown():
self.SetTitle("Passwort Manager")
self.SetBackgroundColour(Color.Random())
self.panel_one.Hide()
self.panel_two.Show()
elif self.panel_two.IsShown():
self.SetTitle("Passwort Manager")
self.SetBackgroundColour(Color.Random())
self.panel_three.Show()
self.panel_two.Hide()
else:
self.SetTitle("Passwort Manager")
self.SetBackgroundColour(Color.Random())
self.panel_one.Show()
self.panel_three.Hide()
self.Layout()
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
So how can I add a dynamic scrollbar that resizes automatically and that works with my code? I am using Python3.6.
Thanks for helping me out.
Have you tried using a scrolled panel?
import wx
import wx.lib.scrolledpanel as scrolled
class TestPanel(scrolled.ScrolledPanel):
def __init__(self, parent):
scrolled.ScrolledPanel.__init__(self, parent, -1)
"""
Write your code here...
"""
self.SetupScrolling()

Why does my horizontal sizers change width after adding them to a vertical sizer?

When I only hade one TxtCtrl, it's right side would expand all the way to the windows edge. But after I created a vertical BoxSizer to and added the horizontal one to that, the TxtCtrol only had a width of about 100 pixels. Why is this?
import wx
class MainPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, style=wx.SIMPLE_BORDER)
top_box = wx.BoxSizer(wx.VERTICAL)
box1 = wx.BoxSizer(wx.HORIZONTAL)
box2 = wx.BoxSizer(wx.HORIZONTAL)
textureName = wx.TextCtrl(self, 1)
texturePath = wx.TextCtrl(self, 1)
box1.Add(wx.StaticText(self, 1, "Name: "), 0, wx.LEFT|wx.RIGHT|wx.TOP, 5)
box1.Add(textureName, 1, wx.ALIGN_LEFT|wx.RIGHT|wx.TOP, 5)
box2.Add(wx.StaticText(self, 1, "Path: "), 0, wx.LEFT|wx.RIGHT|wx.TOP, 5)
box2.Add(texturePath, 1, wx.ALIGN_LEFT|wx.RIGHT|wx.TOP, 5)
top_box.Add(box1)
top_box.Add(box2)
self.SetSizer(top_box)
class MainFrame(wx.Frame):
def __init__(self, parent, id):
title = "Exporter"
wx.Frame.__init__(self, parent, wx.ID_ANY, title,
size=(500, 420),
style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
self.panel = MainPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MainFrame(None, -1)
frame.Centre()
app.MainLoop()
pass
You need to use wx.EXPAND in the style.
top_box.Add(box1, 0, wx.EXPAND)
top_box.Add(box2)
From here: "When an item is Add'ed with the wxEXPAND flag, the item will be resized to fill its alloted area in the opposite orientation."

wxPython and STC Margins - Top and Bottom

Is there any way of implementing padding in the top and bottom of my program for 3 and 4?
Or is there a workaround like adding \n etc....
I feel asif the line numbers and the Styled text are too close to the top and bottom.
How about using panels of the same color nested inside the sizer as a dirty workaround?
import wx
import wx.stc as stc
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.text = stc.StyledTextCtrl(self.panel)
self.text.SetWindowStyle(self.text.GetWindowStyle() | wx.NO_BORDER)
self.text.StyleSetSpec(stc.STC_STYLE_DEFAULT, "size:15,face:Courier New")
self.text.SetWrapMode(stc.STC_WRAP_WORD)
self.text.SetMarginLeft(50)
self.text.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#FFFFFF")
self.menu = wx.Menu()
self.menu.Append(wx.ID_ABOUT, "&About", "Information about this program")
self.menu_bar = wx.MenuBar()
self.menu_bar.Append(self.menu, "&File")
self.SetMenuBar(self.menu_bar)
self.panel_top = wx.Panel(self.panel, size = (20, -1))
self.panel_top.SetBackgroundColour(wx.WHITE)
self.panel_bottom = wx.Panel(self.panel, size = (20, -1))
self.panel_bottom.SetBackgroundColour(wx.WHITE)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.panel_top, 0, wx.ALL | wx.EXPAND)
self.sizer.Add(self.text, 1, wx.ALL | wx.EXPAND)
self.sizer.Add(self.panel_bottom, 0, wx.ALL | wx.EXPAND)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, border=20)
self.panel.SetSizerAndFit(self.border)
self.text.Bind(stc.EVT_STC_CHANGE, self.OnChange)
self.Show()
self.text.SetText("Line!\n"*3)
def OnChange(self, e):
lines = self.text.GetLineCount()
width = self.text.TextWidth(stc.STC_STYLE_LINENUMBER, str(lines)+" ")
self.text.SetMarginWidth(0, width)
if __name__ == "__main__":
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
For your code, modify it as follows:
self.panel_top = wx.Panel(self.panel, size = (20, -1))
self.panel_top.SetBackgroundColour(wx.BLACK)
self.panel_bottom = wx.Panel(self.panel, size = (20, -1))
self.panel_bottom.SetBackgroundColour(wx.BLACK)
#### Add the STC to a Sizer. ####
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel_top, 0, wx.EXPAND,border=20)
sizer.Add(self.text, 1, wx.EXPAND,border=20)
sizer.Add(self.panel_bottom, 0, wx.EXPAND,border=20)
self.panel.SetSizer(sizer)
No, I don't think that Scintilla has a property that controls the size of the top and bottom margins.

wxPython - Getting attribute from another class?

I want to update the self.CreateStatusBar() in MainWindow from MainPanel. And update the self.textOutput in MainPanel from MainWindow.
Been reading alot, but still cant grasp it. Please help me. =)
import wx
ID_EXIT = 110
class MainPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.buttonRun = wx.Button(self, label="Run")
self.buttonRun.Bind(wx.EVT_BUTTON, self.OnRun )
self.buttonExit = wx.Button(self, label="Exit")
self.buttonExit.Bind(wx.EVT_BUTTON, self.OnExit)
self.labelChooseRoot = wx.StaticText(self, label ="Root catalog: ")
self.labelScratchWrk = wx.StaticText(self, label ="Scratch workspace: ")
self.labelMergeFile = wx.StaticText(self, label ="Merge file: ")
self.textChooseRoot = wx.TextCtrl(self, size=(210, -1))
self.textChooseRoot.Bind(wx.EVT_LEFT_UP, self.OnChooseRoot)
self.textScratchWrk = wx.TextCtrl(self, size=(210, -1))
self.textMergeFile = wx.TextCtrl(self, size=(210, -1))
self.textOutput = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY)
self.sizerF = wx.FlexGridSizer(3, 2, 5, 5)
self.sizerF.Add(self.labelChooseRoot) #row 1, col 1
self.sizerF.Add(self.textChooseRoot) #row 1, col 2
self.sizerF.Add(self.labelScratchWrk) #row 2, col 1
self.sizerF.Add(self.textScratchWrk) #row 2, col 2
self.sizerF.Add(self.labelMergeFile) #row 3, col 1
self.sizerF.Add(self.textMergeFile) #row 3, col 2
self.sizerB = wx.BoxSizer(wx.VERTICAL)
self.sizerB.Add(self.buttonRun, 1, wx.ALIGN_RIGHT|wx.ALL, 5)
self.sizerB.Add(self.buttonExit, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
self.sizer1 = wx.BoxSizer()
self.sizer1.Add(self.sizerF, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL, 10)
self.sizer1.Add(self.sizerB, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL)
self.sizer2 = wx.BoxSizer()
self.sizer2.Add(self.textOutput, 1, wx.EXPAND | wx.ALL, 5)
self.sizerFinal = wx.BoxSizer(wx.VERTICAL)
self.sizerFinal.Add(self.sizer1, 0, wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL)
self.sizerFinal.Add(self.sizer2, 1, wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL)
self.SetSizerAndFit(self.sizerFinal)
def OnChooseRoot(self, event):
dlg = wx.DirDialog(self, "Choose a directory:", style=wx.DD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_OK:
root_path = dlg.GetPath()
self.textChooseRoot.SetValue(root_path)
dlg.Destroy()
def OnRun(self, event):
#First check if any of the boxes is empty
pass
def OnExit(self, event):
self.GetParent().Close()
class MainWindow(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="IndexGenerator", size=(430, 330),
style=((wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE |
wx.STAY_ON_TOP) ^ wx.RESIZE_BORDER))
self.CreateStatusBar()
self.fileMenu = wx.Menu()
self.fileMenu.Append(ID_EXIT, "E&xit", "Exit the program")
self.menuBar = wx.MenuBar()
self.menuBar.Append(self.fileMenu, "&File")
self.SetMenuBar(self.menuBar)
wx.EVT_MENU(self, ID_EXIT, self.OnExit)
self.Panel = MainPanel(self)
self.CentreOnScreen()
self.Show()
def OnExit(self, event):
self.Close()
if __name__ == "__main__":
app = wx.App(False)
frame = MainWindow()
app.MainLoop()
Generally speaking, UI elements shouldn't directly modify one another. In an event-driven application, UI elements can listen for events, and then perform some action following the event. Example: if the user does something to element B, element A can be notified of the event and then take an action.
Read more about events in wxPython here:
http://wiki.wxpython.org/AnotherTutorial#Events
I agree with AJ. You shouldn't modify GUI elements from each other directly. That ties things together pretty tightly. Instead, you should use something like pubsub or maybe wx.PostEvent to communicate between classes. Here's a simple pubsub example: http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/
In MainWindow:
self.Panel.textOutput.SetValue("...")
In MainPanel:
wx.Panel.__init__(self, parent)
self.window = parent
self.window.SetStatusText("...")

Categories