I am writing a program to play a video on the right panel when a button pressed on a left panel after selecting what to play. This acts as a test function to show the user. I am a beginner in using Python and WXPython. Learning on the go.
I have added a snippet of the code that I am stuck on below:
import wx, wx.media
filePathList = ["None", "None", "None", "None", "None"]
class FrameClass (wx.Frame):
def __init__(self, parent):
super(FrameClass, self).__init__(None, title = "Super Bot", size = (750, 400))
vsplitter = wx.SplitterWindow(self)
left = LeftPanel(vsplitter, self)
self.right = RightPanel(vsplitter, self)
vsplitter.SplitVertically(left, self.right)
vsplitter.SetMinimumPaneSize(200)
self.Show(True)
class LeftPanel (wx.Panel):
def __init__(self, parent, *args, **kwargs):
wx.Panel.__init__(self, parent = parent)
testBtn1 = wx.Button(self, -1, "Test", pos = (5, 20))
self.Bind(wx.EVT_BUTTON, self.buttonPressed1, testBtn1)
def buttonPressed1(self, event):
file0 = filePathList[0]
self.right.onTestClick(file0)
class RightPanel (wx.Panel):
def __init__(self, parent, media):
wx.Panel.__init__(self, parent = parent)
self.mediaFilePath = media
def onTestClick(self):
self.testMedia = wx.media.MediaCtrl(self, size = (500, 300), style=wx.SIMPLE_BORDER, szBackend = wx.media.MEDIABACKEND_WMP10)
self.testMedia.Bind(wx.media.EVT_MEDIA_LOADED, self.play)
self.testMedia.Load(self.mediaFilePath)
def play(self, event):
self.testMedia.Play()
Currently all works well. What apart from passing the video to the rightPanel video onTestClick. Where is shows the current error
Traceback (most recent call last):
File "frame1.py", line 151, in buttonPressed1
self.right.onTestClick(file0)
AttributeError: 'LeftPanel' object has no attribute 'right'
I can imagine that because right is defined in the FrameClass that it is not known about inside of the LeftPanel when trying to use it.
Any help would be appreciated.
If you want a quick fix, you can just call:
self.GetParent().right.onTestClick(file0)
which is kind-of ugly, because the the parent creates children
and children must know about the structure of the parent at
the same time.
Probably the most wxPython-ish solution would be to create your
own event, which would be created and triggered when the button
is pressed. This event would be handled in the FrameClass.
There is a nice intro here:
https://wxpython.org/Phoenix/docs/html/events_overview.html#custom-event-summary
Finally got it working. Thank you for your inputs as well. Most helpful.
I just needed to make the left panel aware of the right panel. In this case...
vsplitter = wx.SplitterWindow(self)
right = RightPanel(vsplitter, self)
left = LeftPanel(vsplitter, right)
vsplitter.SplitVertically(left, right)
vsplitter.SetMinimumPaneSize(200)
self.Show(True)
class LeftPanel (wx.Panel):
def __init__(self, parent, top):
wx.Panel.__init__(self, parent = parent)
self.refTop = top
and when I wanted to send it something, I reference "self.refTop". Such as...
def buttonPressed1(self, event):
file1 = filePathList[0]
self.refTop.onTestClick(file1)
making sure that RightPanel has an argument ready for it.
class RightPanel (wx.Panel):
def __init__(self, parent, media):
self.mediaFilePath = media
Related
I am currently making a UI in python using wx. I am trying to have multiple tabs active at the same time, but at the same time I am trying to keep either a list or int value active and showing in the bottom right corner on any tab at all times. Unfortunately I seem to have run into a road block. When I run the code below I get the error:
i = parent.GetString(Points.a)
TypeError: CommandEvent.GetString(): too many arguments
Honestly I am only a year into coding practice and I don't really know what this error means. If possible, could someone please explain it to me and possible give me some tips on how to solve the issue?
Thanks in advance.
import wx
class Points:
c = 14
a = [14]
b = "{}\n" .format(a)
class MOC(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.poi = wx.StaticText(self, label=Points.b, pos=(400, 400))
select = wx.Button(self, wx.ID_ANY, '+1', size=(90, 30))
select.Bind(wx.EVT_BUTTON, self.add)
def add(self, parent):
i = parent.GetString(Points.a)
Points.a.remove(Points.c)
Points.c += 1
Points.a.append(Points.c)
self.poi.SetLabel(i)
class TOS(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
wx.StaticText(self, label=Points.b, pos=(400, 400))
class UIFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, size = (500,500), title = "Mind")
p = wx.Panel(self)
nb = wx.Notebook(p)
page1 = MOC(nb)
page2 = TOS(nb)
nb.AddPage(page1, "Means")
nb.AddPage(page2, "Types")
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
if __name__ == "__main__":
app = wx.App()
UIFrame().Show()
app.MainLoop()
In the line i = parent.GetString(Points.a) you are passing the argument Points.a but GetString has no arguments because it is used to get the string from an item i.e. self.Item.GetString().
Points.a is not a wx defined item, it is in fact a python list, to access that you should change the offending line above with
i = str(Points.a[0]) or
i = Points.a[0] or
i = Points.a or
i = str(Points.a) depending on your requirements.
Depending on which access method you choose, you may have to alter the
self.poi.SetLabel(i) as well, as i could be a list or an int rather than the required str
Running with the first option works without further changes
I would like to have two (I will add more later) panels that occupy the same space within the frame and for them to be shown/hidden when the respective button is pressed on the toolbar, "mListPanel" should be the default. Currently the settings panel is shown when the application is launched and the buttons don't do anything. I've searched and tried lots of stuff for hours and still can't get it to work. I apologise if it's something simple, I've only started learning python today.
This is what the code looks like now:
import wx
class mListPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
#wx.StaticText(self, -1, label='Search:')#, pos=(10, 3))
#wx.TextCtrl(self, pos=(10, 10), size=(250, 50))
class settingsPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
class bifr(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Title")
self.listPanel = mListPanel(self)
self.optPanel = settingsPanel(self)
menuBar = wx.MenuBar()
fileButton = wx.Menu()
importItem = wx.Menu()
fileButton.AppendMenu(wx.ID_ADD, 'Add M', importItem)
importItem.Append(wx.ID_ANY, 'Import from computer')
importItem.Append(wx.ID_ANY, 'Import from the internet')
exitItem = fileButton.Append(wx.ID_EXIT, 'Exit')
menuBar.Append(fileButton, 'File')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.Quit, exitItem)
toolBar = self.CreateToolBar()
homeToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'Home', wx.Bitmap('icons/home_icon&32.png'))
importLocalToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'Import from computer', wx.Bitmap('icons/comp_icon&32.png'))
importToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'Import from the internet', wx.Bitmap('icons/arrow_bottom_icon&32.png'))
settingsToolButton = toolBar.AddLabelTool(wx.ID_ANY, 'settings', wx.Bitmap('icons/wrench_plus_2_icon&32.png'))
toolBar.Realize()
self.Bind(wx.EVT_TOOL, self.switchPanels(), settingsToolButton)
self.Bind(wx.EVT_TOOL, self.switchPanels(), homeToolButton)
self.Layout()
def switchPanels(self):
if self.optPanel.IsShown():
self.optPanel.Hide()
self.listPanel.Show()
self.SetTitle("Home")
elif self.listPanel.IsShown():
self.listPanel.Hide()
self.optPanel.Show()
self.SetTitle("Settings")
else:
self.SetTitle("Error")
self.Layout()
def Quit(self, e):
self.Close()
if __name__ == "__main__":
app = wx.App(False)
frame = bifr()
frame.Show()
app.MainLoop()
first off, i would highly suggest that you learn about wxpython sizers and get a good understanding of them (they're really not that hard the understand) as soon as possible before delving deeper into wxpython, just a friendly tip :).
as for your example, a few things:
when your'e not using sizers, you have to give size and position for every window or else they just wont show, so you'd have to change your panel classes to something like this (again this is only for demonstration, you should be doing this with wx.sizers, and not position and size):
class mListPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent,pos=(0,100),size=(500,500))
class settingsPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent,pos=(0,200),size (1000,1000))
further more, when binding an event it should look like this:
self.Bind(wx.EVT_TOOL, self.switchPanels, settingsToolButton)
self.Bind(wx.EVT_TOOL, self.switchPanels, homeToolButton)
notice how I've written only the name of the function without the added (), as an event is passed to it, you cant enter your own parameters to a function emitted from an event (unless you do it with the following syntax lambda e:FooEventHandler(paramaters))
and the event handler (function) should look like this:
def switchPanels(self, event):
if self.optPanel.IsShown():
self.optPanel.Hide()
self.listPanel.Show()
self.SetTitle("Home")
elif self.listPanel.IsShown():
self.listPanel.Hide()
self.optPanel.Show()
self.SetTitle("Settings")
else:
self.SetTitle("Error")
self.Layout()
there should always be a second parameter next to self in functions that are bind to event as the event object is passes there, and you can find its associated methods and parameters in the documentation (in this example it is the wx.EVT_TOOL).
I'm trying to make a simple docking frame that will dock to a parent window and follow it around. So far I have the following:
class DockingFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, style=wx.CAPTION)
parent.Bind(wx.EVT_MOVE, self.OnParentMove)
parent.Bind(wx.EVT_ACTIVATE, self.OnParentActivate)
parent.Bind(wx.EVT_SHOW, self.OnParentShow)
def OnParentMove(self, moveEvent):
print "Docked frame parent moved"
pr = positioning.position(
self.Rect,
my='right_top', at='left_top', of=self.Parent.Rect)
self.Move(pr.top_left)
moveEvent.Skip()
def OnParentActivate(self, event):
print "Docked frame parent activated"
self.Raise()
event.Skip()
def OnParentShow(self, event):
print "Docked frame parent showed"
self.Show(event.GetShow())
event.Skip()
class MainFrame(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None, title=title)
self.info_frame = DockingFrame(self)
self.Show(True)
This works in that if I move the parent window, the docked window moves with it, and if I click on the parent window, the docked window raises itself. However, it severely interferes with the parent window's functionality. I can't close or re-size the parent window anymore, and I get tons of "Docked frame parent activated" messages whenever I click the parent. It seems I don't understand some fundamental wxPython concept, here. What is going on and how do I fix it?
I've seen that aui seems to support docking, but documentation has been sparse so I haven't attempted it. If someone could supply a minimal working code sample as to how to make a Frame dock to another Frame with aui, I could also take that approach.
Note that I'm also using pygame and twisted in this app, which may or may not be interfering here...
And, of course, the simple approach is to simply use the wx.FRAME_FLOAT_ON_PARENT style...
class DockingFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, title="Last Hand",
style=wx.CAPTION | wx.FRAME_FLOAT_ON_PARENT)
parent.Bind(wx.EVT_MOVE, self.OnParentMove)
parent.Bind(wx.EVT_SHOW, self.OnParentShow)
def SnapToParent(self):
print "*Snapping to parent"
pr = positioning.position(
self.Rect,
my='right_top', at='left_top', of=self.Parent.Rect)
self.Move(pr.top_left)
def OnParentMove(self, moveEvent):
moveEvent.Skip()
self.SnapToParent()
def OnParentShow(self, event):
event.Skip()
print "Parent %s" % ("Hide", "Show")[event.GetShow()]
self.Show(event.GetShow())
The trick was that EVT_ACTIVATE fires both for activating and for de-activating. The following code worked. If the parent gets activated, then the dock raises itself & immediately raises the parent after.
class DockingFrame(wx.Frame):
def __init__(self, parent):
self.handleParentActiveState = 'noTriggers'
wx.Frame.__init__(self, parent, title="Last Hand", style=wx.CAPTION)
parent.Bind(wx.EVT_MOVE, self.OnParentMove)
parent.Bind(wx.EVT_ACTIVATE, self.OnParentActivate)
self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
parent.Bind(wx.EVT_SHOW, self.OnParentShow)
def OnActivate(self, event):
event.Skip()
if not event.GetActive():
return
if self.handleParentActiveState == 'activateParentNext':
self.handleParentActiveState = 'resetTriggers'
self.Parent.Raise()
def OnParentActivate(self, event):
event.Skip()
if not event.GetActive():
return
if self.handleParentActiveState == 'noTriggers':
self.handleParentActiveState = 'activateParentNext'
self.Raise()
elif self.handleParentActiveState == 'resetTriggers':
self.handleParentActiveState = 'noTriggers'
def OnParentMove(self, moveEvent):
pr = positioning.position(
self.Rect,
my='right_top', at='left_top', of=self.Parent.Rect)
self.Move(pr.top_left)
moveEvent.Skip()
def OnParentShow(self, event):
event.Skip()
self.Show(event.GetShow())
I have been looking around the Internet but I am not sure if there is a way to show 2 classes in wxPython in 2 separate windows. And could we communicate between them (like one class being the dialog and the other the main class)?
I think I did this before using Show() but I am not sure how to repeat this.
So basically I would like to be able to have a dialog but by using a class instead. This would be more powerful than using Modal dialogs.
Thanks
Here you have a simple example of two frames communicating:
The trick is in sending an object reference to share between frames, either creating one inside the other (as in this case) or through a common parent.
The code is:
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, size=(150,100), title='MainFrame')
pan =wx.Panel(self)
self.txt = wx.TextCtrl(pan, -1, pos=(0,0), size=(100,20), style=wx.DEFAULT)
self.but = wx.Button(pan,-1, pos=(10,30), label='Tell child')
self.Bind(wx.EVT_BUTTON, self.onbutton, self.but)
self.child = ChildFrame(self)
self.child.Show()
def onbutton(self, evt):
text = self.txt.GetValue()
self.child.txt.write('Parent says: %s' %text)
class ChildFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, None, size=(150,100), title='ChildFrame')
self.parent = parent
pan = wx.Panel(self)
self.txt = wx.TextCtrl(pan, -1, pos=(0,0), size=(100,20), style=wx.DEFAULT)
self.but = wx.Button(pan,-1, pos=(10,30), label='Tell parent')
self.Bind(wx.EVT_BUTTON, self.onbutton, self.but)
def onbutton(self, evt):
text = self.txt.GetValue()
self.parent.txt.write('Child says: %s' %text)
if __name__ == "__main__":
App=wx.PySimpleApp()
MainFrame().Show()
App.MainLoop()
You can also use pubsub to communicate between two frames. I show one way of doing just that in this article: http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/
If you don't want the first frame to hide itself, just remove the line with the Hide() in it.
After looking at questions like this it doesn't make sense that my __init__(self, parrent, id) would be throwing a unbound error? help?
main.py
import wx
from customButton import customButton
from wxPython.wx import *
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition, wxSize(400, 400))
# Non-important code here...
# This is the first declaration of the Button1
# This is also where the ERROR is thrown.
# Omitting this line causes the window to execute
# flawlessly.
self.Button1 = customButton.__init__(self, parent, -1)
# ... finishes in a basic wx.program style...
customButton.py
# I've included all of the code in the file
# because have no idea where the bug/error happens
import wx
from wxPython.wx import *
class Custom_Button(wx.PyControl):
# The BMP's
Over_bmp = None #wxEmptyBitmap(1,1,1) # When the mouse is over
Norm_bmp = None #wxEmptyBitmap(1,1,1) # The normal BMP
Push_bmp = None #wxEmptyBitmap(1,1,1) # The down BMP
def __init__(self, parent, id, **kwargs):
wx.PyControl.__init__(self,parent, id, **kwargs)
# Set the BMP's to the ones given in the constructor
#self.Over_bmp = wx.Bitmap(wx.Image(MOUSE_OVER_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
#self.Norm_bmp = wx.Bitmap(wx.Image(NORM_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
#self.Push_bmp = wx.Bitmap(wx.Image(PUSH_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
#self.Pos_bmp = self.pos
self.Bind(wx.EVT_LEFT_DOWN, self._onMouseDown)
self.Bind(wx.EVT_LEFT_UP, self._onMouseUp)
self.Bind(wx.EVT_LEAVE_WINDOW, self._onMouseLeave)
self.Bind(wx.EVT_ENTER_WINDOW, self._onMouseEnter)
self.Bind(wx.EVT_ERASE_BACKGROUND,self._onEraseBackground)
self.Bind(wx.EVT_PAINT,self._onPaint)
self._mouseIn = self._mouseDown = False
def _onMouseEnter(self, event):
self._mouseIn = True
def _onMouseLeave(self, event):
self._mouseIn = False
def _onMouseDown(self, event):
self._mouseDown = True
def _onMouseUp(self, event):
self._mouseDown = False
self.sendButtonEvent()
def sendButtonEvent(self):
event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
event.SetInt(0)
event.SetEventObject(self)
self.GetEventHandler().ProcessEvent(event)
def _onEraseBackground(self,event):
# reduce flicker
pass
def _onPaint(self, event):
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.DrawBitmap(self.Norm_bmp)
# draw whatever you want to draw
# draw glossy bitmaps e.g. dc.DrawBitmap
if self._mouseIn: # If the Mouse is over the button
dc.DrawBitmap(self, self.Mouse_over_bmp, self.Pos_bmp, useMask=False)
if self._mouseDown: # If the Mouse clicks the button
dc.DrawBitmap(self, self.Push_bmp, self.Pos_bmp, useMask=False)
You don't create an object like this:
self.Button1 = customButton.__init__(self, parent, -1)
you do it like this:
self.Button1 = customButton(parent, -1)
__init__ is an implicitly invoked method during object creation.
Don't call __init__() explicitly unless you know you need to.
self.Button1 = customButton(parent, -1)