i am using wxpython and wx.Choice.
I Tried to bind it but it don't reach the function and don't work, whys that?
Also when i do focus at this Choice (and he already binded), it do run the function but twice.
Why's that and how i can change it?
Select=wx.Choice(parent, choices=SectorList,pos=pos,size=(100,25))
Select.Bind(wx.EVT_KEY_DOWN,self.OnInputCharPressSelect)
I am not sure what you are doing since you don't have a small runnable sample. Here is an example:
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
txt = wx.TextCtrl(self)
self.choice_widget = wx.Choice(self, choices=['a', 'b', 'c'])
self.choice_widget.Bind(wx.EVT_KEY_DOWN, self.OnInputCharPressSelect)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(txt, 0, wx.ALL, 5)
main_sizer.Add(self.choice_widget, 0, wx.ALL, 5)
self.SetSizer(main_sizer)
def OnInputCharPressSelect(self, event):
print('OnInputCharPressSelect fired')
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='Choices')
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MainFrame()
app.MainLoop()
When I TAB into the Choice widget from the TextCtrl widget, the bound event handler does not fire, which is correct. It also won't fire if I select an item using the mouse. To do that, you would need to bind the Choice widget to EVT_CHOICE.
To get the OnInputCharPressSelect to fire, you must have the Choice widget highlighted (i.e. selected) and then press a key on your keyboard. This will cause the handler to be fired once per key press.
I tested this code on Window 7 with wxPython 4.0.0b2 and Python 3.6.
Related
I noticed I can have a help string appear in the status bar whenever I mouse over tools in my toolbar. I cannot find a way to accomplish this with text buttons.
My toolbar creation is similar to
# Make Tool Bar
toolbar = self.CreateToolBar()
# Make Tool Bar Items
# Play
self.addBasicTool(toolbar, "Play",
"This is my help string",
stuff.image_play,
self.OnPlay)
# My Button
btn = wx.Button(toolbar, wx.ID_OPEN, label="TEXT BUTTON ")
btn.Bind(wx.EVT_BUTTON, self.OnButtonPress)
toolbar.AddControl(btn)
addBasicTool just takes the image, scales it to a proper size, creates the tool with AddBasicTool, and binds the tool to the handler.
def addBasicTool(self, toolbar, label, desc, imgPath, handler):
icon_width=stuff.toolbar_icon_w
icon_height=stuff.toolbar_icon_h
size = (icon_width, icon_height)
img = wx.Image(imgPath, wx.BITMAP_TYPE_ANY).\
Scale(*size).ConvertToBitmap()
tool = toolbar.AddSimpleTool(-1, img, label, desc)
self.Bind(wx.EVT_MENU, handler, tool)
For the tool, the helper string is set pretty straight forward. I can't find anything to do the same with a button.
This button may just end up being a filler until I get an icon for it, but I'm still curious how helper strings can be done. I could have a handler that sets the statusBar when the mouse is over the button, but I feel like that is already done somewhere. Thanks the help
Basically you'll have to catch the mouse as it moves over your buttons and update the status bar accordingly. It's not very hard. You just need to bind to wx.EVT_MOTION. Here's a simple example:
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
self.frame = parent
test_btn = wx.Button(self, label='Test Button')
test_btn.Bind(wx.EVT_MOTION, self.updateStatusBar)
test_btn_2 = wx.Button(self, label='Test Button')
test_btn_2.Bind(wx.EVT_MOTION, self.updateStatusBar)
self.buttons = {test_btn: 'Test help string',
test_btn_2: 'Another string'}
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(test_btn, 0, wx.ALL, 5)
main_sizer.Add(test_btn_2, 0, wx.ALL, 5)
self.SetSizer(main_sizer)
#----------------------------------------------------------------------
def updateStatusBar(self, event):
""""""
btn = event.GetEventObject()
if btn in self.buttons:
status = self.buttons[btn]
self.frame.sb.SetStatusText(status)
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title='Test Help Strings')
panel = MyPanel(self)
self.sb = self.CreateStatusBar()
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
I think this must be a pretty basic question, but I have Googled it to death with no clear answer, so here goes: I have a TextCtrl and I want a pretty basic sequence of events: 1) The user moves focus to the control by hook or by crook. 2) The user types something in the TextCtrl. 3) The user hits return or tab. 4) At this point, the code grabs the text in the TextCtrl, does some simple processing, and then moves focus to whatever control is next in the tabbing order.
Can anyone tell me how to do this? It seems so basic to me, but I can't find the answer anywhere. Sorry if I've missed something obvious.
To get this to work properly, you will need to catch key events and check to see if the user has pressed the Enter or Tab keys. As #sundar as already mentioned, to get tabbing to work correctly on all platforms, the widgets need to be children of a panel. Here's a fairly simple example:
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
self.text = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
self.text.Bind(wx.EVT_KEY_DOWN, self.onEnter)
btn = wx.Button(self, label="Do something")
self.text.SetFocus()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.text, 0, wx.EXPAND|wx.ALL, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
self.SetSizer(sizer)
#----------------------------------------------------------------------
def onEnter(self, event):
""""""
keycode = event.GetKeyCode()
if keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER or keycode == wx.WXK_TAB:
self.process_text(event=None)
event.EventObject.Navigate()
event.Skip()
#----------------------------------------------------------------------
def process_text(self, event):
"""
Do something with the text
"""
text = self.text.GetValue()
print text.upper()
for word in text.split():
print word
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="TextCtrl Demo")
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
Here we bind to wx.EVT_KEY_DOWN and have it extract the keycode that was pressed. Then it checks to see if the keycode is the Enter or Tab key. If it is, it calls a function to process the text and then it calls event.EventObject.Navigate(), which will cause wxPython to move the focus to the next widget in the tab order.
You might want to read the following about that subject:
http://wxpython-users.1045709.n5.nabble.com/TextCtrl-processing-enter-key-td5075499.html
http://www.wxpython.org/docs/api/wx.NavigationKeyEvent-class.html
For more information on wxPython's key and char events, see the following:
http://www.wxpython.org/docs/api/wx.KeyEvent-class.html
http://www.blog.pythonlibrary.org/2009/08/29/wxpython-catching-key-and-char-events/
1.For the tabbing to work at all, the window or individual panel you plonk controls/wigits on has to have as part of its style flag the following: wxTAB_TRAVERSAL ie;
class MyPanel(wx.Panel):
def __init__(self, parent,id):
wx.Panel.__init__(self, parent, id, wx.DefaultPosition,wx.DefaultSize,
wx.RAISED_BORDER|wx.TAB_TRAVERSAL)
2. The tab order is set by the order you add controls to the panel or frame.
3) Tabbing order also seems to be dependent in the order widgets are created. I assume this is due to widget ID numbers. Order of addition to sizers/panels did not seem to help me with .
4) Here's a little Demofor setting tab order once you have the controls set up:
order = (control1, control2, control3, ...)
for i in xrange(len(order) - 1):
order[i+1].MoveAfterInTabOrder(order[i])
Could someone show me how I could return a value from a wxPython Frame? When the use clicks close, I popup a message dialog asking him a question. I would like to return the return code of this message dialog to my calling function.
Thanks
Because the wxFrame has events that process via the app.MainLoop() functionality, the only way to get at the return value of a wx.Frame() is via catching an event.
The standard practice of handling events is typically from within the class which derives from wx.Window itself (e.g., Frame, Panel, etc.). Since you want code exterior to the wx.Frame to receive information that was gathered upon processing the OnClose() event, then the best way to do that is to register an event handler for your frame.
The documentation for wx.Window::PushEventHandler is probably the best resource and even the wxpython wiki has a great article on how to do this. Within the article, they register a custom handler which is an instance of "MouseDownTracker." Rather than instantiating within the PushEventHandler call, you'd want to instantiate it prior to the call so that you can retain a handle to the EventHandler derived class. That way, you can check on your derived EventHandler class-variables after the Frame has been destroyed, or even allow that derived class to do special things for you.
Here is an adaptation of that code from the wx python wiki (admittedly a little convoluted due to the requirement of handling the results of a custom event with a "calling" function):
import sys
import wx
import wx.lib.newevent
(MyCustomEvent, EVT_CUSTOM) = wx.lib.newevent.NewEvent()
class CustomEventTracker(wx.EvtHandler):
def __init__(self, log, processingCodeFunctionHandle):
wx.EvtHandler.__init__(self)
self.processingCodeFunctionHandle = processingCodeFunctionHandle
self.log = log
EVT_CUSTOM(self, self.MyCustomEventHandler)
def MyCustomEventHandler(self, evt):
self.log.write(evt.resultOfDialog + '\n')
self.processingCodeFunctionHandle(evt.resultOfDialog)
evt.Skip()
class MyPanel2(wx.Panel):
def __init__(self, parent, log):
wx.Panel.__init__(self, parent)
self.log = log
def OnResults(self, resultData):
self.log.write("Result data gathered: %s" % resultData)
class MyFrame(wx.Frame):
def __init__(self, parent, ID=-1, title="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE):
wx.Frame.__init__(self, parent, ID, title, pos, size, style)
self.panel = panel = wx.Panel(self, -1, style=wx.TAB_TRAVERSAL | wx.CLIP_CHILDREN | wx.FULL_REPAINT_ON_RESIZE)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add((25, 25))
row = wx.BoxSizer(wx.HORIZONTAL)
row.Add((25,1))
m_close = wx.Button(self.panel, wx.ID_CLOSE, "Close")
m_close.Bind(wx.EVT_BUTTON, self.OnClose)
row.Add(m_close, 0, wx.ALL, 10)
sizer.Add(row)
self.panel.SetSizer(sizer)
def OnClose(self, evt):
dlg = wx.MessageDialog(self, "Do you really want to close this frame?", "Confirm Exit", wx.OK | wx.CANCEL | wx.ICON_QUESTION)
result = dlg.ShowModal()
dlg.Destroy()
if result == wx.ID_CANCEL:
event = MyCustomEvent(resultOfDialog="User Clicked CANCEL")
self.GetEventHandler().ProcessEvent(event)
else: # result == wx.ID_OK
event = MyCustomEvent(resultOfDialog="User Clicked OK")
self.GetEventHandler().ProcessEvent(event)
self.Destroy()
app = wx.App(False)
f2 = wx.Frame(None, title="Frame 1 (for feedback)", size=(400, 350))
p2 = MyPanel2(f2, sys.stdout)
f2.Show()
eventTrackerHandle = CustomEventTracker(sys.stdout, p2.OnResults)
f1 = MyFrame(None, title="PushEventHandler Tester (deals with on close event)", size=(400, 350))
f1.PushEventHandler(eventTrackerHandle)
f1.Show()
app.MainLoop()
You can get the result of clicking the OK, CANCEL buttons from the Dialog ShowModal method.
Given dialog is an instance of one of the wxPython Dialog classes:
result = dialog.ShowModal()
if result == wx.ID_OK:
print "OK"
else:
print "Cancel"
dialog.Destroy()
A few years late for the initial question, but when looking for the answer to this question myself, I stumbled upon a built-in method of getting a return value from a modal without messing with any custom event funniness. Figured I'd post here in case anyone else needs it.
It's simply this guy right here:
wxDialog::EndModal void EndModal(int retCode)
Ends a modal dialog, passing a value to be returned from the
*wxDialog::ShowModal invocation.*
Using the above, you can return whatever you want from the Dialog.
An example usage would be subclassing a wx.Dialog, and then placing the EndModal function in the button handlers.
class ProjectSettingsDialog(wx.Dialog):
def __init__(self):
wx.Dialog.__init__(self, None, -1, "Project Settings", size=(600,400))
sizer = wx.BoxSizer(wx.VERTICAL) #main sized
sizer.AddStretchSpacer(1)
msg = wx.StaticText(self, -1, label="This is a sample message")
sizer.Add(msg, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 15)
horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
okButton = wx.Button(self, -1, 'OK')
self.Bind(wx.EVT_BUTTON, self.OnOK, okButton)
cancelBtn = wx.Button(self, -1, "Cancel")
self.Bind(wx.EVT_BUTTON, self.OnCancel, cancelBtn)
horizontal_sizer.Add(okButton, 0, wx.ALIGN_LEFT)
horizontal_sizer.AddStretchSpacer(1)
horizontal_sizer.Add(cancelBtn, 0, wx.ALIGN_RIGHT)
sizer.Add(horizontal_sizer, 0)
sizer.AddStretchSpacer(1)
self.SetSizer(sizer)
def OnOK(self, event):
self.EndModal(wx.ID_OK) #returns numeric code to caller
self.Destroy()
def OnCancel(self, event):
self.EndModal(wx.ID_CANCEL) #returns numeric code to caller
self.Destroy()
(Note: I just banged this code out quickly; didn't test the sizers)
As you can see, all you need to do is call the EndModal from a button event to return a value to whatever spawned the dialog.
I wanted to do the same thing, to have a graphical "picker" that I could run from within a console app. Here's how I did it.
# Fruit.py
import wx
class Picker (wx.App):
def __init__ (self, title, parent=None, size=(400,300)):
wx.App.__init__(self, False)
self.frame = wx.Frame(parent, title=title, size=size)
self.apple_button = wx.Button(self.frame, -1, "Apple", (0,0))
self.apple_button.Bind(wx.EVT_BUTTON, self.apple_button_click)
self.orange_button = wx.Button(self.frame, -1, "Orange", (0,100))
self.orange_button.Bind(wx.EVT_BUTTON, self.orange_button_click)
self.fruit = None
self.frame.Show(True)
def apple_button_click (self, event):
self.fruit = 'apple'
self.frame.Destroy()
def orange_button_click (self, event):
self.fruit = 'orange'
self.frame.Destroy()
def pick (self):
self.MainLoop()
return self.fruit
Then from a console app, I would run this code.
# Usage.py
import Fruit
picker = Fruit.Picker('Pick a Fruit')
fruit = picker.pick()
print 'User picked %s' % fruit
user1594322's answer works but it requires you to put all of your controls in your wx.App, instead of wx.Frame. This will make recycling the code harder.
My solution involves define a "PassBack" variable when defining your init function. (similar to "parent" variable, but it is normally used already when initiating a wx.Frame)
From my code:
class MyApp(wx.App):
def __init__ (self, parent=None, size=(500,700)):
wx.App.__init__(self, False)
self.frame = MyFrame(parent, -1, passBack=self) #Pass this app in
self.outputFromFrame = "" #The output from my frame
def getOutput(self):
self.frame.Show()
self.MainLoop()
return self.outputFromFrame
and for the frame class:
class MyFrame(wx.Frame):
def __init__(self, parent, ID, passBack, title="My Frame"):
wx.Frame.__init__(self, parent, ID, title, size=(500, 700))
self.passBack = passBack #this will be used to pass back variables/objects
and somewhere during the execution of MyFrame
self.passBack.outputFromFrame = "Hello"
so all in all, to get a string from an application
app = MyApp()
val = app.getOutput()
#Proceed to do something with val
Check this answer on comp.lang.python: Linkie
I don't think a wxFrame can return a value since it is not modal. If you don't need to use a wxFrame, then a modal dialog could work for you. If you really need a frame, I'd consider using a custom event.
It would go something like this:
(1) User clicks to close the wxFrame
(2) You override OnClose (or something like that) to pop up a dialog to ask the user a question
(3) Create and post the custom event
(4) Close the wxFrame
(5) Some other code processes your custom event
I think I just had the same problem as you. Instead of making that popup a frame, I made it a dialog instead. I made a custom dialog by inheriting a wx.dialog instead of a wx.frame. Then you can utilize the code that joaquin posted above. You check the return value of the dialog to see what was entered. This can be done by storing the value of the textctrl when the user clicks ok into a local variable. Then before it's destroyed, you get that value somehow.
The custom dialog section of this site helped me out greatly.
http://zetcode.com/wxpython/dialogs/
I have a frame that exists as a start up screen for the user to make a selection before the main program starts. After the user makes a selection I need the screen to stay up as a sort of splash screen until the main program finishes loading in back.
I've done this by creating an application and starting a thread:
class App(wx.App):
'''
Creates the main frame and displays it
Returns true if successful
'''
def OnInit(self):
try:
'''
Initialization
'''
self.newFile = False
self.fileName = ""
self.splashThread = Splash.SplashThread(logging, self)
self.splashThread.start()
#...More to the class
which launches a frame:
class SplashThread(threading.Thread):
def __init__(self, logger, app):
threading.Thread.__init__(self)
self.logger = logger
self.app = app
def run(self):
frame = Frame(self.logger, self.app)
frame.Show()
The app value is needed as it contains the callback which allows the main program to continue when the user makes their selection. The problem is that the startup screen only flashes for a millisecond then goes away, not allowing the user to make a selection and blocking the rest of start up.
Any ideas? Thanks in advance!
You don't need threads for this. The drawback is that the splash window will block while loading but that is an issue only if you want to update it's contents (animate it) or if you want to be able to drag it. An issue that can be solved by periodically calling wx.SafeYield for example.
import time
import wx
class Loader(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
self.btn1 = wx.Button(self, label="Option 1")
self.btn2 = wx.Button(self, label="Option 2")
sizer.Add(self.btn1, flag=wx.EXPAND)
sizer.Add(self.btn2, flag=wx.EXPAND)
self.btn1.Bind(wx.EVT_BUTTON, self.OnOption1)
self.btn2.Bind(
wx.EVT_BUTTON, lambda e: wx.MessageBox("There is no option 2")
)
def OnOption1(self, event):
self.btn1.Hide()
self.btn2.Hide()
self.Sizer.Add(
wx.StaticText(self, label="Loading Option 1..."),
1, wx.ALL | wx.EXPAND, 15
)
self.Layout()
self.Update()
AppFrame(self).Show()
class AppFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
time.sleep(3)
parent.Hide()
# the top window (Loader) is hidden so the app needs to be told to exit
# when this window is closed
self.Bind(wx.EVT_CLOSE, lambda e: wx.GetApp().ExitMainLoop())
app = wx.PySimpleApp()
app.TopWindow = Loader()
app.TopWindow.Show()
app.MainLoop()
In my wxPython application I've created a wx.ScrolledPanel, in which there is a big wx.StaticBitmap that needs to be scrolled.
The scroll bars do appear and I can scroll with them, but I'd also like to be able to scroll with the mouse wheel and the arrow keys on the keyboard. It would be nice if the "Home", "Page Up", and those other keys would also function as expected.
How do I do this?
UPDATE:
I see the problem. The ScrolledPanel is able to scroll, but only when it is under focus. Problem is, how do I get to be under focus? Even clicking on it doesn't do it. Only if I put a text control inside of it I can focus on it and thus scroll with the wheel. But I don't want to have a text control in it. So how do I make it focus?
UPDATE 2:
Here is a code sample that shows this phenomena. Uncomment to see how a text control makes the mouse wheel work.
import wx, wx.lib.scrolledpanel
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
scrolled_panel = \
wx.lib.scrolledpanel.ScrolledPanel(parent=self, id=-1)
scrolled_panel.SetupScrolling()
text = "Ooga booga\n" * 50
static_text=wx.StaticText(scrolled_panel, -1, text)
sizer=wx.BoxSizer(wx.VERTICAL)
sizer.Add(static_text, wx.EXPAND, 0)
# Uncomment the following 2 lines to see how adding
# a text control to the scrolled panel makes the
# mouse wheel work.
#
#text_control=wx.TextCtrl(scrolled_panel, -1)
#sizer.Add(text_control, wx.EXPAND, 0)
scrolled_panel.SetSizer(sizer)
self.Show()
if __name__=="__main__":
app = wx.PySimpleApp()
my_frame=MyFrame(None, -1)
#import cProfile; cProfile.run("app.MainLoop()")
app.MainLoop()
Problem is on window Frame gets the focus and child panel is not getting the Focus (on ubuntu linux it is working fine). Workaround can be as simple as to redirect Frame focus event to set focus to panel e.g.
import wx, wx.lib.scrolledpanel
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = scrolled_panel = \
wx.lib.scrolledpanel.ScrolledPanel(parent=self, id=-1)
scrolled_panel.SetupScrolling()
text = "Ooga booga\n" * 50
static_text=wx.StaticText(scrolled_panel, -1, text)
sizer=wx.BoxSizer(wx.VERTICAL)
sizer.Add(static_text, wx.EXPAND, 0)
scrolled_panel.SetSizer(sizer)
self.Show()
self.panel.SetFocus()
scrolled_panel.Bind(wx.EVT_SET_FOCUS, self.onFocus)
def onFocus(self, event):
self.panel.SetFocus()
if __name__=="__main__":
app = wx.PySimpleApp()
my_frame=MyFrame(None, -1)
app.MainLoop()
or onmouse move over panel, set focus to it, and all keys + mousewheeel will start working e.g.
import wx, wx.lib.scrolledpanel
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = scrolled_panel = \
wx.lib.scrolledpanel.ScrolledPanel(parent=self, id=-1)
scrolled_panel.SetupScrolling()
scrolled_panel.Bind(wx.EVT_MOTION, self.onMouseMove)
text = "Ooga booga\n" * 50
static_text=wx.StaticText(scrolled_panel, -1, text)
sizer=wx.BoxSizer(wx.VERTICAL)
sizer.Add(static_text, wx.EXPAND, 0)
scrolled_panel.SetSizer(sizer)
self.Show()
def onMouseMove(self, event):
self.panel.SetFocus()
if __name__=="__main__":
app = wx.PySimpleApp()
my_frame=MyFrame(None, -1)
app.MainLoop()
Here's an example that should do what you want, I hope. (Edit: In retrospect, this doesnt' quite work, for example, when there are two scrolled panels... I'll leave it up here though so peole can downvote it or whatever.) Basically I put everything in a panel inside the frame (generally a good idea), and then set the focus to this main panel.
import wx
import wx, wx.lib.scrolledpanel
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
main_panel = wx.Panel(self, -1)
main_panel.SetBackgroundColour((150, 100, 100))
self.main_panel = main_panel
scrolled_panel = \
wx.lib.scrolledpanel.ScrolledPanel(parent=main_panel, id=-1)
scrolled_panel.SetupScrolling()
self.scrolled_panel = scrolled_panel
cpanel = wx.Panel(main_panel, -1)
cpanel.SetBackgroundColour((100, 150, 100))
b = wx.Button(cpanel, -1, size=(40,40))
self.Bind(wx.EVT_BUTTON, self.OnClick, b)
self.b = b
text = "Ooga booga\n" * 50
static_text=wx.StaticText(scrolled_panel, -1, text)
main_sizer=wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(scrolled_panel, 1, wx.EXPAND)
main_sizer.Add(cpanel, 1, wx.EXPAND)
main_panel.SetSizer(main_sizer)
text_sizer=wx.BoxSizer(wx.VERTICAL)
text_sizer.Add(static_text, 1, wx.EXPAND)
scrolled_panel.SetSizer(text_sizer)
self.main_panel.SetFocus()
self.Show()
def OnClick(self, evt):
print "click"
if __name__=="__main__":
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1)
frame.Show(True)
self.SetTopWindow(frame)
return True
app = MyApp(0)
app.MainLoop()
For keyboard control, like setting action from the home key, I think you'll need to bind to those events, and respond appropriately, such as using mypanel.Scroll(0,0) for the home key (and remember to call evt.Skip() for the keyboard events you don't act on). (Edit: I don't think there are any default key bindings for scrolling. I'm not sure I'd want any either, for example, what should happen if there's a scrolled panel within a scrolled panel?)