I am using wxPython to display a graphical output in a wx.Frame. with in a class. Here is my code:
class X():
......
def uniform_output(self):
......
self.GraphicalOutput()
def GraphiclaOutput(self):
self._app = wx.App()
self._frame = wx.Frame(None, self._app, 0, 'Graphical Output', size = (800, 600))
self._frame.Show()
self._app.MainLoop()
When I run my code, I create an instance of class X, and it will call its function GraphicalOutput(). However, when the graphical frame should show up, it merely flashed on the screen and disappeared.
May I know how to make the frame stay on the screen until I turn it off?
Thanks.
Seems the parameter is not correct when you create the Frame. Did you see any error in the console?
Maybe you can try this:
frame = wx.Frame(None, -1, 'Graphical Output', size = (800, 600))
Related
I am creating a multi touch accuracy checking device that indicates where the user should touch the screen. It overlays a semi transparent image over an exe called using subprocess with wx as shown here.
I want to output to terminal to prompt user for each data collection point but I can't exit MainLoop() to prompt the user, collect data, and repeat. Press and unpress of tab records one instance of touch in the exe.
Thank you
def scale_bitmap(bitmap, width, height):
image = wx.ImageFromBitmap(bitmap)
image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
result = wx.Bitmap(image)
return result
for x in range(1, 7):
app = wx.App()
trans = 100
frame1 = wx.Frame(None, -1, "KEA", style=wx.CLIP_CHILDREN | wx.STAY_ON_TOP)
# create the class instance
frame1.ShowFullScreen(True)
image_file = "6dataPoints.jpg"
bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
bmp1 = scale_bitmap(bmp1, GetSystemMetrics(1) * 1.5, GetSystemMetrics(1))
bitmap1 = wx.StaticBitmap(frame1, -1, bmp1, (-100, 0))
hwnd = frame1.GetHandle()
extendedStyleSettings = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE,
extendedStyleSettings | win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT)
win32gui.SetLayeredWindowAttributes(hwnd, 0, 255, win32con.LWA_ALPHA)
frame1.SetTransparent(trans)
print("Place fingers over data collection point %d" % (x))
pyautogui.keyDown("tab")
pyautogui.keyUp("tab")
app.MainLoop()
Why do you want to use the terminal for output and prompts instead of doing it in the GUI? It would make sense to just show some (modal) dialog in the GUI instead.
If you really want to use both (blocking) terminal IO and GUI from the same program, the simplest way is to do it from two different threads, with one thread reserved for the GUI stuff only.
If you create a frame through wxpython and change the contents of the staticText, the alignment will be initialized.
How can I solve this problem?
I want to align it again.
This problem is caused by the autoresize of the text control so to prevent that just add wx.ST_NO_AUTORESIZE to the style and it will be solved.
txtCtrl = wx.StaticText(parent, -1, "some label", style = wx.ALIGN_CENTER| wx.ST_NO_AUTORESIZE)
The static text does not have a method called SetStyle()
To dynamically set window alignment flags you have to
Get the wx.Sizer
Find the wx.SizerItem
Set the wx.SizerItem flags via SetFlag
call Sizer.Layout()
Here's a simple example:
import wx
import traceback
def run():
app = wx.App()
# create the test frame
frame = wx.Frame(None, title="test frame", size=(500, 500))
# create a simple boxsizer
sizer = wx.BoxSizer()
# create the object that we'll be dynamically adjusting
st = wx.StaticText(frame, label="Click me")
st.SetFont(wx.Font(30, 74, 90, wx.FONTWEIGHT_BOLD, True, "Arial Rounded"))
# align the text to the middle initially
sizer.Add(st, 0, wx.ALIGN_CENTER_VERTICAL)
frame.SetSizer(sizer)
# bind to an arbitrary event
st.Bind(wx.EVT_LEFT_DOWN, on_click)
# do the initial layout and show the frame
frame.Layout()
frame.Show()
app.MainLoop()
def on_click(event):
event.Skip()
# retrieving the static text object
st = event.GetEventObject() # type: wx.StaticText
# get the sizer that contains this object
sizer = st.GetContainingSizer() # type: wx.BoxSizer
# find the sizer item
# the sizer item holds the alignment information and tells
# the sizer how to display this object
sizer_item = sizer.GetItem(st) # type: wx.SizerItem
# alternate between aligning at the top & bottom
if sizer_item.GetFlag() & wx.ALIGN_BOTTOM:
print("Setting alignment to top")
sizer_item.SetFlag(wx.ALIGN_TOP)
else:
print("Setting alignment to bottom")
sizer_item.SetFlag(wx.ALIGN_BOTTOM)
# call Layout to recalculate the object positions
sizer.Layout()
if __name__ == "__main__":
try:
run()
except:
traceback.print_exc()
input()
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...
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)
...
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.