I've isolated the cause of the problem to be the image, since the code seems to work with other png images with transparency. However, it doesn't seem to work with the one image I need it to. This would be of great help seeing as I'm trying to make a nice shaped window.
The image:
The code:
import wx
class PictureWindow(wx.Frame):
def __init__(self, parent, id, title, pic_location):
# For PNGs. Must be PNG-8 for transparency...
self.bmp = wx.Image(pic_location, wx.BITMAP_TYPE_PNG).ConvertToBitmap()
framesize = (self.bmp.GetWidth(), self.bmp.GetHeight())
# Launch a frame the size of our image. Note the position and style stuff...
# (Set pos to (-1, -1) to let the OS place it.
# This style wx.FRAME_SHAPED is a frameless plain window.
wx.Frame.__init__(self, parent, id, title, size=framesize, pos = (50, 50), style = wx.FRAME_SHAPED)
r = wx.RegionFromBitmap(self.bmp)
self.SetShape(r)
# Define the panel and place the pic
panel = wx.Panel(self, -1)
self.mainPic = wx.StaticBitmap(panel, -1, self.bmp)
# Set an icon for the window if we'd like
#icon1 = wx.Icon("icon.ico", wx.BITMAP_TYPE_ICO)
#self.SetIcon(icon1)
self.Show()
# The paint stuff is only necessary if doing a shaped window
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Main()
def OnPaint(self, event):
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bmp, 0, 0, True)
def Main(self):
sizer = wx.GridBagSizer()
button = wx.Button(self,-1,label="Click me !")
sizer.Add(button, (0,1))
# What pic are we opening?
pic_location = r"C:\Users\user\Pictures\CPUBAR\A4.png" # PNG must be png-8 for transparency...
app = wx.App(redirect=0) # the redirect parameter keeps stdout from opening a wx gui window
PictureWindow(None, -1, 'Picture Viewer', pic_location)
app.MainLoop()
This is in Windows 7, btw.
wx.RegionFromBitmap uses the bitmap's mask to set the shape. If your source image has an alpha channel then it won't have a mask and so wx.RegionFromBitmap will not be able to determine what shape to use. You can convert the source image such that all pixels are either fully opaque or fully transparent, and then wx.Image will load it with a mask instead of an alpha channel. Or you can convert it at runtime using wx.Image's ConvertAlphaToMask method before converting it to a wx.Bitmap.
Your code says that it needs to be in png-8 format in order for transparency to work.
First of all, is the image in png-8 format?
second, why is this a requisite for transparency???
You're converting your image to a bitmap - bitmaps do not support transparency.
As a workaround you could use a .gif (if you can stand the limited color set).
They only support a 1-bit alpha channel.
Related
I'd like to print a file selected with a file picker (or somehow) with
certain extension, so that PyQt or printer will automatically recognize
the format (e.g. pdf, ms word, excel, txt, html, jpg etc.)
So far, I have found here how to print the content
of the TextEdit, but I'd like to print files with various formats.
Is it possible with PyQt5 or should I search elsewhere?
Printing a plain text document does not require a viewer, since the print_() function actually calls the internal QDocument's print_() function:
filePath, filter = QFileDialog.getOpenFileName(self, 'Open file', '', 'Text (*.txt)')
if not filePath:
return
doc = QtGui.QTextDocument()
try:
with open(filePath, 'r') as txtFile:
doc.setPlainText(txtFile.read())
printer = QtPrintSupport.QPrinter(QtPrintSupport.QPrinter.HighResolution)
if not QtPrintSupport.QPrintDialog(printer, self).exec_():
return
doc.print_(printer)
except Exception as e:
print('Error trying to print: {}'.format(e))
You might want to add some functionalities to set the page size, document margins, font sizes etc, before actually printing (just read the QTextDocument docs), I'll leave that to you.
Printing from html files is almost similar, but you'll need to use the QWebEnginePage class from QtWebEngineWidgets. See this answer.
Do not use QTextDocument.setHtml(), as Qt has limited support for html tags.
The same is valid for PDF files too, the difference is that the file has to be loaded through setUrl() and the QWebEngineSettings.PluginsEnabled setting has to be enabled through page.settings().setAttribute(setting, bool) in case it's not.
Read the documentation about PDF File Viewing.
Printing images could be done through two approaches.
The first and simpler, is to create a temporary html file that embeds the image and load to a webengine page as above (you could add controls for zoom/scaling).
Alternatively, you could directly print using QPainter, but you'll have to relate to the printer resolution and image size, so you'd probably want to have a preview dialog before actually printing the image, otherwise it might be too small (or too big).
While more complex than a plain <html><img src=""></html>, this allows a better control on the positioning and sizing of the image[s].
class ImagePrintPreview(QtWidgets.QDialog):
def __init__(self, parent, printer, pixmap):
super().__init__(parent)
self.printer = printer
self.pixmap = pixmap
layout = QtWidgets.QGridLayout(self)
self.viewer = QtWidgets.QLabel()
layout.addWidget(self.viewer, 0, 0, 1, 2)
self.resoCombo = QtWidgets.QComboBox()
layout.addWidget(self.resoCombo, 1, 0)
self.zoom = QtWidgets.QSpinBox(minimum=50, maximum=200, suffix='%')
self.zoom.setValue(100)
self.zoom.setAccelerated(True)
layout.addWidget(self.zoom, 1, 1)
self.zoom.valueChanged.connect(self.updatePreview)
self.buttonBox = QtWidgets.QDialogButtonBox(
QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Cancel)
layout.addWidget(self.buttonBox)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
default = printer.resolution()
self.resoCombo.addItem(str(default), default)
for dpi in (150, 300, 600, 1200):
if dpi == default:
continue
self.resoCombo.addItem(str(dpi), dpi)
self.resoCombo.currentIndexChanged.connect(self.updatePreview)
self.updatePreview()
def updatePreview(self):
# create a preview to show how the image will be printed
self.printer.setResolution(self.resoCombo.currentData())
paperRect = self.printer.paperRect(self.printer.DevicePixel)
printRect = self.printer.pageRect(self.printer.DevicePixel)
# a temporary pixmap that will use the printer's page size
# note that page/paper are QRectF, they have a QSizeF which has to
# be converted to a QSize
pm = QtGui.QPixmap(paperRect.size().toSize())
# new pixmap have allocated memory for their contents, which usually
# result in some random pixels, just fill it with white
pm.fill(QtCore.Qt.white)
# start a qpainter on the pixmap
qp = QtGui.QPainter(pm)
# scale the pixmap to the wanted zoom value
zoom = self.zoom.value() * .01
scaled = self.pixmap.scaledToWidth(int(self.pixmap.width() * zoom), QtCore.Qt.SmoothTransformation)
# paint the pixmap aligned to the printing margins
qp.drawPixmap(printRect.topLeft(), scaled)
# other possible alternatives:
# Center the image:
# qp.translate(printRect.center())
# delta = QtCore.QPointF(scaled.rect().center())
# qp.drawPixmap(-delta, scaled)
# To also rotate 90° clockwise, add this to the above:
# qp.rotate(90)
# *after* qp.translate() and before qp.drawPixmap()
# when painting to a non QWidget device, you always have to end the
# painter before being able to use it
qp.end()
# scale the temporary pixmap to a fixed width
self.viewer.setPixmap(pm.scaledToWidth(300, QtCore.Qt.SmoothTransformation))
def exec_(self):
if super().exec_():
self.printer.setResolution(self.resoCombo.currentData())
# do the same as above, but paint directly on the printer device
printRect = self.printer.pageRect(self.printer.DevicePixel)
qp = QtGui.QPainter(self.printer)
zoom = self.zoom.value() * .01
scaled = self.pixmap.scaledToWidth(int(self.pixmap.width() * zoom), QtCore.Qt.SmoothTransformation)
qp.drawPixmap(printRect.topLeft(), scaled)
# as above, that's important!
qp.end()
class ImagePrinter(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
selBtn = QtWidgets.QPushButton('Open image')
layout.addWidget(selBtn)
selBtn.clicked.connect(self.selectFile)
def selectFile(self):
filePath, filter = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', '/tmp', 'Images (*.jpg *.png)')
if not filePath:
return
pixmap = QtGui.QPixmap(filePath)
if pixmap.isNull():
return
printer = QtPrintSupport.QPrinter(QtPrintSupport.QPrinter.HighResolution)
if QtPrintSupport.QPrintDialog(printer, self).exec_():
ImagePrintPreview(self, printer, pixmap).exec_()
Note that I couldn't test this under windows, so it might be necessary to change things related to the resolution (possibly by using printer.supportedResolutions()).
As already explained in the comments, printing to other (and possibly proprietary) formats requires external modules.
I am looking for a simple solution to display thumbnails using wxPython. This is not about creating the thumbnails. I have a directory of thumbnails and want to display them on the screen. I am purposely not using terms like (Panel, Frame, Window, ScrolledWindow) because I am open to various solutions.
Also note I have found multiple examples for displaying a single image, so referencing any such solution will not help me. The solution must be for displaying multiple images at the same time in wx.
It seems that what I want to do is being done in ThumbnailCtrl, but Andrea's code is complex and I cannot find the portion that does the display to screen. I did find a simple solution in Mark Lutz's Programming Python book, but while his viewer_thumbs.py example definitely has the simplicity that I am looking for, it was done using Tkinter.
So please any wx solution will be greatly appreciated.
EDIT: I am adding a link to one place where Mark Lutz's working Tkinter code can be found. Can anyone think of a wx equivalent?
http://codeidol.com/community/python/viewing-and-processing-images-with-pil/17565/#part-33
I would recommend using the ThumbNailCtrl widget: http://wxpython.org/Phoenix/docs/html/lib.agw.thumbnailctrl.html. There is a good example in the wxPython demo. Or you could use this one from the documentation. Note that the ThumbNailCtrl requires the Python Imaging Library to be installed.
import os
import wx
import wx.lib.agw.thumbnailctrl as TC
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "ThumbnailCtrl Demo")
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
thumbnail = TC.ThumbnailCtrl(panel, imagehandler=TC.NativeImageHandler)
sizer.Add(thumbnail, 1, wx.EXPAND | wx.ALL, 10)
thumbnail.ShowDir(os.getcwd())
panel.SetSizer(sizer)
# our normal wxApp-derived class, as usual
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
Just change the line thumbnail.ShowDir(os.getcwd()) so that it points at the right folder on your machine.
I also wrote up an article for viewing photos here: http://www.blog.pythonlibrary.org/2010/03/26/creating-a-simple-photo-viewer-with-wxpython/ It doesn't use thumbnails though.
Not sure if I am supposed to answer my own question but I did find a solution to my problem and I wanted to share. I was using wx version 2.8. I found that in 2.9 and 3.0 there was a widget added called WrapSizer. Once I updated my version of wx to 3.0 that made the solution beyond simple. Here are the code snippets that matter.
self.PhotoMaxWidth = 100
self.PhotoMaxHeight = 100
self.GroupOfThumbnailsSizer = wx.WrapSizer()
self.CreateThumbNails(len(ListOfPhotots),ListOfPhotots)
self.GroupOfThumbnailsSizer.SetSizeHints(self.whateverPanel)
self.whateverPanel.SetSizer(self.GroupOfThumbnailsSizer)
self.whateverPanel.Layout()
def CreateThumbNails(self, n, ListOfFiles):
thumbnails = []
backgroundcolor = "white"
for i in range(n):
ThumbnailSizer = wx.BoxSizer(wx.VERTICAL)
self.GroupOfThumbnailsSizer.Add(ThumbnailSizer, 0, 0, 0)
thumbnails.append(ThumbnailSizer)
for thumbnailcounter, thumbsizer in enumerate(thumbnails):
image = Image.open(ListOfFiles[thumbnailcounter])
image = self.ResizeAndCenterImage(image, self.PhotoMaxWidth, self.PhotoMaxHeight, backgroundcolor)
img = self.pil_to_image(image)
thumb= wx.StaticBitmap(self.timelinePanel, wx.ID_ANY, wx.BitmapFromImage(img))
thumbsizer.Add(thumb, 0, wx.ALL, 5)
return
def pil_to_image(self, pil, alpha=True):
""" Method will convert PIL Image to wx.Image """
if alpha:
image = apply( wx.EmptyImage, pil.size )
image.SetData( pil.convert( "RGB").tostring() )
image.SetAlphaData(pil.convert("RGBA").tostring()[3::4])
else:
image = wx.EmptyImage(pil.size[0], pil.size[1])
new_image = pil.convert('RGB')
data = new_image.tostring()
image.SetData(data)
return image
def ResizeAndCenterImage(self, image, NewWidth, NewHeight, backgroundcolor):
width_ratio = NewWidth / float(image.size[0])
temp_height = int(image.size[1] * width_ratio)
if temp_height < NewHeight:
img2 = image.resize((NewWidth, temp_height), Image.ANTIALIAS)
else:
height_ratio = NewHeight / float(image.size[1])
temp_width = int(image.size[0] * height_ratio)
img2 = image.resize((temp_width, NewHeight), Image.ANTIALIAS)
background = Image.new("RGB", (NewWidth, NewHeight), backgroundcolor)
masterwidth = background.size[0]
masterheight = background.size[1]
subwidth = img2.size[0]
subheight = img2.size[1]
mastercenterwidth = masterwidth // 2
mastercenterheight = masterheight // 2
subcenterwidth = subwidth // 2
subcenterheight = subheight // 2
insertpointwidth = mastercenterwidth - subcenterwidth
insertpointheight = mastercenterheight - subcenterheight
background.paste(img2, (insertpointwidth, insertpointheight))
return background
I got the pil_to_image portion from another stackoverflow post and I wrote the ResizeAndCenterImage portion to make all of my thumbnails the same size while keeping the aspect ration intact and not do any cropping. The resize and center call can be skipped all together if you like.
I would just display them as wx.Image inside a frame.
http://www.wxpython.org/docs/api/wx.Image-class.html
From the class: "A platform-independent image class. An image can be created from data, or using wx.Bitmap.ConvertToImage, or loaded from a file in a variety of formats. Functions are available to set and get image bits, so it can be used for basic image manipulation."
Seems it should be able to do what you want, unless I'm missing something.
I have a set of images available. If I click on one of those images is there a way to determine which of the images has been clicked on in wxPython?
You will almost certainly have to calculate it for yourself. The most straight-forward method would be to use a mouse event like wx.EVT_LEFT_DOWN and grab the mouse's coordinates in the event handler. Then use that information to tell you where on your wxPython window you clicked. Each of your image widgets or DCs or whatever you're using can report it's size and position, so if the mouse coordinates are in X image's boundaries, you know it's been clicked on. You might also be able to use the HitTest() method, depending on what you're using to show the images.
EDIT: Here is how you would do it if you were using a wx.StaticBitmap, which actually lets you attach an wx.EVT_LEFT_DOWN to it:
import wx
class PhotoCtrl(wx.Frame):
def __init__(self):
size = (400,800)
wx.Frame.__init__(self, None, title='Photo Control', size=size)
self.panel = wx.Panel(self)
img = wx.EmptyImage(240,240)
self.imageCtrl = wx.StaticBitmap(self.panel, wx.ID_ANY,
wx.BitmapFromImage(img),
name="emptyImage")
imageCtrl2 = wx.StaticBitmap(self.panel, wx.ID_ANY,
wx.BitmapFromImage(img),
name="anotherEmptyImage")
self.imageCtrl.Bind(wx.EVT_LEFT_DOWN, self.onClick)
imageCtrl2.Bind(wx.EVT_LEFT_DOWN, self.onClick)
mainSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer.Add(self.imageCtrl, 0, wx.ALL, 5)
mainSizer.Add(imageCtrl2, 0, wx.ALL, 5)
self.panel.SetSizer(mainSizer)
self.Show()
#----------------------------------------------------------------------
def onClick(self, event):
""""""
print event.GetPosition()
imgCtrl = event.GetEventObject()
print imgCtrl.GetName()
if __name__ == '__main__':
app = wx.App(False)
frame = PhotoCtrl()
app.MainLoop()
you dont tell us anything about how you are displaying your images? are you blitting them right on the dc? are you creating panels for them? etc... properly setting up your project is important. basically you give us zero information to help you with.
Keeping all that in mind, something like this would work fine (this is called a self contained code example, you should always provide one with your questions, to make it easier for people to help you)
import wx
a = wx.App(redirect=False)
f= wx.Frame(None,-1,"Some Frame",size = (200,200))
sz = wx.BoxSizer(wx.HORIZONTAL)
def OnClick(evt):
print "Clicked:",evt.GetId()-10023
for i,img in enumerate(["img1","img2","img3"]):
id = 10023+i
p = wx.Panel(f,-1)
sz.Add(p)
sz1 = wx.BoxSizer()
p.Bind(wx.EVT_LEFT_UP,OnClick)
bmp = wx.Image(img).ConvertToBitmap()
b = wx.StaticBitmap(p,-1,bmp)
sz1.Add(b)
p.SetSizer(sz1)
f.SetSizer(sz)
f.Layout()
f.Fit()
f.Show()
a.MainLoop()
Keep in mind I didnt test it... but theoretically it should work...
I'm writing a PyGtk paint program based on the basic tutorial found here.
Is there any way to add an image to the drawing area so that you can still draw over the image? Like a stamp, or an imported photo for example. I've tried adding a gtk.Image() but gtk.DrawingArea object has no attribute add.
self.window = gtk.Window((gtk.WINDOW_TOPLEVEL))
self.window.set_title ("Canvas")
self.window.set_position(gtk.WIN_POS_CENTER)
hbox = gtk.HBox(False, 0)
self.window.add(hbox)
self.window.set_resizable(False)
# Create the drawing area
drawing_area = gtk.DrawingArea()
drawing_area.set_size_request(screenWidth-350, screenHeight-100)
hbox.pack_start(drawing_area, True, True, 0)
drawing_area.show()
You have to draw the image (as a gtk.gdk.Pixbuf, not gtk.Image) onto the backing pixmap yourself using gtk.gdk.Drawable.draw_pixbuf(). Only container widgets (widgets that can contain other widgets) have an add() method, and gtk.DrawingArea is not one.
pixbuf = gtk.gdk.pixbuf_new_from_file(image_filename) #one way to load a pixbuf
pixmap.draw_pixbuf(None, pixbuf, 0, 0, x, y, -1, -1, gtk.gdk.RGB_DITHER_NONE, 0, 0)
Short question:
I know how to draw text on a wx.Bitmap, but how can I draw text on a wx.Icon in wxpython so that it does not appear transparent?
Long question:
I have a wxpython based GUI application, that has a taskbar icon, which I set using mytaskbaricon.SetIcon("myicon.ico").
Now I would like to dynamically put some text on the icon, so I tried to use the wx .DrawText method as explained here.This works fine if I test this for bitmaps (which I use in menu items).
However, the taskbar requires an wxIcon instead of a wxBitmap. So I figured I'll convert the icon to a bitmap, draw the text, and then convert it back to an icon. This works, except that the text is not shown transparent. Why ? And how can I make the text NOT transparent ?
My code is as roughly follows:
import wx
class MyTaskBarIcon(wx.TaskBarIcon):
...
icon = wx.Icon("myicon.ico", wx.BITMAP_TYPE_ICO)
bmp = wx.Bitmap("myicon.ico", wx.BITMAP_TYPE_ICO)
memDC = wx.MemoryDC()
memDC.SetTextForeground(wx.RED)
memDC.SelectObject(bmp)
memDC.DrawText("A", 0, 0)
icon.CopyFromBitmap(bmp)
self.SetIcon(icon, APP_NAME_WITH_VERSION)
...
So, no errors raised and myicon.ico is shown, but the letter A is transparant (instead of red). If I use a .bmp file to start with (myicon.bmp) the text appears in the correct color (but the borders are jagged). I've played around with masks, foreground and background colors, but that didn't help.
(I am using Windows 7, Python 2.6, wxpython 2.8)
Edit: I've shortened my explanation, and made the code more self-contained
Short answer: It seems to me that there is a bug in this particular piece of wx code. I am going to report it and see what comes out of it.
Long answer: You can hack your way around. Setup a color, which is not used in the image. Then draw using that color and when done, fix alpha values and color of those pixels to match your expectation:
import wx
from wx import ImageFromStream, BitmapFromImage, EmptyIcon
import cStringIO, zlib
# ================================ ICON ======================================
def getData():
return zlib.decompress(
'x\xda\x01\x97\x03h\xfc\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\
\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\
\x08\x08\x08|\x08d\x88\x00\x00\x03NIDAT8\x8dm\xd2ML\x9bu\x00\xc7\xf1\xef\xf3\
<\xed\xda><\xa3#\xcb\x8a\x0cp\xac8\x15\x87\x89/ \x11\xd1d&:5&#n\xc9\\\xa2\
\xc6\xc3b\xe2\xd1y0Y2\xa3q^\xcc\xb8\x9a\xb9\xf9rQc\xc6\x0es\xa4\xd1\x91\xe98\
\xc8\x96\xb98H\xc3\x8b\xc0\xc6\x00\x91\xd2\xb2\xa7}\xda\xe7\xa5\xcf\xd3\xf6\
\xf9{0\xa2\x07\xbf\xf7_\xf29\xfc$\x00\xf1>\xb2\xd9\xc7\tI0$\xc0\xd5d\x06\xa5\
\x17q\xf9O\xa5\x0b$$\x85KB\xa2\xec\xcb\xbc\x1e}\x81\xdf\x01$q\x9a`>\xce\xc9`\
\xc7\x91#\xa1\xce\xa3;\xed\xdbg\xb3s\x19c\xe1\x9cz\xbe*A\x0f\x80\x80\xf4A\
\xeb\xb0\xfcPG\xa2;\x10\x8aI\xe5\xd9\x93\x8bB\xe6`l\x88U)\xf3-\xc7\xc3\xbb_{\
;r\xef\xe1Vci\xa4\xb0\xbc:\x17\xb8\xdczQ\xd3B5"A\x1f\x00\xa7"\xe39\x16\xfb\
\xd6_\xb1wu\x1f#\xa9\x15-k\xe6\xd4j\xa2D\xbf\xec\x95\x91\xe5PGX_\x18),.\xcei\
W\xdb\xbf\xd3:\xb7{49\x0e\xeem\x1dkAG+Z\xb4l\xdf\xc6o-\xc3\xea\x9fK\xbf\x84\
\xe5\xa6\xfe&\xa1>\xa8\xad)\xec\x96n}\xc6`E\xa8g7\x95d\xdbD\xf2\x82\xda\xae\
\x06\x08\xd95\x1e\xeej\xa2\xa1^F \xa1\x1b5\xae\xcf\xe5\xa8D\x14\xea\xf4\xf3\
\xdco\x9es\xb7\x9933\xe1Z\xe9U\t\xe0\xd8\xe7\x17?\t4\xecz7\x99\xd0hp\x05\x87\
\xf6u\x927\x0c6-\x87\xf6\xd6\x16\x00\xaa\x02\xbeN\xdd\xc2\xd7\x04\x99\xec:9K\
\xf9\xf8\xd37\x07\x8e\xcb\x00\x99\xca=\xbd\xbe\x00\xbf\xe4\xb1wO\x0c\xbb*\
\x08\x06\x83\x8c\xfd\xf8\x03E\xc3\xa0\xe2\xba\\\x1a\xfb\x99\xee=q\x8c\xac\
\x83#7RtC\x03\x00\x01\x80r\xd9\xea\xa9z2\x86\xeb\x13\x8bEpk\x82:U\xe5\x8f\
\x95\x15\xc6~\x1a\'=5\xc9\xb3\xcf\xef\xa7q\x87Jn\xd3A4\x04)\x97\xad\x1e\x00\
\x19\xc0\xb3-,\xbb\x82\xe3\xf9\xb85\xa8\xf8\x905J\xd4i\x1a\xe9\xa9I^:0\xc4#\
\xbd}\xb8U\xa8x>\x96]\xc1\xb3-\xb6\x04^\xd9N\x17K\x91gv\xc6\x03,el\xeek\x8b\
\x82\x1c\xe6\xd1\xc7\xfby\xa0g/j\xb4\x1e\xd3\x85\xd5\x8cE0"\x91+\xd9xe;\xfd\
\xaf\xc0\xb1\xae\x14\r\x03\xbd\xecr\xf5\xe6\x06\xc1\x10\xd4\x85\x83<5\xf8$\
\xf1\xc6zB\x80\x16\x86_of\xf1\xf0(\x1a\x06\x9ec]\xd9\x12\xb8\xb63\xea:\xe6\
\xa1\xd9\x9a\xd2-\xb7U\xf9bD\xf0\\o\x82\xaeD\x1d\x08X\xc9Z\x8c^\xcbP4\xd6\
\x99\xdf\xb00\xf3k3\x08e\x14#\xfa\xe7\xeb}GO\xbd\xf5Xr\xc7\xf0BAS[\xe3\x1a\
\xb1P\x08\xc5\x97\xa9\xf9\x82\x8aT\xc5\xf0\\\xaa\xd5*\xaa\xb8k\xa7\xefl\xbes\
\xfd\xcc\xb1\xd3[\x02\x80\xe17\x9e\x98\x8fF\xa3jv3_;12\xaf\xccJ*\xb2\x12\x06\
\xc0\xaf\x95iV+\xbc\xf7rR\xc8rcD\xa2kv\xe0\xcc\xdf;\x19 \x95J5\x17\n\x85\xef\
\xc3\xe10f\xa9`\x98\xf9;\x1f\xda\xb9\xe9qk\xe3\x86nm\xdc\xd0\xed\xdc\xf4\xf8\
\xf2\xf2\xfc\x07\x85B\xdel\x8e\xc7%]\xd7/\xa7R\xa9\xe4\x96\xc04M\xc7q\x9c\
\xb5\x89\x89\x89N!\xc4\xd3S\xdf|4\xcd\xfftw\xff\x97_]\xd3\xf5I\xc0\xf2}\xdf\
\x02\xf8\x0b\xc1.\x9e\xd8Y.\x85\x85\x00\x00\x00\x00IEND\xaeB`\x822\x86\xba\
\xb3' )
def getBitmap():
return BitmapFromImage(getImage())
def getImage():
stream = cStringIO.StringIO(getData())
return ImageFromStream(stream)
def getIcon():
icon = EmptyIcon()
icon.CopyFromBitmap(getBitmap())
return icon
# ============================================================================
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.number = 0
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.panel = wx.Panel(self)
self.button = wx.Button(self.panel, label="Test")
self.button.Bind(wx.EVT_BUTTON, self.OnButton)
self.tbicon = wx.TaskBarIcon()
self.tbicon.SetIcon(getIcon(), "Test")
self.sizer = wx.BoxSizer()
self.sizer.Add(self.button)
self.panel.SetSizerAndFit(self.sizer)
self.Show()
# --------------------------------------------------------------------------
def OnClose(self, e):
self.tbicon.Destroy()
self.Destroy()
wx.Exit()
# --------------------------------------------------------------------------
def OnButton(self, e):
# HERE WE GO!
self.number += 1
bitmap = getBitmap()
# Find unused color
image = bitmap.ConvertToImage()
my_solid_color = wx.Color(*image.FindFirstUnusedColour(0, 0, 0)[1:])
# Use the unused *unique* color to draw
dc = wx.MemoryDC()
dc.SetTextForeground(my_solid_color)
dc.SelectObject(bitmap)
dc.DrawText(str(self.number), 0, 0)
dc.SelectObject(wx.NullBitmap)
# Convert the bitmap to Image again
# and fix the alpha of pixels with that color
image = bitmap.ConvertToImage()
for x in range(image.GetWidth()):
for y in range(image.GetHeight()):
p = wx.Colour(image.GetRed(x, y),
image.GetGreen(x, y),
image.GetBlue(x, y))
if p == my_solid_color:
image.SetAlpha(x, y, 255) # Clear the alpha
image.SetRGB(x, y, 0, 0, 0) # Set the color that we want
# Convert back to Bitmap and save to Icon
bitmap = image.ConvertToBitmap()
icon = wx.IconFromBitmap(bitmap)
self.tbicon.SetIcon(icon, "Test")
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
Note: A had to add some icon. You can ignore that part of the code.
Just a guess, but perhaps create your initial icon as an "EmptyIcon", then copy the bmp to it.
import wx
class MyTaskBarIcon(wx.TaskBarIcon):
...
icon = wx.EmptyIcon()
bmp = wx.Bitmap("myicon.ico", wx.BITMAP_TYPE_ICO)
bmp = WriteTextOnBitmap("A", bmp, color=wx.RED) #this function is as in the link above
icon.CopyFromBitmap(bmp)
self.SetIcon(icon, APP_NAME_WITH_VERSION)
...