wxPython: Making a scrollable DC - python

I am drawing inside a wx.Window using a PaintDC. I am drawing circles and stuff like that into that window. Problem is, sometimes the circles go outside the scope of the window. I want a scrollbar to automatically appear whenever the drawing gets too big. What do I do?

Use a wx.ScrolledWindow and set the size of the window as soon as your 'drawing go outside' the window with
SetVirtualSize(width,height)
If this size is bigger than the client size, then wx will show scrollbars. When drawing in the window make sure to use CalcUnscrolledPosition and CalcScrolledPosition
Here you can find some more information.

Related

How to move canvas drawn shapes to have a fixed position on screen?

I have a GUI that I've made in tkinter using a canvas that has a bar along the left side and a bar along the top containing information. In the remaining area various rectangles are drawn corresponding to the information in those bars I described. The issue is, when you scroll away on the canvas, those events will leave as well.
Basically, I want to create a visual effect like position: fixed is in CSS where these bars on the side and the top stay in place relative to the rest of the canvas so that they don't move from their relative position while scrolling.
I tried making use of the scrollbar commands, but have had trouble making my own function there. I also tried to see if there was an event I could bind to the canvas to track the movement so that I could move the bars myself but I could not find anything.
There is no way to do this directly in the canvas unless you write the code to move the items in the top and left whenever the user scrolls. It would probably require a fair amount of work.
However, it's trivial to have separate canvases for the side and top that do not scroll, and a third canvas that has all of the scrolled data.
I was able to end up solving my own issue by adapting the solution from: How can I add Unscrollable Image to a frame/Canvas?
Simply put, I made my own yview and xview functions that would scroll my desired "bars" with the window by moving the objects.
Special thanks to #jasonharper for his help.

resize all contents of window?

I'm making a game with Tkinter canvas, and I'm planning to expand it (for UI) using grid.
Problem I'm facing is, that as it is, game window takes up bit more than the height of my screen. If I add anything on top, some parts will be completely off-screen. I can not change resolution of the canvas, as some parts move on pixel-basis. Thus I want to change size of the whole 'image' that Tkinter renders(canvas + other possible labels), that is the whole window.
Is there a way to do so?
window snapshot for reference

wxPython Slider background colour incomplete change

wxPython 2.8.10, Python 2.6.2, Windows 7 x64
So I am having a bit of a wxPython issue I am hoping someone can say where I am going wrong. In my application I have Sliders where the background colour changes as you move the slider around. I do this via SetBackgroundColour from within a EVT_SLIDER handler. It mostly works, but I end up with a border of unchanged colour around the outer edge of the widget.
I have tried Refresh up the chain, RefreshRect on the top level Frame around the widget (and a few pixels further out), various combinations of Update and Layout, but nothing seems to erase it. The best I have managed is if I use something like:
frame = wx.GetTopLevelParent(slider)
rect = slider.GetRect()
slider.ClearBackground()
slider.SetBackgroundColour(wx.Colour(red,green,blue))
frame.RefreshRect(rect)
It will correctly draw the background box with the new colour without the border issue, but it will not repaint the slider itself.
However, if I click away so the focus is elsewhere, the border snaps to the new colour.
I could probably use an overlay or custom paint function but I am hoping there is something I am missing here that will get me the desired results.
Any suggestions?
(edited to add)
Looks like resizing the window manually corrects the issue, but Layout() does not.
It also functions correctly if you do the client size trick:
w,h = slider.GetClientSize()
slider.SetClientSize( (w+1,h) )
slider.SetClientSize( (w,h) )

python tkinter canvas 'transparent'

I think transparent is the right word I'm looking for. Hopefully my description will explain it properly no matter what.
I have a graph of time based data going back decades. Pretty much simply setup to show one day per x-pixel, unless zoomed in closer. I would like to have a box, maybe along the lines of 5x100, appear on top of the graph so when I move the mouse over the graph the box will move and keep pace with the mouse. Anotherwords showing what was happening in the 5 furthest days 'x number of days prior'. Anotherwords when computing an average going forward what are the next values to be falling off as new data arrives. Naturally I want the underlying graphed data to be displayed with the transparent box on top of it outlining the days in question. This may get crazy enough to be a much wider box with two areas that are colored light grey or something like that to show the areas in question but the colored areas are separated by numerous days(could be multiple transparent windows that are tracked together as well. Is this feasible with tkinter? From the research I've been doing it's questionable if using
root.attributes('alpha', .30)
would work or not. It doesn't sound like I could do something like as it would end up making the graph transparent to whatever is underneath it.
self.Graph.create_line()
self.Box.attributes('alpha', .30)
If I understand correctly I have to use
attributes
right at the root level versus the individual 'window' level so the above (severely chopped down) code wouldn't work...or would it. I haven't had a chance to try anything out yet to see what happens...that will be later on this evening. Kinda hoping to save myself a little time by asking now and you never know who else may need the help sometime.
If I understand what you're trying to do, it's going to be pretty hard.
Setting window attributes works just fine to make a window transparent. You've got a minor problem in the code—attributes start with a hyphen—but otherwise you've got it right:
self.Box.attributes("-alpha", .30)
However, it sounds like you want that Box to be an embedded part of the graph window, not its own top-level window that can be dragged around by the user, etc. Unfortunately, Tkinter does not have any notion of child windows, and it doesn't expose nearly enough of the native stuff you'd need to fake them by creating an immobile window and manually moving it to track the movements of another window. So, you don't have a window, which means you don't have window transparency.
The obvious thing for Box to be is some kind of widget, like a Frame or Canvas. But widgets don't have transparency.
Box could instead be just a collection of elements drawn onto the same Canvas as the Graph. That seems promising… but none of the Canvas methods handle alpha transparency. (Some of them do handle all-or-nothing transparency, but that doesn't help.)
One thing that does handle transparency is PhotoImage. So, if you draw Box off-screen, get the resulting contents as a PhotoImage, add the alpha (e.g., via PIL), then create_image the result… close, but no cigar. Depending on the settings of the underlying Tk library, Tkinter may just draw the pixmap with 1-bit transparency or ignore transparency completely. (Experiment with loading alpha-transparent PNG files in PIL and drawing them on a Canvas.) So, unless you want an app that looks right on some systems, doesn't draw the Box at all on others, and draws it opaque on others, this is a dead end.
So, what's left? Only manual compositing: Draw the Graph and the Box on separate off-screen windows, get the pixmaps, use PIL to compose them, and create_image the result.
At which point you're probably better off just using something like PIL's ImageDraw or a more powerful library to construct the pixmap in the first place. Or, of course, using a more powerful GUI library than Tk, like Qt or wx.
Maybe this can give you some ideas to play with:
from tkinter import *
root = Tk()
c = Canvas(root, width=640, height=480, bd=0, highlightthickness=0)
c.create_line(0,240,640,240, fill='blue')
c.pack()
#pil image with transparency
try:
from PIL import Image, ImageTk
except ImportError:
pass
else:
pim = Image.new('RGBA', (5,100), (0,255,0,64))
photo = ImageTk.PhotoImage(pim)
c.create_image(200,200, image=photo, anchor='nw')
#blank standard photoimage with red vertical borders
im = PhotoImage(width=7, height=480)
dat = ('red',)*480
im.put(dat, to=(0,0))
im.put(dat, to=(6,0))
box = c.create_image(0, 0, image=im, anchor='nw')
def on_motion(event):
left,top = c.coords(box)
dx = event.x - (left+7)
c.move(box, dx, 0)
c.bind('<Motion>', on_motion)
root.mainloop()

Can I draw on top of a canvas inside of another canvas?

I am creating a Solitaire clone using Python's Tkinter window toolkit. My window contains a main canvas, and within the main canvas a series of widgets that inherit from Canvas that hold the cards. I have implemented a "Drag to Move" system where a user can click the mouse down to select a card in one of the inner canvases, drag it to a new canvas, and let go to place the card into the receiving canvas.
The Problem: I want to draw the cards in motion between the canvas on which they are drawn, and the canvas they are moving to, so the user can see them moving across the screen during the click and drag motion. When I try to draw cards in-between the canvases that I already have, they are always drawn behind, meaning I can only see cards through the padding around the inner canvases.
Here is an example where I drew several of them so the effect could be seen clearly, and the inner canvases are also clearly visible.
What I've Tried: I've tried to move the canvases back using Misc.lower(aCanvas), but i wasn't able to create the desired effect. I've also tried to design a custom overridden cursor, but it seems my cursor size is limited to 32px*32px, which is insufficient for the size of the card images I want to move.
My Question: How can I draw on top of a canvas that is inside of another canvas? If I can't, how would you solve this problem?
You cannot do what you want. Embedded widgets are always above the canvas items.
Why is it that you are embedding canvases insidebcanvases? Why not just use a single canvas?

Categories

Resources