I am trying to add a feature to a calculator i have made with wxpython, i want there to be a button , that when clicked changes the background colour (the panel). To show you my code i have made a smaller program, that should only change colour, and even in this one i get the same outcome:
the background colour doesn't change, nothing happens when i click the button, and i dont even receive any errormessahe.Actually, the calculator does change colour, but not in the way i want it to, it only changes the colour of the text (a wx.StaticText), and it's not really meant to do that.
Anyway, here is the code :
import wx
class calc(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Calculator",size=(400,400))
global panel
panel=wx.Panel(self)
a=wx.Button(panel,label="GO",pos=(100,100),size=(50,50))
self.Bind(wx.EVT_BUTTON, self.change, a)
def change(self,event):
panel.SetBackgroundColour("red")
if __name__=="__main__":
app=wx.App(False)
frame=calc(parent=None,id=-1)
frame.Show()
app.MainLoop()
when i run this, the frame with the button show up, and when i click on the button, nothing happens!! Does anybody know what is wrong with this?
Thanks in advice!!!
While your code worked for me on Xubuntu 14.04, wxPython 2.8.12 and Python 2.7, I went ahead and rewrote it slightly to remove the global and clean it up a bit:
import wx
class calc(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Calculator", size=(400,400))
self.panel = wx.Panel(self)
a = wx.Button(self.panel, label="GO", pos=(100,100), size=(50,50))
self.Bind(wx.EVT_BUTTON, self.change, a)
def change(self,event):
self.panel.SetBackgroundColour("red")
self.Refresh() # for windows
if __name__=="__main__":
app = wx.App(False)
frame = calc()
frame.Show()
app.MainLoop()
This also works for me.
Related
So, I'm trying to write a program using wxPython which will have a notebook with tabs that each have the user enter some data into textboxes. This is for a physics related project so I want each textbox to have a "units" label after it displaying what units it should be entered in. The problem is: When the program runs, I get a black rectangle in the upper left corner of each textctrl which is the size of the label that the units are in. The black box disappears forever immediately after any of the following:
press tab onto the textctrl
move the cursor onto the textctrl
switch tabs in the notebook
resize the window until the textctrl has to shrink with it.
functionally everything works fine, I just want to get rid of the black rectangles on startup.
This is my code:
#! usr/bin/python
import wx
class MainWindow(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None, title=title, size=(400,300))
self.make_gui()
self.Show()
def make_gui(self):
self.panel=wx.Panel(self,wx.ID_ANY)
sizer=wx.BoxSizer(wx.VERTICAL)
ins=self.gui_inputs()
sizer.Add(ins)
self.panel.SetSizer(sizer)
def gui_inputs(self):
sizer=wx.BoxSizer(wx.HORIZONTAL)
simpleinputs=(("Page 1",(("Name",None),("Item","in"))),("sec page",tuple()))
simple=self.gui_inputs_make_simple(simpleinputs)
sizer.Add(simple)
return sizer
def gui_inputs_make_simple(self,simpleinputs):
sizer=wx.BoxSizer(wx.VERTICAL)
notebook=wx.Notebook(self.panel)
for tab in simpleinputs:
pan=wx.Panel(notebook,wx.ID_ANY)
siz=wx.BoxSizer(wx.VERTICAL)
for item in tab[1]:
it=self.gui_inputs_make_labeled_unitinput(pan,item[0],item[1])
siz.Add(it)
pan.SetSizer(siz)
notebook.AddPage(pan,tab[0])
sizer.Add(notebook)
return sizer
def gui_inputs_make_labeled_unitinput(self,par,label='',units='',validatenumber=False):
sizer=wx.BoxSizer(wx.HORIZONTAL)
lbl=wx.StaticText(par,label=label+':')
sizer.Add(lbl)
edit=wx.TextCtrl(par)
sizer.Add(edit)
if units!=None:
unit=wx.StaticText(par,label=units)
sizer.Add(unit)
return sizer
app = wx.App(False)
frame = MainWindow("GUI")
app.MainLoop()
and this is a screenshot of what I get:
The following are ways I was able to get the black rectangles to disappear (but none let me do what I need to do):
When I remove the code to put the units in, it works. When I remove the text from the units fields, it works. When I have only one tab, it works.
If anyone can tell me why this is happening, I would be greatly appreciative.
Thanks in advance!
This was an interesting one:
The black boxes in the TextCtrl instances disappear as soon the sizer cascades are set up properly. You can do this by updating the layout of your main sizer by:
sizer.Layout()
or
sizer.Fit(self)
at the end of your make_gui method.
This works for me but does of course not explain why the TextCtrl stays black in the first place without.
I have a simple wxPython application. It basically has a image and a text-entry field (a wx.TextCtrl).
I want to be able to immediately be able to start entering text as soon as the window opens. Right now, I have to first click in the text control, and then I can start entering text.
Here is a minimal app that demonstrates the issue:
import wx
class MyFrame(wx.Frame):
""" We simply derive a new class of Frame. """
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(200, 100))
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
mainSizer.Add(self.control, 1, wx.EXPAND)
self.SetSizer(mainSizer)
self.Show(True)
app = wx.App(False)
frame = MyFrame(None, 'Small editor')
app.MainLoop()
I've poked around with wx.SetInsertionPoint, but that does not seem to have any effect.
Ah, derp. I had to look further up the inheritance chain.
You can simply call SetFocus() on the control (in this case, self.control.SetFocus()).
SetFocus() is a member function of wxWindow. I was only looking at the docs for wxTextCtrl.
Of course, I didn't think to look up the inheritance chain until I had already asked the question.
I'm leaving this here, as this is a pretty hard to google issue. Hopefully this will help someone else.
So I'm working on a rhythm trainer, and using wxpython as the UI Toolkit. I was wondering if anyone knew how to bind keyboard presses to play sounds? So to put it simply, users can use the keyboard to play a drum beat. Example "Pressing the A key will play the bass drum"
Now I've come across a tutorial -
http://www.blog.pythonlibrary.org/2009/08/29/wxpython-catching-key-and-char-events/
But this seems like it needs the button to successfully play the sound. I've got a bit of the functionality working using this example. But I was wondering if there's another way to do it without the need of a button?
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Key Press Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
btn = wx.Button(panel, label="OK")
btn.Bind(wx.EVT_KEY_DOWN, self.onKeyPress)
def onKeyPress(self, event):
keycode = event.GetKeyCode()
print keycode
if keycode == ord('A'):
print "you pressed the spacebar!"
sound_file = "notation1.wav"
sound=wx.Sound(sound_file)
print(sound_file)
sound.Play(wx.SOUND_ASYNC)
event.Skip()
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm()
frame.Show()
app.MainLoop()
This is my example using the tutorial.
Cheers!
My tutorial is about catching keystrokes on the widget that's in focus. In the case of the tutorial, that was the button that was in focus and that was why it was bound to EVT_KEY_DOWN. Sadly, panels don't really accept focus very easily, so you'll be better off to set the focus on the panel manually using SetFocus() or bind the key event to most of the widgets.
You might be able to use an AcceleratorTable, but I'm not sure if that will work in your situation. Here's a link to a tutorial on that topic though:
http://www.blog.pythonlibrary.org/2010/12/02/wxpython-keyboard-shortcuts-accelerators/
import wx
class TestDraw(wx.Panel):
def __init__(self,parent=None,id=-1):
wx.Panel.__init__(self,parent,id)
self.SetBackgroundColour("#FFFFFF")
self.Bind(wx.EVT_PAINT,self.onPaint)
def onPaint(self, event):
event.Skip()
dc=wx.PaintDC(self)
dc.BeginDrawing()
width=dc.GetSize()[0]
height=dc.GetSize()[1]
if height<width:
self.drawTestRects(dc)
else:
dc.Clear()
dc.EndDrawing()
def drawTestRects(self,dc):
dc.SetBrush(wx.Brush("#000000",style=wx.SOLID))
dc.DrawRectangle(50,50,50,50)
dc.DrawRectangle(100,100,100,100)
class TestFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(640,480))
self.mainPanel=TestDraw(self,-1)
self.Show(True)
app = wx.App(False)
frame = TestFrame(None,"Test App")
app.MainLoop()
This code should draw the test rectangles only when the height is less than the width, and otherwise the window should remain clear. However, if you mess with resizing the window, the panel isn't actually redrawn unless it is moved off the window. What am I doing wrong?
You can bind a method to handle wx.EVT_SIZE or the panel and invalidate it there. Alternatively simply use the wx.FULL_REPAINT_ON_RESIZE for the panel.
The documentation for a SizeEvent claims that there may be some complications when drawing depends on the dimensions of the window. I do not know exactly what is going on behind the scenes. I followed the suggestion on the link and added the call self.Refresh() to the top of onPaint() and this seems to give the desired behavior. See mghie's answer for a more efficient example of working code.
Why does my code print the lines gray instead of black?
import wx
class MyFrame(wx.Frame):
def __init__(self,*args,**kwargs):
wx.Frame.__init__(self,*args,**kwargs)
self.panel=wx.Panel(self,-1,size=(1000,1000))
self.Bind(wx.EVT_PAINT, self.on_paint)
self.Bind(wx.EVT_SIZE, self.on_size)
self.bitmap=wx.EmptyBitmapRGBA(1000,1000,255,255,255,255)
dc=wx.MemoryDC()
dc.SelectObject(self.bitmap)
dc.SetPen(wx.Pen(wx.NamedColor("black"),10,wx.SOLID))
dc.DrawCircle(0,0,30)
dc.DrawLine(40,40,70,70)
dc.Destroy()
self.Show()
def on_size(self,e=None):
self.Refresh()
def on_paint(self,e=None):
dc=wx.PaintDC(self.panel)
dc.DrawBitmap(self.bitmap,0,0)
dc.Destroy()
if __name__=="__main__":
app=wx.PySimpleApp()
my_frame=MyFrame(parent=None,id=-1)
app.MainLoop()
Beside the frame/panel paint problem already pointed out the color problem is due to the alpha channel of the 32 bit bitmap.
I remember having read to use wx.GCDC instead of wx.DC.
Ok I tested with newer version of wx(2.8.9.2)
and Now I wonder why it is even working on your side.
you are trying to paint Panel but overriding the paint event of Frame
instead do this
self.panel.Bind(wx.EVT_PAINT, self.on_paint)
and all will be fine