building gui using wxpython - user-interface

I added an image into a panel in my gui . I want this image to be fitted in the panel, where i wanna make its length as same as the panel legth .. How can i do this please ?
i did the following in my code ? so the image appeared at the top of the panel as what i want, but i wanna resize this image to increase its length .
class myMenu(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(900, 700))
panel = wx.Panel(self, -1)
panel.SetBackgroundColour('#4f3856')
img = 'C:\Users\DELL\Desktop\Implementation\img1.jpg'
bmp = wx.Bitmap(img)
btmap = wx.StaticBitmap(panel, wx.ID_ANY, bmp, (0, 0))

If you want to scale the image you'll probably want to open it as a wx.Image rather than a wx.Bitmap. You can then scale it using the wx.Image's scale(self, width, height, quality) method http://www.wxpython.org/docs/api/wx.Image-class.html#Scale
The real problem is you want to get the image to resize every time the window does. That means you'll need to bind the wx.EVT_SIZE event to some method in your class (say onSize). Then every time onSize is called, you'll need to:
Find the current window size,
Scale the wx.Image to that size,
Convert it to a wx.Bitmap using wx.BitmapFromImage,
Call SetBitmap on your wx.StaticBitmap, passing the new bitmap.
See http://zetcode.com/wxpython/events/ for a basic introduction to event handling in wxPython, including an example with the wx.EVT_SIZE.

Related

Creating a fixed background using tkinter

I am using tkinter when and trying to set up a window with a background image. In some of the processes I have a frame that fills up with checkboxes so I created a scrollbar so the user can see all the options. The problem is the scroll bar also moves the background image of the canvas. Is there a way I can fix the image to not move or somehow move the frame by itself.
code is
def canvasScroll():
canvas = gui.createCanvas()
fFrame = gui.createNewFrame()
scrollbar = Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand = scrollbar.set)
scrollbar.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand= True)
canvas.create_window((150,50),window = fFrame, anchor='nw', tags = "frame")
gOb.change_canvas(canvas)
fFrame.bind("<Configure>", gui.scroll)
gOb.change_scrollbar(scrollbar)
gOb.change_frame(fFrame)
def createCanvas():
canvas = Canvas(root,height = _h, width = _w,highlightthickness = 0)
canvas.pack(side='top',fill='both',expand='yes')
canvas.create_image(-200,-200,image=bground,anchor='nw')
return canvas
def createNewFrame():
frame = Frame(root,height = _h, width = _w,background='white')
frame.pack()
return frame
Just to clear things up, these guys are all part of a class name gui and gOb is an object that hold several gui objects.
Here's one idea - it's kind of kludgy, but it would work. Every time the scrollbar scrolls, shift the background image's position so it appears to stay in the same place:
Tag your image so you can access it later:
canvas.create_image(-200,-200,image=bground,anchor='nw',tags="background")
# ^^^^^^^^^^^^^^^^^
Make your scrollbar call a function that you define:
scrollbar = Scrollbar(root, orient="vertical", command=scrollCallback)
Define your scroll callback:
def scrollCallback(*args):
canvas.yview(*args)
# Arrange for your background image to move so it appears to stay in the same position as the canvas scrolls.

images in layers with movement and transparency - wxpython

It might sound unproper 'images in layers' like in Photoshop but in fact that is what I have and would like to make working.
I use a set of wx.boxsizer's to have a nice&organized screen after launching my program.
In one row of Horizontal wx.BoxSizer's I have 3 columns done with different wx.Panels and each of that is containing moving wx.StaticBitmaps done by a Timer function.
The second wx.Panel which is in the middle with 0 proportion to mantain original panel size contains 2 images actually, one PNG with transparency and the moving wx.StaticBitmap which should be the background for this PNG.
This is not working out for me. I simply want that the PNG to be over the other image which is moved by the timer. 2 layers if you like.
It is creating a nice very simple and basic action effect (like the object in the PNG is running)
Now I thought of a few ways to go about this but none of them worked:
Figure out how python decides which image to bring in front and which would stay behind. Manipulate that
Keep the moving image in the sizer and take out the PNG and place it over the moving image (than I need to dynamically determine where is that moving image)
Make the moving image the wx.panel background and then probably I can simply call the transparent PNG over it.
I will paste here a part of my script for the brave eyes:
class AnimationPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.loc = wx.Image("intro/runner.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()
self.locpic = wx.StaticBitmap(self, -1, self.loc, (0, 0), (self.loc.GetWidth(), self.loc.GetHeight()))
self.xer = 3080
self.xer2 = 2310
self.xer3 = 1540
self.env = wx.Image("intro/environ1.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()
self.env2 = wx.Image("intro/environ2.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()
self.env3 = wx.Image("intro/environ3.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap()
self.picture = wx.StaticBitmap(self, -1, self.env, (0, 0), (self.env.GetWidth(), self.env.GetHeight()))
self.picture2 = wx.StaticBitmap(self, -1, self.env2, (770, 0), (self.env2.GetWidth(), self.env2.GetHeight()))
self.picture3 = wx.StaticBitmap(self, -1, self.env3, (1540, 0), (self.env3.GetWidth(), self.env3.GetHeight()))
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.timer.Start(5)
def OnTimer(self, event):
if self.xer <= 3080:
self.xer += 1
self.picture.Move((self.xer,0))
else:
self.xer = -770
if self.xer2 <= 3080:
self.xer2 += 1
self.picture2.Move((self.xer2,0))
else:
self.xer2 = -770
if self.xer3 <= 3080:
self.xer3 += 1
self.picture3.Move((self.xer3,0))
else:
self.xer3 = -770
This is in the main frame:
ap = AnimationPanel(self)
v2box = wx.BoxSizer(wx.HORIZONTAL)
v2box.Add(someother, 1, wx.EXPAND)
v2box.Add(ap, 0, wx.EXPAND)
v2box.Add(someother, 1, wx.EXPAND)
I did put research in this but I'm quite of a beginner so please help me out with some simple tips or suggestions if it's possible.
Thanks.
In the wxpython demo install there is a samples folder that has a pySketch demo.
In this code it creates dc drawn objects that can be moved in front and behind other objects.
A quick look over this code it looks like the drawn items are stored in a list and then drawn in the list order.
I guess that's how you would implement your layering, you would have a list of layers and in each layer you would store your items for that layer.

Sizing a frame to an image in WxPython

I'm making a program with an image for a backdrop, and what I'm trying to do is get the frame to fit the image precisely.
It's easy to initiate the frame with the dimensions of the image:
wx.Frame.__init__(self, parent, title=title, size=(500, 300))
but because this also accounts for the borders and header of the window, this isn't entirely accurate. Short of manually adjusting the pixel size (which wouldn't be consistent cross-OS anyway), what can I do?
Edit: I've found an answer, but it looks like I can't self-answer for a few hours. In the meantime...
Backdrop = wx.Bitmap("image.png")
self.SetClientSize((Backdrop.GetWidth(), Backdrop.GetHeight()))
You could accomplish the same thing with a sizer, which would also make things easier if you ever need to include other items alongside the image and control how they scale with the frame.
Here's a basic example of a frame that resizes itself to fit an image.
import wx
class Frame(wx.Frame):
def __init__(self, parent, id, title, img_path):
wx.Frame.__init__(self, parent, id, title,
style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
image = wx.StaticBitmap(self, wx.ID_ANY)
image.SetBitmap(wx.Bitmap(img_path))
sizer = wx.BoxSizer()
sizer.Add(image)
self.SetSizerAndFit(sizer)
self.Show(True)
app = wx.App()
frame = Frame(None, wx.ID_ANY, 'Image', '/path/to/file.png')
app.MainLoop()

Convert a given point from the window’s base coordinate system to the screen coordinate system

I am trying to figure out the way to convert a given point from the window’s base coordinate system to the screen coordinate system. I mean something like - (NSPoint)convertBaseToScreen:(NSPoint)point.
But I want it from quartz/carbon.
I have CGContextRef and its Bounds with me. But the bounds are with respect to Window to which CGContextRef belongs. For Example, if window is at location (100, 100, 50, 50) with respect to screen the contextRef for window would be (0,0, 50, 50). i.e. I am at location (0,0) but actually on screen I am at (100,100). I
Any suggestion are appreciated.
Thank you.
The window maintains its own position in global screen space and the compositor knows how to put that window's image at the correct location in screen space. The context itself, however doesn't have a location.
Quartz Compositor knows where the window is positioned on the screen, but Quartz 2D doesn't know anything more than how big the area it is supposed to draw in is. It has no idea where Quartz Compositor is going to put the drawing once it is done.
Similarly, when putting together the contents of a window, the frameworks provide the view system. The view system allows the OS to create contexts for drawing individual parts of a window and manages the placement of the results of drawing in those views, usually by manipulating the context's transform, or by creating temporary offscreen contexts. The context itself, however, doesn't know where the final graphic is going to be rendered.
I'm not sure if you can use directly CGContextRef, you need window or view reference or something like do the conversion.
The code I use does the opposite convert mouse coordinates from global (screen) to view local and it goes something like this:
Point mouseLoc; // point you want to convert to global coordinates
HIPoint where; // final coordinates
PixMapHandle portPixMap;
// portpixmap is needed to get correct offset otherwise y coord off at least by menu bar height
portPixMap = portPixMap = GetPortPixMap( GetWindowPort( GetControlOwner( view ) ) );
QDGlobalToLocalPoint(GetWindowPort( GetControlOwner( view ), &mouseLoc);
where.x = mouseLoc.h - (**portPixMap).bounds.left;
where.y = mouseLoc.v - (**portPixMap).bounds.top;
HIViewConvertPoint( &where, NULL, view );
so I guess the opposite is needed for you (haven't tested if it actually works):
void convert_point_to_screen(HIView view, HIPoint *point)
{
Point point; // used for QD calls
PixMapHandle portPixMap = GetPortPixMap( GetWindowPort( GetControlOwner( view ) ) );
HIViewConvertPoint( &where, view, NULL ); // view local to window local coordtinates
point.h = where->x + (**portPixMap).bounds.left;
point.w = where->y + (**portPixMap).bounds.top;
QDLocalToGlobalPoint(GetWindowPort( GetControlOwner( view ), &point);
// convert Point to HIPoint
where->x = point.h;
where->y = point.v;
}

Speed up image display

I am using the PIL (python image library) to crop a very large image and present the cropped area to the interface. The problem Im having is that the process is taking too long. When the user clicks on the image to crop it, the image takes quite a long time to show up on the sizer I attach it to.
I tried doing this two ways: First I tried saving the cropped area as an image to the disk, and loaded it on the fly into the sizer. The second attempt was to create an empty image and convert the pil image into the wx image and load that onto the sizer. Surprising to me is that the first method of writing to the disk feels faster than the second method of managing it in memory. Here are the code samples:
First method:
area = image_object.crop(self.cropxy)
area.save(CROP_IMAGE, 'jpeg')
crop_image = wx.Image(CROP_IMAGE, wx.BITMAP_TYPE_JPEG).ConvertToBitmap()
crop_bitmap = wx.StaticBitmap(self.crop_panel, bitmap=crop_image, name="Cropped Image")
crop_bitmap.CenterOnParent()
crop_bitmap.Refresh()
Second method:
area = image_object.crop(self.cropxy)
image = wx.EmptyImage(area.size[0], area.size[1])
image.SetData(area.convert("RGB").tostring())
crop_image = wx.BitmapFromImage(image)
crop_bitmap = wx.StaticBitmap(self.crop_panel, bitmap=crop_image, name="Cropped Image")
crop_bitmap.CenterOnParent()
crop_bitmap.Refresh()
Is there a better way to do this so that the image will now show up so slowly?
So in order to solve something somewhere else in the interface, when I queue up my images I decided to pre-load the wxImage objects. Never had to before when they were much smaller.
Anyway - I found some code on google that would allow me to convert between wxImage objects and PIL objects and by doing so, I can convert the in-memory wxImage object to the PIL object, crop it, and convert it back to the image just in time to display it. This is 'Blazing' fast by comparison. You just hardly take your finger off the mouse and the crop shows just fine.
Here are the conversion routines:
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 image_to_pil(self, image):
""" Method will convert wx.Image to PIL Image """
pil = Image.new('RGB', (image.GetWidth(), image.GetHeight()))
pil.fromstring(image.GetData())
return pil

Resources