Save the selected value of a combobox in wxpython - python

I'm working to design a gui using wxpython, a pecie of my code is that i have a class which a fram
declaration and also i declared variables that i wanna chage their values based on the comboboxes
selection. i did the folowing:
class myMenu(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(900, 700))
self.ct = 0
self.phaseSelection = ""
self.opSelection = ""
self.instSelection = ""
self.orgSelection = ""
panel = wx.Panel(self, -1)
panel.SetBackgroundColour('#4f3856')
phasesList = ["preOperations", "inOperations", "postOperations"]
self.cbPhases = wx.ComboBox(panel, 500, 'Phase', (50, 150), (160,-1), phasesList, wx.CB_DROPDOWN)
self.Bind(wx.EVT_COMBOBOX, self.OnPhaseSelection, id = self.cbPhases.GetId())
and this is the code of the "OnPhaseSelection" event :
def OnPhaseSelection(self, event):
self.phaseSelection = self.cbPhases.GetValue()
where i wanna save the selected value in the variable "self.phaseSelection" that i declared it with an
empty string as initial value, then i wanna use this variable with the new saved value, but when i run
the program, the variable contains the default value of the combobox! so please what is the problem in
my work ?

I'm not sure what's wrong with that. It looks like it should work. I copied most of it and put it into a runnable example that works on Windows:
import wx
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
panel = wx.Panel(self, wx.ID_ANY)
self.ct = 0
self.phaseSelection = ""
self.opSelection = ""
self.instSelection = ""
self.orgSelection = ""
phasesList = ["preOperations", "inOperations", "postOperations"]
self.combo = wx.ComboBox(panel, choices=phasesList)
self.combo.Bind(wx.EVT_COMBOBOX, self.onCombo)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.combo)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def onCombo(self, event):
"""
"""
self.phaseSelection = self.combo.GetValue()
print self.phaseSelection
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm().Show()
app.MainLoop()

Related

How to switch panels in python using wxPython

I'm trying to create an App which allows the user to switch the information show using buttons. The basic idea of the code is that the user sees buttons on the left side of the screen and when the user presses "button 1", the code shows Panel1. I've made 2 buttons so far and the code for 2 panels is written as well but i can't figure out how to update my MainFrame so it show a different panel when one of the buttons is pressed.
Code:
import wx
TabNumber = 1
class ButtonPanel(wx.Panel):
def __init__(self, parent):
global TabNumber
super(ButtonPanel, self).__init__(parent, -1)
self.Tab1Button = wx.Button(self, label="TAB 1")
self.Tab1Button.Bind(wx.EVT_BUTTON, self.SwitchTab(1))
self.Tab2Button = wx.Button(self, label="TAB 2")
self.Tab2Button.Bind(wx.EVT_BUTTON, self.SwitchTab(2))
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.Tab1Button, wx.CENTER,0)
self.Sizer.Add(self.Tab2Button, wx.CENTER, 0)
self.SetSizer(self.Sizer)
def SwitchTab(self, tab):
def OnClick(event):
print(f"Switch to tab {tab} started")
TabNumber = tab
print(TabNumber)
return OnClick
class Panel1(wx.Panel):
def __init__(self, parent):
super(Panel1, self).__init__(parent, -1)
self.panel = wx.Panel(self)
self.text = wx.StaticText(self.panel, label="1")
class Panel2(wx.Panel):
def __init__(self, parent):
super(Panel2, self).__init__(parent, -1)
self.panel = wx.Panel(self)
self.text = wx.StaticText(self.panel, label="2")
class MainFrame(wx.Frame):
def __init__(self):
super(MainFrame, self).__init__(None, -1, "Test Application")
self.Panels = {
"Panel1": Panel1(self),
"Panel2": Panel2(self)
}
self.MySizer = wx.BoxSizer(wx.HORIZONTAL)
self.tabpanel = ButtonPanel(self)
self.MySizer.Add(self.tabpanel,wx.CENTER,0)
self.InfoPanel = self.Panels["Panel"+str(TabNumber)]
self.MySizer.Add(self.InfoPanel, wx.CENTER,0)
self.SetSizer(self.MySizer)
if __name__ == "__main__":
app = wx.App(False)
frame = MainFrame()
frame.Show()
app.MainLoop()
I was also wondering how I can adjust the ratio for the space that is given to my ButtonPanel and my InfoPanel.
As far as I can see, you are trying to do something that works like a Wizard... On the one hand, you can use wx.adv.Wizard. On the other hand, you can look at this tutorial that does something very similar and adapt it to what you need:
WXPython: How to create a generic wizard
Good luck!

How to I disable the text ctrl when I select the combo box to a particular value?

I want to achieve the effect that when I select the ComboBox to anonymous, the TextCtrl grays out. I want the TextCtrl object be local to the method set_name, I don't want tc be a member of the entire class. That is, how can I achieve this without change tc as self.tc? If it is possible, I also don't want to merge the two methods select_user_type and set_name as a single one.
import wx
class Example(wx.Frame):
def __init__(self, title):
super().__init__(None, title=title)
self.panel = wx.Panel(self)
self.initUI()
def initUI(self):
sizer = wx.GridBagSizer(2, 2)
self.select_user_type(sizer)
self.set_name(sizer)
self.panel.SetSizer(sizer)
sizer.Fit(self)
def select_user_type(self, sizer):
user_type = ['normal', 'anonymous']
combo = wx.ComboBox(self.panel, choices=user_type)
sizer.Add(combo, pos=(0, 1), span=(1, 2), flag=wx.TOP|wx.EXPAND, border=5)
combo.Bind(wx.EVT_COMBOBOX, self.on_user_type)
def set_name(self, sizer):
text1 = wx.StaticText(self.panel, label="Enter your name:")
sizer.Add(text1, pos=(1, 0), flag=wx.LEFT | wx.TOP | wx.BOTTOM, border=10)
tc1 = wx.TextCtrl(self.panel, style=wx.TE_CENTER, value="enter_name_here")
tc1.Bind(wx.EVT_TEXT, self.on_get_text)
sizer.Add(tc1, pos=(1, 1), flag=wx.TOP|wx.RIGHT|wx.BOTTOM|wx.EXPAND, border=5)
def on_get_text(self, e):
tc = e.GetEventObject()
print(tc.GetValue())
def on_user_type(self, e):
print("how to disable text ctrl when I select anonymous")
if __name__ == '__main__':
app = wx.App()
Example("Example").Show()
app.MainLoop()
You have a couple options if you don't want to save the references directly on the class instance
1. save a reference outside of the instance ie
import wx
combo_tc_map = {}
class Example(wx.Frame):
self.panel = wx.Panel(self)
combobox = wx.ComboBox(self.panel)
textctrl = wx.TextCtrl(self.panel)
# references are saved in a module level dict
combo_tc_map[combobox] = textctrl
combobox.Bind(wx.EVT_COMBOBOX, self.on_user_type)
def on_user_type(self, e):
combo = e.GetEventObject()
tc = combo_tc_map[combo]
tc.Disable()
2.
Alternatively you could save a reference to the textctrl directly on the combo box ie:
import wx
class Example(wx.Frame):
self.panel = wx.Panel(self)
combobox = wx.ComboBox(self.panel)
textctrl = wx.TextCtrl(self.panel)
# reference is saved directly to the ComboBox
combobox._linked_textctrl = textctrl
combobox.Bind(wx.EVT_COMBOBOX, self.on_user_type)
def on_user_type(self, e):
combo = e.GetEventObject()
tc = combo._linked_textctrl
tc.Disable()

Calling a Subform of Startup

class MyDialog(wx.Frame):
def __init__(self, parent, title):
self.no_resize = wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER | wx.MAXIMIZE_BOX)
wx.Frame.__init__(self, parent, title=title, size=(500, 450),style = self.no_resize)
self.panel = wx.Panel(self, size=(250, 270))
self.combo = wx.ComboBox(self.panel, -1, pos=(60, 100))
#call settings form here
self.start_read_thread()
self.Centre()
self.Show(True)
def read_employees(self,read_file):
emp_list = []
with open(read_file) as f_obj:
for line in f_obj:
emp_list.append(line)
wx.CallAfter(self.combo.Append, emp_list)
def start_read_thread(self):
filename = 'employees.txt'
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
executor.submit(self.read_employees, filename)
app = wx.App(False)
frame = MyDialog(None, "Messaging App")
app.MainLoop()
Problem:
When the program loads for the first time on the users machine, it will open a settings menu that prompts for the e-mail/password. Without filling out the settings menu, the program is of no use, so calling the settings subform and having the user configure it is necessary. In subsequent startups, it will just read the data in from the file.
Should I call the settings subform from the __init__ constructor directly, or another thread and pass the data? I'm still learning threading, but to me, it seems like overkill for a simple subform to gather the data.
Any time afterward, the user can on the settings menu and access that same subform to update the data.
It does seem like overkill.
Without knowing exactly what your plans are, I'd run with something simple like this.
import wx
import os
class MyDialog(wx.Frame):
def __init__(self, parent, title):
self.no_resize = wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER | wx.MAXIMIZE_BOX)
wx.Frame.__init__(self, parent, title=title, size=(500, 450),style = self.no_resize)
self.panel = wx.Panel(self, size=(250, 270))
self.emp_list = []
e_name = 'employees.txt'
if os.access(e_name, os.R_OK):
with open(e_name,'r') as f_obj:
for line in f_obj:
self.emp_list.append(line.strip())
else:
#Call employees.txt setup routine here
frame = SetUp(parent=self)
self.combo = wx.ComboBox(self.panel, -1,choices=self.emp_list, pos=(60, 100))
self.Centre()
self.Show(True)
class SetUp(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self, parent, wx.ID_ANY, "Setup employee data", size= (280,130))
self.parent=parent
sizer = wx.BoxSizer(wx.VERTICAL)
self.emp_panel = wx.Panel(self, wx.ID_ANY)
self.employee_name = wx.TextCtrl(self.emp_panel, wx.ID_ANY, "Input Employee Name",size=(200,25))
self.emp_button = wx.Button(self.emp_panel, wx.ID_ANY, "Add")
self.emp_button.Bind(wx.EVT_BUTTON, self.AddEmp)
close_button = wx.Button(self.emp_panel, wx.ID_ANY, "Close")
close_button.Bind(wx.EVT_BUTTON, self.OnClose)
sizer.Add(self.employee_name)
sizer.Add(self.emp_button)
sizer.Add(close_button)
self.emp_panel.SetSizer(sizer)
self.Show()
def AddEmp(self,event):
e_name = 'employees.txt'
emp_name = self.employee_name.GetValue()
with open(e_name,'a') as f_obj:
f_obj.write(emp_name+"\n")
def OnClose(self,event):
e_name = 'employees.txt'
if os.access(e_name, os.R_OK):
with open(e_name,'r') as f_obj:
for line in f_obj:
self.parent.combo.Append(line.strip())
self.Close()
app = wx.App()
frame = MyDialog(None, "Messaging App")
app.MainLoop()
It's very rough and ready but I am running of time to do other things.
Hopefully it will help

Get user input from a dialog before showing the mainframe

I have wxPython GUI program that has to get an input from the user to run. I want to show the dialog before the main frame, store the input, close the dialog and then run the main program. Right now I am using raw_input instead. This is my code:
import wx
import wx.lib.iewin as iewin
import subprocess
class MyBrowser(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id,
style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP)
self.transparency = 255
sizer = wx.BoxSizer(wx.VERTICAL)
self.browser = iewin.IEHtmlWindow(self)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
self.Bind(wx.EVT_CHAR_HOOK, self.onKey)
def SetTransparent(self, value):
self.transparency = value
wx.Frame.SetTransparent(self, value)
def GetTransparent(self):
return self.transparency
def decreaseTransparency(self, e):
self.SetTransparent(self.GetTransparent() - 10)
def increaseTransparency(self, e):
self.SetTransparent(self.GetTransparent() + 10)
def onKey(self, evt):
if evt.GetKeyCode() == wx.WXK_DOWN:
self.decreaseTransparency(self)
elif evt.GetKeyCode() == wx.WXK_UP:
self.increaseTransparency(self)
else:
evt.Skip()
def load(self,uri):
self.browser.Navigate(uri)
#starts livestreamer process
response = raw_input("Livestreamers name:\n")
livestreamer = "livestreamer twitch.tv/"
host = subprocess.Popen(['livestreamer', 'twitch.tv/'+response, 'best'], stdout=subprocess.PIPE)
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.Navigate("https://www.twitch.tv/" + response+ "/chat?popout=")
dialog.Show()
app.MainLoop()
host.communicate()[0]
This is what I have in mind:
dialog example
In your browser init create a dialog box, run ShowModal on it, and then get the input with dialog.GetValue
class MyBrowser(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id,
style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP)
self.transparency = 255
self.dialog = wx.TextEntryDialog(None, message="Enter stuff")
self.dialog.ShowModal()
print self.dialog.GetValue()
self.Bind(wx.EVT_CHAR_HOOK, self.onKey)
Obviously replace printing it with whatever you want to do with the value
If you want to access it after instantiation of the MyBrowser object assign it as an instance variable rather than printing.
class MyBrowser(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id,
style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP)
self.transparency = 255
self.dialog = wx.TextEntryDialog(None, message="Enter stuff")
self.dialog.ShowModal()
self.dlg_val = self.dialog.GetValue()
self.Bind(wx.EVT_CHAR_HOOK, self.onKey)
Then use it further down
if __name__ == "__main__":
dialog = MyBrowser(None)
print dialog.dlg_val

Put an AuiManager inside a AuiNotebook page

Is it possible ho put an AuiManager inside an AuiNotebook page?
Have tested with a small sample code, but I only get a 'Segmentation fault'.
Is this possible to begin with? The reason why I want this is to split a notebook page in two parts and get the caption field and the maximize field in the top of each part of the two parts. A simple splitterwindow would work but does not look as good and cannot be maximized as easily. And nor does it have the caption field.
Sample code below.
import wx
import wx.aui
import wx.lib.inspection
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.mgr = wx.aui.AuiManager(self)
self.left = wx.Panel(self, -1, size = (200, 150))
self.right = wx.aui.AuiNotebook(self, -1, size = (200, 150))
self.bottom = wx.Panel(self, -1, size = (200, 150))
self.mgr.AddPane(self.bottom, wx.aui.AuiPaneInfo().Bottom())
self.mgr.AddPane(self.left, wx.aui.AuiPaneInfo().Left().Layer(1))
self.mgr.AddPane(self.right, wx.aui.AuiPaneInfo().CenterPane())
self.new_panel('Panel 1')
self.mgr.Update()
self.Update()
def new_panel(self, nm):
pnl = wx.Window(self)
pnl.identifierTag = nm
self.right.AddPage(pnl, nm, select = True)
self.sizer = wx.BoxSizer()
self.sizer.Add(self.right, 1, wx.EXPAND)
self.SetSizer(self.sizer)
pnl.SetFocus()
mgr = wx.aui.AuiManager(pnl)
left = wx.Panel(self)
right = wx.Panel(self)
mgr.AddPane(left, wx.aui.AuiPaneInfo().Left())
mgr.AddPane(right, wx.aui.AuiPaneInfo().Right())
mgr.Update()
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, '07_wxaui.py')
frame.Show()
self.SetTopWindow(frame)
return 1
if __name__ == "__main__":
app = MyApp(0)
wx.lib.inspection.InspectionTool().Show()
app.MainLoop()
wxAUIManager only works as a child of a wxFrame.
http://docs.wxwidgets.org/trunk/classwx_aui_manager.html

Categories

Resources