Inserting an image below sliders in wxPython - python

I want to have an image below a slider in a wxpython GUI. The text asks "What is the value?" and I want to have a picture of a value (such as 35) below the slider, and have different images that change as you navigate through.
I have researched this issue, but only found ways to make an image the entire background, rather then appear in the panel.
import wx
class MyPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
self.SetBackgroundColour("white")
text1 = wx.StaticText(self, -1, "What is the value", (10,10))
self.slider1 = wx.Slider(self, -1, 50, 0, 100, (10, 40), (200, 50),
wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
self.Bind(wx.EVT_SLIDER, self.sliderUpdate)
def sliderUpdate(self, event):
self.pos1 = self.slider1.GetValue()
if self.pos1 == 35:
box = wx.MessageDialog(None, "BINGO!", "Title", wx.OK)
box.ShowModal()
app = wx.App()
frame = wx.Frame(None, -1, "Title", size = (400, 310))
MyPanel(frame,-1)
frame.Show(True)
app.MainLoop()
Additionally, I am unsure how to create multiple pages to switch the pictures at the bottom and have a submit button that checks if it is correct before moving on.
Any literature or videos that you can point me to to better learn wxpython would be appreciated as well.

Just add the image to the panel in the required position or start using sizers.
I've added some quick PIL code to generate an image of a number or text, so that you can generate your image on the fly if you need to, although I have left it as a single global instance. You may want to make it a function.
import wx
from PIL import Image, ImageDraw
temp_img=[]
for i in range(101):
img = Image.new('RGB', (100,30))
d = ImageDraw.Draw(img)
d.text((10,10), str(i))
width, height = img.size
temp_img.append(wx.Bitmap.FromBuffer(width, height, img.tobytes()))
class MyPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
self.SetBackgroundColour("white")
text1 = wx.StaticText(self, -1, "What is the value", (10,10))
self.slider1 = wx.Slider(self, -1, 50, 0, 100, (10, 40), (200, 50),
wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS)
self.bmp = wx.StaticBitmap(self, -1, bitmap=temp_img[50], pos=(10,100))
self.Bind(wx.EVT_SLIDER, self.sliderUpdate)
def sliderUpdate(self, event):
self.pos1 = self.slider1.GetValue()
self.bmp.SetBitmap(temp_img[self.pos1])
if self.pos1 == 35:
box = wx.MessageDialog(None, "BINGO 35!", "Title", wx.OK)
box.ShowModal()
app = wx.App()
frame = wx.Frame(None, -1, "Title", size = (400, 310))
MyPanel(frame,-1)
frame.Show(True)
app.MainLoop()
Edited to show multiple images based on the slider value.

Related

wxpython: Set application color (Default Properties)

I want to change the color for my whole pythonwx application. I found out that the currently used colors are noted down in wx.Frame.DefaultAttributes.colBg respectively.colFg. I checked with paint that these are really the used colors.
Now there is a wx.Frame.GetDefaultAttributes() but not wx.Frame.SetDefaultAttributes() method. But I still need to change the color and I do not think that setting every control manually is a desired solution.
I tried:
frame.DefaultProperties = customProperties
and
frame.DefaultProperties.colBg = customColor
but both throw a AttributeError ("can't set attribute"). Any help is appreciated.
The default properties are probably defined within whatever theme you have set for the desktop. I do not believe that there is a way to redefine these from within wxpython.
The easiest way that I have found to set a default colour scheme, is to set the colours for each of the children in an object, such as a panel.
In the following code, keep pressing the Encrypt button to see the results.
import wx
from random import randrange
class CipherTexter(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(1000, 600))
self.panel = wx.Panel(self)
cipherText = wx.StaticText(self.panel, label="Cipher Texter ", pos=(20, 30))
encryptorText = wx.StaticText(self.panel, label="Encryptor ", pos=(20, 70))
decryptorText = wx.StaticText(self.panel, label="Decryptor ", pos=(20, 100))
self.cipher = wx.TextCtrl(self.panel, -1, style=wx.TE_MULTILINE, size=(400,400), pos=(400, 30))
self.encryptor = wx.TextCtrl(self.panel, -1, size=(100,30), pos=(200, 70))
self.decryptor = wx.TextCtrl(self.panel, -1, size=(100,30), pos=(200, 100))
self.encrypt = wx.Button(self.panel, -1, "Encrypt", pos=(20, 140))
self.decrypt = wx.Button(self.panel, -1, "Decrypt", pos=(20, 180))
self.panel.SetBackgroundColour('white')
self.encrypt.Bind(wx.EVT_BUTTON, self.encryptNow)
self.decrypt.Bind(wx.EVT_BUTTON, self.decryptNow)
self.Show()
def AColour(self):
red = randrange(0,255)
green = randrange(0,255)
blue = randrange(0,255)
x = wx.Colour(red,green,blue)
return x
def encryptNow(self, event):
cfg_colour = self.AColour()
txt_colour = self.AColour()
children = self.panel.GetChildren()
for child in children:
child.SetBackgroundColour(cfg_colour)
child.SetForegroundColour(txt_colour)
print(cfg_colour)
def decryptNow(self, event):
pass
app = wx.App(False)
frame = CipherTexter(None, "The SS Cipher")
app.MainLoop()

How to make an Chat box with wx.Python

I am new coding guis, and I want to make a chat box where the user could chat with an IA that answer questions and FAQS
This is for a personal work where you have an IA that you can chat and interact with him, I searched tutorials on StackOverflow but are to have a chat online and it was more complex
app = wx.App(False)
frame = wx.Frame(None, -1, 'Chat', size= (450, 550))
frame.Show(True)
mati = wx.StaticBitmap(frame, -1, wx.Bitmap('chat01.png', wx.BITMAP_TYPE_ANY), pos = wx.Point(0, 0), size = (450, 550))
wx.TextCtrl(mati, pos = (0, 455), size = (450, 50))
sizer = wx.BoxSizer(wx.VERTICAL)
I expect a functional chat where the user can write questions and talk to the IA
As Michael wrote in the commments, please take a look at How to ask first.
After that take a look at wxPython Tutorial! There you will find some information about Widgets you need. To start with you should use wx.TextCtrl or wx.StaticText for inputs and prints in your GUI.
wx.TextCtrl(parent, id, value, pos, size, style)
and
Wx.StaticText(parent, id, label, position, size, style)
Also this code sample should give you a good starting point:
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(200,100))
self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
self.Show(True)
app = wx.App(False)
frame = MyFrame(None, 'Example')
app.MainLoop()

Slow GUI update of a wx (Python) widget?

Consider this example (tried on python2.7, Ubuntu 11.04):
import wx
import wx.lib.agw.knobctrl as KC
# started from: http://wxpython.org/Phoenix/docs/html/lib.agw.knobctrl.html
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "KnobCtrl Demo")
self.panel = wx.Panel(self)
self.knob1 = KC.KnobCtrl(self, -1, size=(100, 100))
self.knob1.SetTags(range(0, 151, 10))
self.knob1.SetAngularRange(-45, 225)
self.knob1.SetValue(45)
# explicit sizes here - cannot figure out the expands ATM
self.text_ctrl_1 = wx.TextCtrl(self, -1, "0", size=(50, -1))
self.slider_1 = wx.Slider(self, -1, 0, -12, 12, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_INVERSE, size=(150, -1))
self.text_ctrl_2 = wx.TextCtrl(self, -1, "0", size=(50, -1))
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.knob1, 0, wx.EXPAND | wx.ALL, 20)
main_sizer.Add(self.text_ctrl_1, 0, wx.EXPAND, 20)
main_sizer.Add(self.slider_1, 0, wx.EXPAND , 20)
main_sizer.Add(self.text_ctrl_2, 0, wx.EXPAND, 20)
self.panel.SetSizer(main_sizer)
main_sizer.Layout()
self.knob1.Bind(KC.EVT_KC_ANGLE_CHANGED, self.OnAngleChanged)
self.slider_1.Bind(wx.EVT_SCROLL, self.OnSliderScroll)
def OnAngleChanged(self, e):
theknob = e.EventObject
x = theknob._mousePosition.x
y = theknob._mousePosition.y
ang = theknob.GetAngleFromCoord(x, y)
self.text_ctrl_1.SetValue("%.2f" % (ang))
self.text_ctrl_1.Refresh() # no dice
def OnSliderScroll(self, e):
obj = e.GetEventObject()
val = obj.GetValue()
self.text_ctrl_2.SetValue(str(val))
# our normal wxApp-derived class, as usual
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
It results with something like this:
The thing is: if you move the slider very fast, you will notice the bottommost text box updates also rather fast; but if you move the rotary knob very fast, it seems its text box (below it) changes with much reduced frequency ?!
Why is this; and would it be possible to get the response speed of the rotary knob's text box to be as fast as slider's one?
Ok, I think I got something working, but I'm not 100% sure, so a more erudite answer would be appreciated. First, note that:
The wx.Slider widget is (I think) implemented in C; so the only time Python "knows" anything about its execution is when the widget broadcasts an event
The wx.lib.agw.knobctrl.KnobCtrl is implemented in Python; thus the Python interpreter "knows" (as it has to run it) each line of code of the widget's execution.
So, what I did, is I tried to trace the execution, with:
python -m trace --trace --timing test.py > test.pylog
What I could notice is that: OnSliderScroll appeared in the log apparently without being triggered by a mouse event, while multiple OnMouseEvents would appear from knobctrl.py (the mouseovers), and only some would trigger SetTrackPosition() which eventually calls OnAngleChanged(). But even more importantly, there was a ton of _gdi_.DC_DrawLine in the log! Then, looking at the knobctrl.py source, I realised that the gradient is actually painted in a Python for loop, line-by-line:
def DrawDiagonalGradient(self, dc, size):
...
for ii in xrange(0, maxsize, 2):
currCol = (r1 + rf, g1 + gf, b1 + bf)
dc.SetPen(wx.Pen(currCol, 2))
dc.DrawLine(0, ii+2, ii+2, 0)
...
... so I thought, this must be hogging the time! So, what is done in the code below, is that a subclass is derived from KnobCtrl, where DrawDiagonalGradient() so it uses a plain fill instead of a gradient, which works much faster.
So, the code below compares the original and the derived variant, using the same event handler and the same textfield; you can check out the video at https://vid.me/kM8V, which looks something like this:
You'll notice the textctrl barely changes when the original knob is turned (even if, notably, the printouts are emitted with the expected speed) ; but updates pretty decently when the derived knob with "plain" background is turned (nearly as fast as the slider). I think the "plain" goes even faster when there is no draw of any kind in the overloaded method, but then the previous positions of the knob dot are not erased. My guess is, the draws of the original knob's gradient take up so much time in the allocated drawing timeframe, that Python needs to drop other queued updates for that frame, here notably the update of the text control.
Note that the knob emits both KC.EVT_KC_ANGLE_CHANGING (which will not refresh the draw unless e.Skip() is present in the handler), and KC.EVT_KC_ANGLE_CHANGED; however, as far as I can see, they always follow each other, so below *CHANGED is used for both.
Of course, if I've misunderstood the problem and the solution, I'd love to know...
import wx
import wx.lib.agw.knobctrl as KC
# started from: http://wxpython.org/Phoenix/docs/html/lib.agw.knobctrl.html
class KnobCtrlPlain(KC.KnobCtrl):
def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
size=wx.DefaultSize,
agwStyle=KC.KC_BUFFERED_DC):
super(KnobCtrlPlain, self).__init__(parent, id, pos, size, agwStyle)
def DrawDiagonalGradient(self, dc, size):
col1 = self._startcolour
r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
sizex, sizey = size
# must have a filled draw here, to erase previous draws:
dc.SetPen(wx.TRANSPARENT_PEN)
dc.SetBrush(wx.Brush(col1, wx.SOLID))
#~ dc.DrawCircle(self.Width/2, self.Height/2, sizex)
dc.DrawRectangle(0, 0, sizex, sizey) # same effect as circle; prob. faster?
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "KnobCtrl DemoB")
self.panel = wx.Panel(self)
self.knob1 = KC.KnobCtrl(self.panel, -1, size=(100, 100))
self.knob1.SetTags(range(0, 151, 10))
self.knob1.SetAngularRange(-45, 225)
self.knob1.SetValue(45)
self.knob2 = KnobCtrlPlain(self.panel, -1, size=(100, 100))
self.knob2.SetTags(range(0, 151, 10))
self.knob2.SetAngularRange(-45, 225)
self.knob2.SetValue(45)
self.text_ctrl_1 = wx.TextCtrl(self.panel, -1, "0", size=(50, -1))
self.slider_1 = wx.Slider(self.panel, -1, 0, -12, 12, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_INVERSE, size=(150, -1))
self.text_ctrl_2 = wx.TextCtrl(self.panel, -1, "0", size=(50, -1))
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.knob1, 0, wx.EXPAND | wx.ALL, 20)
main_sizer.Add(self.text_ctrl_1, 0, wx.EXPAND, 20)
main_sizer.Add(self.knob2, 0, wx.EXPAND | wx.ALL, 20)
main_sizer.Add(self.slider_1, 0, wx.EXPAND , 20)
main_sizer.Add(self.text_ctrl_2, 0, wx.EXPAND, 20)
self.panel.SetSizer(main_sizer)
main_sizer.Layout()
self.knob1.Bind(KC.EVT_KC_ANGLE_CHANGED, self.OnAngleChanged)
self.knob2.Bind(KC.EVT_KC_ANGLE_CHANGED, self.OnAngleChanged)
self.slider_1.Bind(wx.EVT_SCROLL, self.OnSliderScroll)
def OnAngleChanged(self, e):
theknob = e.EventObject
x = theknob._mousePosition.x
y = theknob._mousePosition.y
ang = theknob.GetAngleFromCoord(x, y)
strval = str("%.2f" % (ang))
print("ac: " + strval)
self.text_ctrl_1.SetValue(strval)
def OnSliderScroll(self, e):
obj = e.GetEventObject()
val = obj.GetValue()
strval = str(val)
print("ss: " + strval)
self.text_ctrl_2.SetValue(strval)
# our normal wxApp-derived class, as usual
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()

wxPython Background image on frame

MMGP Answerd but wont let me credit him right ;-) So I will at least mention him here.
(And I did finally get to credit him... 8-)
His linked discussion on Double Buffering provided a base code that worked with the following modifications:
Insert this beginning at line 106 (overwritting existing code until you get to the last line shown here):
# Here's the actual drawing code.
cliWidth, cliHeight = self.GetClientSize()
bmp=wx.Bitmap("Logo16x9.png")
bmpWide = bmp.GetWidth()
bmpHeight = bmp.GetHeight()
img = bmp.ConvertToImage()
scaleFactor = cliWidth/bmpWide
bmp = wx.BitmapFromImage(img.Scale(int(bmpWide * scaleFactor), int(bmpHeight * scaleFactor)))
bmpWide = bmp.GetWidth()
bmpHeight = bmp.GetHeight()
xPos = (cliWidth - (bmpWide))/2
yPos = (cliHeight - (bmpHeight))/2
# altered by me
dc.DrawBitmap(bmp, xPos, yPos)
class TestFrame(wx.Frame):
I've been beating my head against this all day.
I'm new to drawing graphics with the wxPython modules, and when I needed to draw a background image on a frame I found this code which works well if the image is the full size of the window.
However, I need to place a company logo as the background, and have it remain centered through resizes. In it's current form the resize causes a graphic artifact the size of a small nation to appear on the screen with any resize event.
The logo image file (used on line 43 of the code) is a 400x300 (WxH) image.
I am looking for a way to either: resize my image on the fly to match wx.GetClientSize(),
or a way to avoid/remove the artifact. Preferably without involving PIL or ImageMagick. App has to function on a local level only, and be system agnostic (Win, Lin and Mac), none of this involves network activities or mapped drives.
Python 2.7 and wxPython 2.8
The code I am using (with my modification annotated) is as follows:
import wx
########################################################################
class MainPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.frame = parent
sizer = wx.BoxSizer(wx.VERTICAL)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
for num in range(4):
label = "Button %s" % num
btn = wx.Button(self, label=label)
sizer.Add(btn, 0, wx.ALL, 5)
hSizer.Add((1,1), 1, wx.EXPAND)
hSizer.Add(sizer, 0, wx.TOP, 100)
hSizer.Add((1,1), 0, wx.ALL, 75)
self.SetSizer(hSizer)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
#----------------------------------------------------------------------
def OnEraseBackground(self, evt):
"""
Add a picture to the background
"""
# yanked from ColourDB.py
dc = evt.GetDC()
# Added by me
cliWidth, cliHeight = self.GetClientSize()
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
# added by me
xPos = (cliWidth - 400)/2
yPos = (cliHeight - 300)/2
# altered by me
dc.DrawBitmap(bmp, xPos, yPos)
#dc.DrawBitmap(bmp, 0, 0)
########################################################################
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, size=(600,450))
panel = MainPanel(self)
self.Center()
########################################################################
class Main(wx.App):
""""""
#----------------------------------------------------------------------
def __init__(self, redirect=False, filename=None):
"""Constructor"""
wx.App.__init__(self, redirect, filename)
dlg = MainFrame()
dlg.Show()
#----------------------------------------------------------------------
if __name__ == "__main__":
app = Main()
app.MainLoop()
Update: Latest Failure - Modified lines 37 to 52
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
img = bmp.ConvertToImage()
scaleFactor = cliWidth/400
bmp = wx.BitmapFromImage(img.Scale(int(400*scaleFactor),int(300*scaleFactor)))
# added by me
#xPos = (cliWidth - 400)/2
#yPos = (cliHeight - 300)/2
# altered by me
#dc.DrawBitmap(bmp, xPos, yPos)
dc.DrawBitmap(bmp, 0, 0)
Another attempt and another fail. No difference in the output to screen. Additionally, the referenced document on double buffering does not address this issue, but does suffer from the same result. This code modifies lines 36 through 57 of the original.
brsh = wx.Brush('#000000')
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
dc.SetBackground(brsh)
dc.SetDeviceOrigin(0,0)
dc.DestroyClippingRegion()
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
img = bmp.ConvertToImage()
scaleFactor = cliWidth/400
bmp = wx.BitmapFromImage(img.Scale(int(400*scaleFactor),int(300*scaleFactor)))
# added by me
#xPos = (cliWidth - 400)/2
#yPos = (cliHeight - 300)/2
# altered by me
#dc.DrawBitmap(bmp, xPos, yPos)
dc.DrawBitmap(bmp, 0, 0)
From the comments I suggested using double buffered drawing, but I didn't see that in the edited post. Also, I had several drawing issues when self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) was used. But this line might be helpful in other systems beyond mine, so I wanted to keep it. So, in order to handle the situation, here is a updated code that uses double buffered drawing and works fine here:
import wx
class MainPanel(wx.Panel):
def __init__(self, parent, bg_img='Logo4x3.png'):
wx.Panel.__init__(self, parent=parent)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.bg = wx.Bitmap(bg_img)
self._width, self._height = self.bg.GetSize()
sizer = wx.BoxSizer(wx.VERTICAL)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
for num in range(4):
btn = wx.Button(self, label="Button %s" % num)
sizer.Add(btn, 0, wx.ALL, 5)
hSizer.Add((1,1), 1, wx.EXPAND)
hSizer.Add(sizer, 0, wx.TOP, 100)
hSizer.Add((1,1), 0, wx.ALL, 75)
self.SetSizer(hSizer)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
def OnSize(self, size):
self.Layout()
self.Refresh()
def OnEraseBackground(self, evt):
pass
def OnPaint(self, evt):
dc = wx.BufferedPaintDC(self)
self.Draw(dc)
def Draw(self, dc):
cliWidth, cliHeight = self.GetClientSize()
if not cliWidth or not cliHeight:
return
dc.Clear()
xPos = (cliWidth - self._width)/2
yPos = (cliHeight - self._height)/2
dc.DrawBitmap(self.bg, xPos, yPos)
app = wx.App()
frame = wx.Frame(None, size=(400,300))
panel = MainPanel(frame)
frame.Show()
app.MainLoop()
The method OnEraseBackground is intentionally empty.

Using a loop to generate unique bitmap buttons with separate events when clicked

I'm pretty new to Python, so I'll hope you forgive me for such amateurish code. I've tried pouring over examples that do similar things but I'm having trouble figuring out what they're doing that is different. In examples I've seen each button generated with the loop had a different action, for mine only the last button in the loop is affected by the click, no matter which button I press. Here's the code:
import wx
import mmap
class pt:
Note = open('note.txt', "r+")
buf = mmap.mmap(Note.fileno(), 0)
TL = 0
readline = buf.readline
while readline():
TL += 1
class MainWindow(wx.Frame):
def __init__(self, parent, title):
w, h = wx.GetDisplaySize()
x = w * 0
y = h - bdepth
wx.Frame.__init__(self, parent, title = title, pos = (x, y), size = (200,bdepth), style = wx.STAY_ON_TOP)
self.__DoLayout()
self.Bind(wx.EVT_BUTTON, self.OnClick)
self.Show(True)
def __DoLayout(self):
self.__DoButtons(wx.Panel(self, size=(200,bdepth), pos=(0,0), name='panel'), 'Cheese')
def __DoButtons(self, panel, label):
for i, line in enumerate(pt.Note):
solid = wx.EmptyBitmap(200,50,-1)
dc = wx.MemoryDC()
dc.SelectObject(solid)
solidbrush = wx.Brush(wx.Colour(75,75,75),wx.SOLID)
solidpen = wx.Pen(wx.Colour(75,75,75),wx.SOLID)
dc.SetBrush(solidbrush)
dc.SetPen(solidpen)
dc.DrawRectangle(0, 0, 200, 50)
dc.SetTextForeground(wx.Colour(255, 255, 255))
dc.DrawText(line.rstrip(), 30, 17)
dc.SelectObject(wx.NullBitmap)
self.checked = wx.Image('buttonchecked.png', wx.BITMAP_TYPE_PNG).ConvertToBitmap()
dc = wx.MemoryDC()
dc.SelectObject(self.checked)
dc.SetTextForeground(wx.Colour(200, 255, 0))
dc.DrawText(line.rstrip(), 30, 17)
dc.SelectObject(wx.NullBitmap)
self.b = wx.BitmapButton(panel, i + 800, solid, (0, i * 50), (solid.GetWidth(), solid.GetHeight()), style = wx.NO_BORDER, name=line.rstrip())
def OnClick(self, event):
self.b.SetBitmapDisabled(self.checked)
self.b.Enable(False)
print('cheese')
bdepth = pt.TL * 50
app = wx.App(False)
frame = MainWindow(None, "Sample editor")
app.MainLoop()enter code here
Only the last button is working because each time you go through the __DoButtons loop you reassign self.b to a different button. So after the loop has finished self.b is only assigned to the last button. You can get the button pressed using the event.GetEventObject() method.
Change your OnClick method to:
def OnClick(self, event):
button = event.GetEventObject()
button.SetBitmapDisabled(self.checked)
button.Enable(False)
print('cheese')

Categories

Resources