So I'm learning Python and wanted to try some graphics, so I'm giving SFML a try. I wrote the following program and everything seems good, but the window goes black and white after about 6 seconds (but it keeps drawing the sprite). Am I missing something that is causing the window to go "inactive"?
from sfml import sf
from math import *
texture = sf.Texture.from_file('gum.png')
sprite = sf.Sprite(texture)
i = 0
w = sf.RenderWindow(sf.VideoMode(1024, 768), "Sprite Test")
w.clear()
w.active = True
while w.is_open:
i += .1
if i == 180:
i = 0
#w.clear()
sprite.position = (cos(i) * i + 500, sin(i) * i + 350)
w.draw(sprite)
w.display()
You'll have to poll events. Otherwise the window won't respond to your window manager and be considered unresponsive (typically drawn in a different way, e.g. darkened or brighter).
I've never used the SFML bindings (so this might include bugs), but you'll most likely need something like this:
while w.is_open:
while w.poll_event(e):
# handle events here
i += .1
# Here follows your code as-is
w.display()
Related
My goal is to write a script in python that shows how much percent of the desktop is hidden behind all visible windows on top of it, even those not created by the script.
I wrote
import win32api, win32gui
def get_visible_area():
# Get the dimensions of the desktop
desktop_width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
desktop_height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
# Get the list of all open windows
windows = win32gui.GetDesktopWindow()
(child_windows, _) = win32gui.EnumChildWindows(windows)
# Initialize variables to keep track of the visible area
visible_area = desktop_width * desktop_height
total_area = desktop_width * desktop_height
# Iterate through all open windows and subtract their visible area from the total visible area
for window in child_windows:
if win32gui.IsWindowVisible(window):
left, top, right, bottom = win32gui.GetWindowRect(window)
window_width = right - left
window_height = bottom - top
window_area = window_width * window_height
visible_area -= window_area
# Calculate the percentage of the desktop that is hidden behind windows
percentage_hidden = (total_area - visible_area) / total_area * 100
return percentage_hidden
print("Percentage of desktop hidden behind windows:", get_visible_area(), "%")
But it does not take into account that windows overlap each other and it includes all windows somewhere, not only those that cover the desktop and are visible. How to include only those and have a 0-100% value.
I'm trying to figure out how to find the mouse coordinates when clicking on the graph window a few times.
So far I've tried
mx ,my = win.mouseX(), win.mouseY() and it tells me that the Nonetype is not callable. I've seen other posts involving tkinter, but I am not using that library even though I see that it's easier. Some more example code is as follows:
from graphics import *
win = GraphWin("test", 300, 300)
for i in range(3):
win.getMouse()
mx, my = win.mouseX(), win.mouseY()
print(mx,my)
I want the above code to have the user click on the window and print the regarding mouse coordinates. Eventually I want to store these coordinates, but I think I can figure that out.
win.getMouse() returns a Point which you can get coordinates from like this:
from graphics import *
win = GraphWin("test", 300, 300)
for i in range(3):
point = win.getMouse()
mx, my = point.getX(), point.getY()
print(mx,my)
EDIT: I've add the code from the turtle module at the end of this question. I can't see why there is self.screensize(wx-20, wy-20), but I expect that is the source of the issue.
I'm confused by setworldcoordinates() from the Python turtle module. I can't see why my code displays negative x-ccordinates when I click near the left-hand edge of the turtle window, as in the image below.
My code is below. Could someone please explain how to modify it to have the left-hand edge of the window be at exactly x=0?
import turtle
BLOCK_SIZE = 40
BORDER = 5
STAMP_SIZE = 20
ROWS = 10
COLUMNS = 12
def click_handler(x, y):
print(x, y)
screen = turtle.Screen()
screen.setup(COLUMNS * (BLOCK_SIZE + BORDER), ROWS * (BLOCK_SIZE + BORDER))
screen.setworldcoordinates(0, 0, screen.window_width(), screen.window_height())
screen.onclick(click_handler)
setworldcoordinates definition from turtle module:
def setworldcoordinates(self, llx, lly, urx, ury):
"""Set up a user defined coordinate-system.
Arguments:
llx -- a number, x-coordinate of lower left corner of canvas
lly -- a number, y-coordinate of lower left corner of canvas
urx -- a number, x-coordinate of upper right corner of canvas
ury -- a number, y-coordinate of upper right corner of canvas
Set up user coodinat-system and switch to mode 'world' if necessary.
This performs a screen.reset. If mode 'world' is already active,
all drawings are redrawn according to the new coordinates.
But ATTENTION: in user-defined coordinatesystems angles may appear
distorted. (see Screen.mode())
Example (for a TurtleScreen instance named screen):
>>> screen.setworldcoordinates(-10,-0.5,50,1.5)
>>> for _ in range(36):
... left(10)
... forward(0.5)
"""
if self.mode() != "world":
self.mode("world")
xspan = float(urx - llx)
yspan = float(ury - lly)
wx, wy = self._window_size()
self.screensize(wx-20, wy-20)
oldxscale, oldyscale = self.xscale, self.yscale
self.xscale = self.canvwidth / xspan
self.yscale = self.canvheight / yspan
srx1 = llx * self.xscale
sry1 = -ury * self.yscale
srx2 = self.canvwidth + srx1
sry2 = self.canvheight + sry1
self._setscrollregion(srx1, sry1, srx2, sry2)
self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
self.update()
There are three sizes to consider: size of the window on the screen; size of the visible area of the window we can draw on; size of the window's canvas backing store that we can scroll. I believe you can adjust the third using turtle's screensize() method.
Between the size of the window on the screen and the the size of the visible drawing area sits the chrome, the window's overhead of borders and border shadows, etc. It seems like turtle is simply estimating these instead of calculating them based on window system characteristics:
self.screensize(wx-20, wy-20)
This uncommented magic -20 appears nowhere else in the turtle code. I'd guess the tkinter underpinnings could provide an exact value.
The two problems I see are that turtle's estimate can be off and onclick() is registering clicks on a portion of the chrome (on my system), which doesn't make sense. The best I could come up with is compounding it with an estimated correction:
from turtle import Screen
BLOCK_SIZE = 40
BORDER = 5
ROWS = 10
COLUMNS = 12
WIDTH = COLUMNS * (BLOCK_SIZE + BORDER)
HEIGHT = ROWS * (BLOCK_SIZE + BORDER)
CHROME = 7 # correction guesstimate for OS X
def click_handler(x, y):
print(x, y)
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.setworldcoordinates(CHROME, CHROME, WIDTH, HEIGHT)
screen.onclick(click_handler)
screen.mainloop()
If you click on the left or bottom chrome, you should get values < zero (I won't say negative as -0.0 turns up here) until you click on the drawable part of the window. The right and top will produce values greater than the calculated width and height if you click on the chrome, but within them otherwise.
Again, I believe the real solution lies in turtle's tkinter underpinnings.
Hopefully I'll be able to explain this well. I'm currently using helper functions to draw a six-pointed star in the turtle graphics window of python. First, we had to create a function to draw a triangle. Here is my code:
import turtle
wn = turtle.Screen()
tess = turtle.Turtle()
tess.speed(30)
def triangle(sz):
for i in range(3):
tess.fd(sz)
tess.lt(120)
Then, we had to use the triangle function to draw a six-pointed star. Here is my code:
def sixPtdStar(sz):
triangle(sz)
tess.lt(90)
tess.pu()
tess.fd(80)
tess.rt(90)
tess.fd(120)
tess.pd()
tess.rt(180)
triangle(sz)
Now, for me, this all runs smoothly. But the parameters for our test run of those two functions was that sz = 120 (so in the shell we'd type sixPtdStar(120) and it would run. But then we had to draw a row of stars with a new function, and then a BOX outline by those rows of stars, in another function. Here is my code:
def rowOfStars(numInRow,sz):
for i in range(numInRow):
sixPtdStar(sz)
tess.pu()
tess.lt(90)
tess.fd(80)
tess.lt(90)
def sqrOfRows(numInRow, sz):
for i in range(4):
rowOfStars(numInRow, sz)
tess.rt(90)
While this accomplishes the task, it only does so if the sz = 120. And for our test run on the rowOfStars function, the parameters are supposed to be (6, 72) and for the test run on the sqrOfRows function, our parameters are supposed to be (6, 36).
So my issue is this. How can I make this work no matter what sz equals? When I run it as is (with (6, 72) for rowOfStars or (6, 36) for sqrOfRows), the pen moves too far because the triangles aren't as big anymore.
Please let me know if more info is needed! Thanks! (I'm using Python 3.5.2)
Anywhere you use a unit that has a dimension:
tess.fd(80)
tess.fd(120) # probably should be tess.fd(sz)
tess.fd(80)
you need to scale it by what ever logic you used to get from 120 (sz) to 80. However, as #wptreanor mentioned, that logic is slightly flawed as the points on your star are uneven:
Also, your rowOfStars() routine doesn't really draw a row of stars (math is off and the pen is in the wrong state at times.) Simply fixing the scaling won't fix this. Finally, your sqrOfRows() routine won't work until rowOfStars() is fixed, and to make it useful, you need to adjust the starting position on the screen to make room for the drawing.
Below is my rework of your code to address some of these issues. It uses a slightly different calculation of how to position from finishing the lower to starting the upper triangle so the numbers are slightly different:
from turtle import Turtle, Screen
WIDTH_RATIO = 2 * 3**0.5 / 3 # ratio of widest point in star to edge of triangle
def triangle(size):
for i in range(3):
tess.fd(size)
tess.lt(120)
def sixPtdStar(size):
triangle(size)
tess.lt(30)
tess.pu()
tess.fd(size * WIDTH_RATIO)
tess.lt(150)
tess.pd()
triangle(size)
def rowOfStars(numInRow, size):
for i in range(numInRow):
sixPtdStar(size)
tess.pu()
tess.lt(90)
tess.fd(size * WIDTH_RATIO / 2)
tess.lt(90)
tess.pd()
def sqrOfRows(numInRow, size):
tess.pu()
halfSize = numInRow * size / 2
tess.goto(-halfSize, halfSize) # center on screen
tess.pd()
for i in range(4):
rowOfStars(numInRow, size)
tess.rt(90)
screen = Screen()
tess = Turtle()
tess.speed("fastest") # numbers > 10 are all equivalent, safer to use symbols
sqrOfRows(6, 36)
screen.exitonclick()
The problem is in your sixPtdStar() function.
def sixPtdStar(sz):
triangle(sz)
tess.lt(90)
tess.pu()
tess.fd(80) # here
tess.rt(90)
tess.fd(120) # and here
tess.pd()
tess.rt(180)
triangle(sz)
If your function takes a size as a parameter, all functions involving movement (such as forward() or goto()) need to be scaled by the size as well. The following code should work:
def sixPtdStar(sz):
triangle(sz)
tess.lt(90)
tess.pu()
tess.fd((2.0/3.0)*sz) #formerly 80
tess.rt(90)
tess.fd(sz) #formerly 120
tess.pd()
tess.rt(180)
triangle(sz)
This will ensure that all forward movements are proportional to the size of the object you create. You will need to make similar tweaks to your rowOfStars() function. I've also noticed that your six pointed star isn't fully symmetrical. You could resolve that by replacing tess.fd((2.0/3.0)*sz) with tess.fd((7.0/12.0)*sz).
I need to find window position and size, but I cannot figure out how. For example if I try:
id.get_geometry() # "id" is Xlib.display.Window
I get something like this:
data = {'height': 2540,
'width': 1440,
'depth': 24,
'y': 0, 'x': 0,
'border_width': 0
'root': <Xlib.display.Window 0x0000026a>
'sequence_number': 63}
I need to find window position and size, so my problem is: "y", "x" and "border_width" are always 0; even worse, "height" and "width" are returned without window frame.
In this case on my X screen (its dimensions are 4400x2560) I expected x=1280, y=0, width=1440, height=2560.
In other words I'm looking for python equivalent for:
#!/bin/bash
id=$1
wmiface framePosition $id
wmiface frameSize $id
If you think Xlib is not what I want, feel free to offer non-Xlib solution in python if it can take window id as argument (like the bash script above). Obvious workaround to use output of the bash script in python code does not feel right.
You are probably using reparenting window manager, and because of this id window has zero x and y. Check coordinates of parent window (which is window manager frame)
Liss posted the following solution as a comment:
from ewmh import EWMH
ewmh = EWMH()
def frame(client):
frame = client
while frame.query_tree().parent != ewmh.root:
frame = frame.query_tree().parent
return frame
for client in ewmh.getClientList():
print frame(client).get_geometry()
I'm copying it here because answers should contain the actual answer, and to prevent link rot.
Here's what I came up with that seems to work well:
from collections import namedtuple
import Xlib.display
disp = Xlib.display.Display()
root = disp.screen().root
MyGeom = namedtuple('MyGeom', 'x y height width')
def get_absolute_geometry(win):
"""
Returns the (x, y, height, width) of a window relative to the top-left
of the screen.
"""
geom = win.get_geometry()
(x, y) = (geom.x, geom.y)
while True:
parent = win.query_tree().parent
pgeom = parent.get_geometry()
x += pgeom.x
y += pgeom.y
if parent.id == root.id:
break
win = parent
return MyGeom(x, y, geom.height, geom.width)
Full example here.
In the same idea as #mgalgs, but more direct, I ask the root window to translate the (0,0) coordinate of the target window :
# assuming targetWindow is the window you want to know the position of
geometry = targetWindow.get_geometry()
position = geometry.root.translate_coords(targetWindow.id, 0, 0)
# coordinates are in position.x and position.y
# if you are not interested in the geometry, you can do directly
import Xlib.display
position = Xlib.display.Display().screen().root.translate_coords(targetWindow.id, 0, 0)
This gives the position of the client region of the targeted window (ie. without borders, title bar and shadow decoration created by the window manage). If you want to include them, replace targetWindow with targetWindow.query_tree().parent (or second parent).
Tested with KUbuntu 20.04 (ie KDE, Plasma and KWin decoration).