Clipboard.Flush() always fails in wxpython app - python

In the EVT_CLOSE handler of a wxpython app, I'm trying to flush the clipboard to leave the copied text available to other applications. However, the Flush() method always returns false.
Example:
cp = wx.Clipboard.Get()
print cp.Flush()
Returns:
False
I'm using python 2.7.3 on Fedora 16 (Gnome 3 default spin) and wx.VERSION returns (2, 8, 12, 0, '')
Thanks for any help you can give me
UPDATE: Apparently it's been a "known bug" since 2009. Not sure what'll happen with it. Please add solutions if you're way into WX

I just finished creating a simple demo app and mine works. Here's my code:
import wx
########################################################################
class ClipboardPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
lbl = wx.StaticText(self, label="Enter text to copy to clipboard:")
self.text = wx.TextCtrl(self, style=wx.TE_MULTILINE)
copyBtn = wx.Button(self, label="Copy")
copyBtn.Bind(wx.EVT_BUTTON, self.onCopy)
copyFlushBtn = wx.Button(self, label="Copy and Flush")
copyFlushBtn.Bind(wx.EVT_BUTTON, self.onCopyAndFlush)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(lbl, 0, wx.ALL, 5)
sizer.Add(self.text, 1, wx.EXPAND)
sizer.Add(copyBtn, 0, wx.ALL|wx.CENTER, 5)
sizer.Add(copyFlushBtn, 0, wx.ALL|wx.CENTER, 5)
self.SetSizer(sizer)
#----------------------------------------------------------------------
def onCopy(self, event):
""""""
self.dataObj = wx.TextDataObject()
self.dataObj.SetText(self.text.GetValue())
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(self.dataObj)
wx.TheClipboard.Close()
else:
wx.MessageBox("Unable to open the clipboard", "Error")
#----------------------------------------------------------------------
def onCopyAndFlush(self, event):
""""""
self.dataObj = wx.TextDataObject()
self.dataObj.SetText(self.text.GetValue())
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(self.dataObj)
wx.TheClipboard.Flush()
else:
wx.MessageBox("Unable to open the clipboard", "Error")
self.GetParent().Close()
########################################################################
class ClipboardFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="Clipboard Tutorial")
panel = ClipboardPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = ClipboardFrame()
app.MainLoop()
I'm on Windows 7, wxPython 2.8.12 and Python 2.6.6. What are you on? Does this code work for you?

Related

How to access from child to widget in parent window?

I have parent class with panel (notebook) and combobox as follows:
class A(wx.aui.AuiMDIChildFrame):
def __init__(self,parent):
self.panel_1 = wx.Panel(self, -1)
self.NB = wx.Notebook(self.panel_1, -1, style=0)
self.NB_A= WindowFirst(self.NB)
self.ComboA= wx.ComboBox(self.panel_1, 500, 'Phase', (50, 150), (160,-1), phasesList, wx.CB_DROPDOWN)
and in another py file:
class WindowFirst(GeneralPanel):
def __init__(self,parent):
how do I access ComboA from here?
This isn't my complete code... Just want is relevent for the question.
How do I acess comboA from WindowFirst? I need to be able to set values to the ComboA from WindowFirst.
I can access from A to WindowFirst, but not the other way around.
Any suggestions?
This cannot be done as long as you are trying to access ComboA from WindowFirst.init(). The constructor for WindowFirst is called as NB_A gets created, at which time ComboA has not yet been created. So no matter how you try to access ComboA, it's not possible because it doesn't exist
However, if you want to access ComboA from another method of WindowFirst, that can be done. You have NB_A as a child of NB, NB as a child of panel_1, panel_1 as a child of A and ComboA as a child of A. You just need to make sure ComboA exists before you try to access it. So something like this.
def anotherFunction():
#how do I access ComboA from here?
nb = self.GetParent()
panel_1 = nb.GetParent()
a = panel_1.GetParent()
try:
#try to access ComboA and do what you gotta do
a.ComboA.doSomething()
except:
#something went wrong (like ComboA doesn't exist yet)
print "ComboA doesn't exist yet"
or for brevity
def anotherFunction():
#how do I access ComboA from here?
try:
self.GetParent().GetGrandParent().ComboA.doSomething()
except:
print "ComboA doesn't exist yet"
The recommended way to communicate between classes in wxPython is to use pubsub, which is included with wxPython. Basically you will want to create a listener in your class A and then publish messages to it from WindowFirst to tell it to update.
Here's an example:
import random
import wx
from wx.lib.pubsub import pub
########################################################################
class TabPanel(wx.Panel):
#----------------------------------------------------------------------
def __init__(self, parent):
""""""
wx.Panel.__init__(self, parent)
colors = ["red", "blue", "gray", "yellow", "green"]
self.color = random.choice(colors)
self.SetBackgroundColour(self.color)
self.Bind(wx.EVT_LEFT_DCLICK, self.update_button)
lbox = wx.ListBox(self, choices=colors)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(lbox, 0, wx.ALL, 10)
self.SetSizer(sizer)
#----------------------------------------------------------------------
def update_button(self, event):
""""""
pub.sendMessage('button_listener', message=self.color)
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
########################################################################
class DemoFrame(wx.Frame):
"""
Frame that holds all other widgets
"""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, wx.ID_ANY,
"Notebook Tutorial",
size=(600,400)
)
panel = MyPanel(self)
self.tab_num = 3
self.notebook = wx.Notebook(panel)
tabOne = TabPanel(self.notebook)
self.notebook.AddPage(tabOne, "Tab 1")
tabTwo = TabPanel(self.notebook)
self.notebook.AddPage(tabTwo, "Tab 2")
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5)
self.btn = wx.Button(panel, label="Get Color")
sizer.Add(self.btn)
panel.SetSizer(sizer)
self.Layout()
# create a listener
pub.subscribe(self.change_button, 'button_listener')
self.Show()
#----------------------------------------------------------------------
def change_button(self, message, arg2=None):
""""""
self.btn.SetLabel(message)
#----------------------------------------------------------------------
if __name__ == "__main__":
app = wx.App(False)
frame = DemoFrame()
app.MainLoop()
Note that the pubsub API changed slightly in wxPython 2.9 and above. If you're using an older version, then you'll need to change the code a bit. I have a tutorial illustrating the older API here.
For more information on the newer API, check out my updated article here:
http://www.blog.pythonlibrary.org/2013/09/05/wxpython-2-9-and-the-newer-pubsub-api-a-simple-tutorial/

How to delete an animated gif from a frame with wxPython?

I can't for the life of me figure out how to destroy or hide a gif from a wxPython frame.
Here is the example code:
import wx
import wx.animate
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "GIF frame")
panel = wx.Panel(self, wx.ID_ANY)
btn1 = wx.Button(self, -1, "Start GIF",(50,10))
btn1.Bind(wx.EVT_BUTTON, self.onButton1)
btn2 = wx.Button(self, -1, "Stop GIF",(50,40))
btn2.Bind(wx.EVT_BUTTON, self.onButton2)
#----------------------------------------------------------------------
def onButton1(self, event):
self.animateGIF()
#----------------------------------------------------------------------
def onButton2(self, event):
self.animateGIF(False)
#----------------------------------------------------------------------
def animateGIF(self, state=True):
gif_fname = "test.gif"
gif = wx.animate.GIFAnimationCtrl(self, -1, gif_fname,pos=(50,70),size=(10,10))
gif.GetPlayer()
if state:
gif.Play()
else:
gif.Stop()
#gif.Destroy(), gif.Hide() have no effect besides cancelling the Stop() function.
#----------------------------------------------------------------------
# Run the program
app = wx.App()
frame = MyForm().Show()
app.MainLoop()
So, how do I go about deleting this gif from my frame ?
Thank you! I hope the code is clear enough.
I believe you are loading a new GIF every time you call animateGIF. I suggest the following, though I am sure this can be improved:
import wx
import wx.animate
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "GIF frame")
# panel not used in this example
#panel = wx.Panel(self, wx.ID_ANY)
self.btn1 = wx.Button(self, -1, "Start GIF",(50,10))
self.btn1.Bind(wx.EVT_BUTTON, self.onButton1)
self.btn2 = wx.Button(self, -1, "Stop GIF",(50,40))
self.btn2.Bind(wx.EVT_BUTTON, self.onButton2)
self.gif = None
#----------------------------------------------------------------------
def onButton1(self, event):
self.animateGIF()
#----------------------------------------------------------------------
def onButton2(self, event):
self.animateGIF(False)
#----------------------------------------------------------------------
def animateGIF(self, state=True):
if self.gif == None:
gif_fname = "test.gif"
self.gif = wx.animate.GIFAnimationCtrl(self, -1, gif_fname,pos=(50,70),size=(10,10))
# call to GetPlayer was unnecessary
#gif.GetPlayer()
if state:
self.gif.Play()
else:
self.gif.Stop()
self.gif.Destroy()
self.gif = None
#----------------------------------------------------------------------
# Run the program
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()

Python and multiple select with a ListCtrl

I have a custom listctrl in my application that I would like the ability to select multiple rows (and deselect) much like one would do in a ListBox. Currently I have a listctrl that I am able to grab single selections; however, once I click on another row in my listctrl, the previous "un-highlights". I would like it to stay highlighted unless I click on it again -- so the user knows which rows he/she has selected (exact same way a ListBox works). I tried adding wx.LC_MULTIPLE_SEL to the listctrl line, but this did not work.
Help? Thanks!
I took this example from the following site by Mike Driscoll Python Blog. I adapted to it to grab row selections. Essentially I select a row and the index is appended to a list called InfoList. When I select a new row, it appends correctly, but I would like the row to stay "highlighted" in the actual list. Then I could add another line to remove an item from the list if I select it again in the listctrl.
import wx
import wx.lib.mixins.listctrl as listmix
InfoList = []
musicdata = {
0 : ("Bad English", "The Price Of Love", "Rock"),
1 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"),
2 : ("George Michael", "Praying For Time", "Rock"),
3 : ("Gloria Estefan", "Here We Are", "Rock"),
4 : ("Linda Ronstadt", "Don't Know Much", "Rock"),
5 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"),
6 : ("Paul Young", "Oh Girl", "Rock"),
}
########################################################################
class TestListCtrl(wx.ListCtrl):
#----------------------------------------------------------------------
def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=0):
wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
########################################################################
class TestListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin):
#----------------------------------------------------------------------
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)
self.list_ctrl = TestListCtrl(self, size=(-1,100),
style=wx.LC_REPORT
|wx.BORDER_SUNKEN
|wx.LC_SORT_ASCENDING
)
self.list_ctrl.InsertColumn(0, "Artist")
self.list_ctrl.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT)
self.list_ctrl.InsertColumn(2, "Genre")
items = musicdata.items()
index = 0
for key, data in items:
self.list_ctrl.InsertStringItem(index, data[0])
self.list_ctrl.SetStringItem(index, 1, data[1])
self.list_ctrl.SetStringItem(index, 2, data[2])
self.list_ctrl.SetItemData(index, key)
index += 1
# Now that the list exists we can init the other base class,
# see wx/lib/mixins/listctrl.py
self.itemDataMap = musicdata
listmix.ColumnSorterMixin.__init__(self, 3)
self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list_ctrl)
### I ADDED THIS ###
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectMustHave, self.list_ctrl)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
### I ADDED THIS ###
def OnSelectMustHave(self,event):
info = event.GetData()
InfoList.append(info)
print info,InfoList
#----------------------------------------------------------------------
# Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
def GetListCtrl(self):
return self.list_ctrl
#----------------------------------------------------------------------
def OnColClick(self, event):
print "column clicked"
event.Skip()
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "List Control Tutorial")
# Add a panel so it looks the correct on all platforms
panel = TestListCtrlPanel(self)
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
its gross but this will do what you want
def OnSelectMustHave(self,event):
info = event.GetData()
InfoList.append(info)
def do_select():
map(lambda x:self.list_ctrl.Select(x,1) ,set(InfoList))
wx.CallLater(100,do_select)
print info,InfoList
return
however since you have the list of selected elements in InfoList something like the below solution may work
def OnSelectMustHave(self,event):
info = event.GetData()
InfoList.append(info)
map(lambda x:self.list_ctrl.SetItemBackgroundColour(x,wx.LIGHT_GREY) ,set(InfoList))
print info,InfoList
return
A regular ListCtrl works:
import wx
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "List Control Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.index = 0
self.list_ctrl = wx.ListCtrl(panel, size=(-1,100),
style=wx.LC_REPORT
|wx.BORDER_SUNKEN
)
self.list_ctrl.InsertColumn(0, 'Subject')
self.list_ctrl.InsertColumn(1, 'Due')
self.list_ctrl.InsertColumn(2, 'Location', width=125)
btn = wx.Button(panel, label="Add Line")
btn.Bind(wx.EVT_BUTTON, self.add_line)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def add_line(self, event):
line = "Line %s" % self.index
self.list_ctrl.InsertStringItem(self.index, line)
self.list_ctrl.SetStringItem(self.index, 1, "01/19/2010")
self.list_ctrl.SetStringItem(self.index, 2, "USA")
self.index += 1
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
And if I modify this to use the two mixins you mentioned, it also works:
import wx
import wx.lib.mixins.listctrl as listmix
########################################################################
class MyListCtrl(wx.ListCtrl, listmix.TextEditMixin, listmix.ColumnSorterMixin):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.ListCtrl.__init__(self, parent, style=wx.LC_REPORT|wx.BORDER_SUNKEN)
listmix.ColumnSorterMixin.__init__(self, 3)
listmix.TextEditMixin.__init__(self)
#----------------------------------------------------------------------
def GetListCtrl(self):
return self
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "List Control Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.index = 0
self.list_ctrl = MyListCtrl(panel)
self.list_ctrl.InsertColumn(0, 'Subject')
self.list_ctrl.InsertColumn(1, 'Due')
self.list_ctrl.InsertColumn(2, 'Location', width=125)
btn = wx.Button(panel, label="Add Line")
btn.Bind(wx.EVT_BUTTON, self.add_line)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 1, wx.ALL|wx.EXPAND, 5)
sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def add_line(self, event):
line = "Line %s" % self.index
self.list_ctrl.InsertStringItem(self.index, line)
self.list_ctrl.SetStringItem(self.index, 1, "01/19/2010")
self.list_ctrl.SetStringItem(self.index, 2, "USA")
self.index += 1
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
I am using wxPython 2.6 and wxPython 2.8.12 on Windows 7. I can select multiple items one at a time and deselect them as well.

wxGTK+ wxComboBox deselection

When creating wx.ComboBox under Windows you can specify wxCB_READONLY to let users select from only proposed options. But you can clear selection by:
combo.SetSelection(wx.NOT_FOUND)
But under linux (wxGTK) the option is deselected on creation, but once selected in cannot be cleared. Not by any of following:
combo.SetSelection(wx.NOT_FOUND)
combo.SetValue('')
Is it possible to do this anyhow?
Actually, setting the value to an empty string works for me on Arch Linux:
import wx
########################################################################
class MyPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
choices = ["", "1", "2", "3"]
self.choices = choices
self.cbo = wx.ComboBox(self, value="1", choices=choices)
btn = wx.Button(self, label="Reset")
btn.Bind(wx.EVT_BUTTON, self.onReset)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.cbo, 0, wx.ALL, 5)
sizer.Add(btn, 0, wx.ALL, 5)
self.SetSizer(sizer)
#----------------------------------------------------------------------
def onReset(self, event):
""""""
print "resetting"
self.cbo.SetValue("")
########################################################################
class MyFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title="CombBox")
panel = MyPanel(self)
self.Show()
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame()
app.MainLoop()

How can wxThumbnailCtrl in wxpython be used?

I think this is a new widget and theres no examples online about this. im not sure how i should start using it or how it can be used.
Here is simple example to get you started. self.button selects directory with images; on doubleclick on any of thumbnails a messagebox is shown with info on selected thumb.
import wx
from wx.lib.agw import thumbnailctrl as tn
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, style=wx.DEFAULT_FRAME_STYLE)
self.button = wx.Button(self, -1, "Select dir")
self.Bind(wx.EVT_BUTTON, self.ButtonPress, self.button)
self.tn = tn.ThumbnailCtrl(self)
self.tn.Bind(tn.EVT_THUMBNAILS_DCLICK, self.TnClick)
box = wx.BoxSizer(wx.VERTICAL)
box.Add(self.tn, 1, wx.EXPAND, 0)
box.Add(self.button, 0, wx.ADJUST_MINSIZE, 0)
self.SetSizer(box)
box.Fit(self)
self.Layout()
def ButtonPress(self, evt):
dlg = wx.DirDialog(self, 'Get dir')
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
dlg.Destroy()
self.tn.ShowDir(path)
def TnClick(self, evt):
sel = self.tn.GetSelection()
wx.MessageBox(self.tn.GetThumbInfo(sel))
if __name__ == "__main__":
app = wx.PySimpleApp(0)
frame = MyFrame(None, -1, "")
frame.Show()
app.MainLoop()

Categories

Resources