What I want to do is simply add pixels to the top of any window I choose with setpixel.
But the problem is that I couldn't find any resources on this subject.
The pixels I add in win32gui.setpixel appear either in the python terminal or on the desktop but they are not visible above chrome, for example.
How can I add pixels above everything or certain tabs?
import win32gui, time
import os
cls = lambda: os.system('cls')
cls()
print("Hazır.")
while True:
x=int(960) # 1920 / 2 = 960 for X position on screen.
y=int(600) # 1200 / 2 = 600 for Y position on screen.
color=int(255) # Pixel color, 255 = Red
hwnd=win32gui.WindowFromPoint((x,y))
hdc=win32gui.GetDC(hwnd)
x1,y1=win32gui.ScreenToClient(hwnd,(x,y))
win32gui.SetPixel(hdc,x1,y1,color)
win32gui.SetPixel(hdc,x1-1,y1,color)
win32gui.SetPixel(hdc,x1+1,y1,color)
win32gui.SetPixel(hdc,x1,y1-1,color)
win32gui.SetPixel(hdc,x1,y1+1,color)
win32gui.SetPixel(hdc,x1-1,y1-1,color)
win32gui.SetPixel(hdc,x1+1,y1+1,color)
win32gui.SetPixel(hdc,x1-1,y1+1,color)
win32gui.SetPixel(hdc,x1+1,y1-1,color)
win32gui.SetPixel(hdc,x1-2,y1,color)
win32gui.SetPixel(hdc,x1+2,y1,color)
win32gui.SetPixel(hdc,x1,y1-2,color)
win32gui.SetPixel(hdc,x1,y1+2,color)
win32gui.SetPixel(hdc,x1-2,y1-2,color)
win32gui.SetPixel(hdc,x1+2,y1+2,color)
win32gui.SetPixel(hdc,x1-2,y1+2,color)
win32gui.SetPixel(hdc,x1+2,y1-2,color)
win32gui.ReleaseDC(hwnd,hdc)
time.sleep(0.1)
Related
I'm trying to use skia-python with glfw to draw various shapes and text onto a transparent floating overlay. I have a small demo working for my purposes, but it behaves differently if the window is created with full screen resolution versus created with anything smaller.
The code here alternates between drawing some red text or a green circle, and attempts to clear the canvas in between using canvas.clear(skia.ColorTRANSPARENT). This behaves exactly as I want if the window is created with dimensions anything less than 1920x1080 (the resolution of my screen). If I create the window with these full screen dimensions, instead of clearing the canvas this call fills the screen with black (and then the rest of the code still works, alternating between text and circle).
import contextlib, glfw, skia
from OpenGL import GL
import time
WIDTH, HEIGHT = 1920, 1080
#WIDTH, HEIGHT = 1919, 1079
#contextlib.contextmanager
def glfw_window():
if not glfw.init():
raise RuntimeError('glfw.init() failed')
glfw.window_hint(glfw.STENCIL_BITS, 8) # ?
glfw.window_hint(glfw.SAMPLES, 14) # ?
glfw.window_hint(glfw.DECORATED, 0)
glfw.window_hint(glfw.TRANSPARENT_FRAMEBUFFER, 1)
glfw.window_hint(glfw.FLOATING, 1)
window = glfw.create_window(WIDTH, HEIGHT, '', None, None)
glfw.make_context_current(window)
yield window
glfw.terminate()
#contextlib.contextmanager
def skia_surface(window):
context = skia.GrDirectContext.MakeGL()
(fb_width, fb_height) = glfw.get_framebuffer_size(window)
backend_render_target = skia.GrBackendRenderTarget(
fb_width,
fb_height,
0, # sampleCnt
0, # stencilBits
skia.GrGLFramebufferInfo(0, GL.GL_RGBA8))
surface = skia.Surface.MakeFromBackendRenderTarget(
context, backend_render_target, skia.kBottomLeft_GrSurfaceOrigin,
skia.kRGBA_8888_ColorType, skia.ColorSpace.MakeSRGB())
assert surface is not None
yield surface
context.abandonContext()
def drawString(canvas):
paint = skia.Paint(AntiAlias=True, Color=skia.ColorRED)
font = skia.Font(skia.Typeface('meiryo'), 36)
canvas.drawString('あかさたな', 100, 100, font, paint)
def drawCircle(canvas):
paint = skia.Paint(Color=skia.ColorGREEN)
canvas.drawCircle(100, 100, 40, paint)
with glfw_window() as window:
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
with skia_surface(window) as surface:
with surface as canvas:
while (glfw.get_key(window, glfw.KEY_ESCAPE) != glfw.PRESS
and not glfw.window_should_close(window)):
canvas.clear(skia.ColorTRANSPARENT)
if int(time.time()) % 2 == 0:
drawString(canvas)
else:
drawCircle(canvas)
surface.flushAndSubmit()
glfw.swap_buffers(window)
glfw.poll_events()
#glfw.wait_events()
For the purpose of demonstration, this is the entire working demo. Most of it comes from this skia-python documentation. I think the only packages it needs are glfw (2.5.3), PyOpenGl (3.1.6), and skia-python (87.4)
My actual use case will use a slightly different loop and doesn't need to draw to the screen as frequently as this demo, but it does need to periodically clear the canvas. I don't actually need it to be perfectly full screen, I can use 1919x1079, mostly I'm just curious what's going on here. This is being tested on Windows 10 with Python 3.10 by the way
I am trying to use PyQt5 to draw a round gauge (MacOS 11.0.1, Python 3.9).
I used the drawArc statement to created the gauge background, so I set the pen width to a large value (70). The resulting arc looks like a horseshoe, presumably because the "pen" is a 70 pixels square, not a line perpendicular to the direction of travel.
Is there a way of creating an arc - in PyQt5 - like the one on the right side of the picture?
I am open to suggestions: the application has already been written with Python+Tkinter, but thanks to the lack of anti-aliasing on Tkinter+Raspberry, I need re-write it.
(Plan B is to continue with PyQt, create a pie slice (drawPie) and cover the centre area with a circle of background colour - but this is not ideal, as it imposes some limitations to my design.)
# importing libraries
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
arcreading = 0
adder = .1
# creating a Gauge class
class Gauge(QMainWindow):
# constructor
def __init__(self):
super().__init__()
timer = QTimer(self) # create a timer object
timer.timeout.connect(self.update) # add action to the timer, update the whole code
timer.start(0) # update cycle in milliseconds
self.setGeometry(200, 200, 600, 600) # window location and size
self.setStyleSheet("background : black;") # background color
# -----------------------
# method for paint event
# -----------------------
def paintEvent(self, event):
global arcreading
global adder
# print('x')
kanvasx = 50 # binding box origin: x
kanvasy = 50 # binding box origin: y
kanvasheight = 150 # binding box height
kanvaswidth = 150 # binding box width
arcsize = 270 # arc angle between start and end.
arcwidth = 70 # arc width
painter = QPainter(self) # create a painter object
painter.setRenderHint(QPainter.Antialiasing) # tune up painter
painter.setPen(QPen(Qt.green, arcwidth)) # set color and width
# ---------- the following lines simulate sensor reading. -----------
if arcreading > arcsize or arcreading < 0: # variable to make arc move
adder = -adder # arcreading corresponds to the
# value to be indicated by the arc.
arcreading = arcreading + adder
# --------------------- end simulation ------------------------------
#print(arcreading)
# drawArc syntax:
# drawArc(x_axis, y_axis, width, length, startAngle, spanAngle)
painter.drawArc(kanvasx, kanvasy, # binding box: x0, y0, pixels
kanvasheight + arcwidth, # binding box: height
kanvaswidth + arcwidth, # binding box: width
int((arcsize + (180 - arcsize) / 2)*16), # arc start point, degrees (?)
int(-arcreading*16)) # arc span
painter.end() # end painter
# Driver code
if __name__ == '__main__':
app = QApplication(sys.argv)
# creating a Gauge object
win = Gauge()
# show
win.show()
exit(app.exec_())
You need to set the capStyle of the pen with the appropriate Qt.PenCapStyle, in your case you should use FlatCap, which ends exactly at the end of the line, while the default is SquareCap (which covers the end and extends by half the line width):
painter.setPen(QPen(Qt.green, arcwidth, cap=Qt.FlatCap))
I want to be able to change the background color of Python's console (python.exe) to any RGB color.
I know that I can use the color command (documentation link 1 and documentation link 2) to pick the background and foreground (font) colors from 16 available colors:
import os
os.system('color 8f')
I also know that I can manually change the RGB values of those 16 colors by right-clicking the top bar of the console and then clicking in properties and going to the colors' tab.
I would like to know if there's a programmatic solution though, just as there is for changing the font color to an RGB value:
import os
os.system('')
def rgb(red, green, blue):
return f'\x1b[38;2;{red};{green};{blue}m'
red_color = rgb(255, 0, 0)
green_color = rgb(0, 255, 0)
blue_color = rgb(0, 0, 255)
print(f'{red_color}red {green_color}green {blue_color}blue')
I'm asking for the background color of the whole console screen, not the background color of the text. I also don't want to install some different console or a module that somehow does it without understanding how.
I found out that I can use the GetConsoleScreenBufferInfoEx and SetConsoleScreenBufferInfoEx functions to programmatically change the values of any of the 16 colors of the console.
The code below is a combination of the code found in the question and answers:
Why does the console window shrink when using GetConsoleScreenBufferInfoEx in Windows?
Executable called via subprocess.check_output prints on console but result is not returned
Change entire console background color (Win32 C++)
import ctypes
from ctypes import wintypes
import os
import sys
import time
class COORD(ctypes.Structure):
_fields_ = (('X', wintypes.SHORT), ('Y', wintypes.SHORT))
class CONSOLE_SCREEN_BUFFER_INFOEX(ctypes.Structure):
_fields_ = (
('cbSize', wintypes.ULONG),
('dwSize', COORD),
('dwCursorPosition', COORD),
('wAttributes', wintypes.WORD),
('srWindow', wintypes.SMALL_RECT),
('dwMaximumWindowSize', COORD),
('wPopupAttributes', wintypes.WORD),
('bFullscreenSupported', wintypes.BOOL),
('ColorTable', wintypes.DWORD * 16))
def __init__(self, *args, **kwds):
super(CONSOLE_SCREEN_BUFFER_INFOEX, self).__init__(*args, **kwds)
self.cbSize = ctypes.sizeof(self)
def rgb_values_to_integer_color(red, green, blue):
integer_color = red + (green * 256) + (blue * 256 * 256)
return integer_color
STD_OUTPUT_HANDLE = -11
console_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
console_screen_information = CONSOLE_SCREEN_BUFFER_INFOEX()
# get the original color to later set it back
ctypes.windll.kernel32.GetConsoleScreenBufferInfoEx(console_handle, ctypes.byref(console_screen_information))
original_color = console_screen_information.ColorTable[0]
# prevent the console screen's height from shrinking
console_screen_information.srWindow.Bottom += 1
# set the new rgb color
console_screen_information.ColorTable[0] = rgb_values_to_integer_color(red=84, green=170, blue=255)
ctypes.windll.kernel32.SetConsoleScreenBufferInfoEx(console_handle, ctypes.byref(console_screen_information))
# wait 3 seconds
time.sleep(3)
# change back to the original color
console_screen_information.ColorTable[0] = original_color
ctypes.windll.kernel32.SetConsoleScreenBufferInfoEx(console_handle, ctypes.byref(console_screen_information))
The first color (black by default) is the one being changed since it's the default one being used out of the 16 as background color.
If you need to update the screen color for example at the start of a program you can just do os.system('cls') (after SetConsoleScreenBufferInfoEx).
I'm trying to write a simple CLI python text editor using curses module that comes with python. I have everything set up correctly on my Windows 10 box and can do all the tutorials without issue.
I draw in the order, the screen, and windows on the screen with a border less than the screen. Create a window using the border measurements that are in 2 rows, columns in from the outside of the screen. Then I define a text area and create a subwindow.
If I exclude the subwindow, a border is drawn and the cursor placed inside the border. But when I try to save the text by gathering it the text includes the border. So, that is the reason for the subwindow. If he box is larger than subwindow why would the border disappear.
Here is the code:
import curses
import traceback
from curses.textpad import Textbox, rectangle
from pathlib import Path
def draw_menu():
pass
def edit_mode(window):
textbox = Textbox(window)
textbox.edit()
return textbox.gather()
def main(screen):
"""
Get the screen size and set a border around the text area.
Reset the cursor to the top of the text area.
"""
# get the current screen size
y_max, x_max = screen.getmaxyx()
ymin_border, xmin_border, ymax_border, xmax_border = \
2, 2, y_max-2, x_max-2
ymin_textpad, xmin_textpad, ymax_textpad, xmax_textpad = \
ymin_border+1, xmin_border+1, ymax_border-1, xmax_border-1
# draw the windows and box around it. Place cursor at beginning of
# the edit area
window = curses.newwin(ymax_border, xmax_border, ymin_border, xmin_border)
window.box()
# if this line is excluded I see the box but then the box is saved input
text_box = screen.subwin(ymax_textpad, xmax_textpad, ymin_textpad,
xmin_textpad)
window.addstr(ymin_textpad, xmin_textpad, "")
screen.refresh()
text = edit_mode(text_box) # right now drop user into edit mode
return text
if __name__ == "__main__":
buffer = ""
try:
screen = curses.initscr()
curses.noecho()
buffer = main(screen)
curses.echo()
curses.endwin()
print(f"Saved Buffer to Screen\n{buffer}")
except:
curses.echo()
curses.endwin()
traceback.print_exc()
I am beginning to learn Python after being trapped using VB6 forever. To help myself learn some gui with Tkinter, I'm making a simple slot machine. To animate the wheels, I have a ~300x2000 image that has all of the pictures I intend to use displayed as a strip. About 6 pictures right now. I just show part of the image (wheel) at a time to make it spin. Anyway, I'm having trouble with the part of the code where I come to the end of the image and need to transition from the end of the image back to the beginning (wheel spins down, so the start is the bottom and end is the top).
For some reason, I can't get the images to crop and display correctly, even though I think my script makes sense logically. My code is posted below. You can make an image around the resolution of 300x2000 or so to use with this to see the problem I am having. My code starts printing outside of the area that I want it to show (outside the showsize variable) and I can't figure out why.
Any help with this problem would be much appreciated. It seems that the crops don't cut the images short enough, but all the information that I found about it make me think my script should be working just fine. I've tried to annotate my code to explain what's going on.
from Tkinter import *
from PIL import Image, ImageTk
def main():
root = Tk()
root.title = ("Slot Machine")
canvas = Canvas(root, width=1500, height=800)
canvas.pack()
im = Image.open("colors.png")
wheelw = im.size[0] #width of source image
wheelh = im.size[1] #height of source image
showsize = 400 #amount of source image to show at a time - part of 'wheel' you can see
speed = 3 #spin speed of wheel
bx1 = 250 #Box 1 x - where the box will appear on the canvas
by = 250 #box 1 y
numberofspins = 100 #spin a few times through before stopping
cycle_period = 0 #amount of pause between each frame
for spintimes in range(1,numberofspins):
for y in range(wheelh,showsize,-speed): #spin to end of image, from bottom to top
cropped = im.crop((0, y-showsize, wheelw, y)) #crop which part of wheel is seen
tk_im = ImageTk.PhotoImage(cropped)
canvas.create_image(bx1, by, image=tk_im) #display image
canvas.update() # This refreshes the drawing on the canvas.
canvas.after(cycle_period) # This makes execution pause
for y in range (speed,showsize,speed): #add 2nd image to make spin loop
cropped1 = im.crop((0, 0, wheelw, showsize-y)) #img crop 1
cropped2 = im.crop((0, wheelh - y, wheelw, wheelh)) #img crop 2
tk_im1 = tk_im2 = None
tk_im1 = ImageTk.PhotoImage(cropped1)
tk_im2 = ImageTk.PhotoImage(cropped2)
#canvas.delete(ALL)
canvas.create_image(bx1, by, image=tk_im2) ###THIS IS WHERE THE PROBLEM IS..
canvas.create_image(bx1, by + y, image=tk_im1) ###PROBLEM
#For some reason these 2 lines are overdrawing where they should be. as y increases, the cropped img size should decrease, but doesn't
canvas.update() # This refreshes the drawing on the canvas
canvas.after(cycle_period) # This makes execution pause
root.mainloop()
if __name__ == '__main__':
main()
It's simpler, and much faster and smoother if you don't recreate your images on every cycle. Here's my solution using canvas.move(). Notice that I moved the canvas.create_image calls outside of the for loop. I also put the code in a class and added a 'spin' button, and added something to make it exit without errors.
from Tkinter import *
from PIL import Image, ImageTk
import sys
class SlotMachine():
def __init__(self):
root = Tk()
root.title = ("Slot Machine")
self.canvas = Canvas(root, width=1200, height=800)
self.canvas.grid(column=0,row=0)
button = Button(root, text="Spin!", width=20, command = self.spin)
button.grid(column=0,row=1)
self.alive = True
root.protocol("WM_DELETE_WINDOW", self.die)
root.mainloop()
def spin(self):
im = Image.open("colors.png")
wheelw = im.size[0] #width of source image
wheelh = im.size[1] #height of source image
showsize = 400 # amount of source image to show at a time -
# part of 'wheel' you can see
speed = 3 #spin speed of wheel
bx1 = 250 #Box 1 x - where the box will appear on the canvas
by = 250 #box 1 y
numberofspins = 100 #spin a few times through before stopping
cycle_period = 3 #amount of pause between each frame
tk_im1 = ImageTk.PhotoImage(im)
tk_im2 = ImageTk.PhotoImage(im)
im1id = self.canvas.create_image(bx1, by + showsize, image=tk_im1)
im2id = self.canvas.create_image(bx1, by + showsize + wheelh,
image=tk_im2)
for spintimes in range(1,numberofspins):
for y in range(wheelh,0,-speed):
if self.alive:
self.canvas.move(im1id, 0, -speed)
self.canvas.move(im2id, 0, -speed)
self.canvas.update()
self.canvas.after(cycle_period)
else:
sys.exit()
self.canvas.move(im1id, 0, wheelh)
self.canvas.move(im2id, 0, wheelh)
def die(self):
self.alive = False
if __name__ == '__main__':
mySlotMachine = SlotMachine()
This will place parts of the wheel outside of its box, but you can just put your slot machine texture on top of that.