Why PyGame is not drawing a single pixel using .set_at?

Question:

I want to find a way to draw a line made of black pixels in PyGame. Following Pygame: Draw single pixel, I end up with:
pygame 1px width line
using this code:

import pygame

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
FPS = 10

pygame.init()
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
screen = pygame.display.set_mode((200, 200))
screen.fill(WHITE)

pygame.display.flip()
clock = pygame.time.Clock()
screen_width, screen_height = screen.get_size()

for i in range(100):
  screen.set_at((i, 100), BLACK)

while True:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      exit()
  
  pygame.display.update()
  clock.tick(FPS)

I used ColorSlurp to check the width.

Why do I end up with a 4px wide line ? Is there a way to fix it to actually get a 1 pixel line width?

Notes

I thought maybe ColorSlurp was adding fake extra pixels on zoom (like "over zooming"). So I checked with HTML canvas, I got this:
html canvas 1px test

By zooming out, I get an actual 1 pixel wide line. So I have the same behavior but my computer can actually display a thiner line compared to what .set_at(position, color) on PyGame or .fillRect(x, y, 1, 1) on canvas create.

Asked By: Vince M

||

Answers:

set_at changes the color of a single pixel. However, if your display is DPI-scaled, the surface will be scaled up when the Pygame window is updated. You must disable scaling for the Pygame window. e.g. in windows you can do:

import ctypes
ctypes.windll.user32.SetProcessDPIAware()
Answered By: Rabbid76
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.