Brad Zeis
Brad Zeis

Reputation: 10845

How can I determine the monitor refresh rate?

Is there a cross platform way to get the monitor's refresh rate in python (2.6)? I'm using Pygame and PyOpenGL, if that helps.

I don't need to change the refresh rate, I just need to know what it is.

Upvotes: 8

Views: 8441

Answers (5)

Shai Avr
Shai Avr

Reputation: 1350

I recommend switching to the community edition of pygame. Their website https://pyga.me/. Long story short, the pygame former core developers had challenges contributing to the original development upstream, so they forked the repository and moved to this new distribution that aims to offer more frequent releases, continuous bug fixes and enhancements, and a more democratic governance model (The magic of Open Source). You can easily switch to it by running pip uninstall pygame and then pip install pygame-ce --upgrade. They have the same API as the original pygame (so you still use import pygame and everything remains the same).

They have many nice new features and bug fixes, including methods to get the monitor's refresh rate in the display module:

import pygame

pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
running = True

print(
    "Screen refresh rate for current window:", pygame.display.get_current_refresh_rate()
)  # Must be called after pygame.display.set_mode()
print(
    "Screen refresh rate for all displays:", pygame.display.get_desktop_refresh_rates()
)  # Safe to call before pygame.display.set_mode()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill("purple")

    pygame.display.flip()
    clock.tick(60)  # limits FPS to 60

pygame.quit()

On my computer, this prints

pygame-ce 2.3.2 (SDL 2.26.5, Python 3.11.4)
Screen refresh rate for current window: 144
Screen refresh rate for all displays: [144]

which is indeed correct.

Upvotes: 2

Cracko298
Cracko298

Reputation: 11

You can use DEVMODEW, but this only works on Windows Machines.

Install 'wmi' using pip with "pip install wmi"

import ctypes
import wmi
from time import sleep

class DEVMODEW(ctypes.Structure): # Defines the DEVMODEW Structure
_fields_ = [
    ("dmDeviceName", ctypes.c_wchar * 32),
    ("dmSpecVersion", ctypes.c_uint16),
    ("dmDriverVersion", ctypes.c_uint16),
    ("dmSize", ctypes.c_uint32),
    ("dmDriverExtra", ctypes.c_uint16),
    ("dmFields", ctypes.c_uint32),
    ("dmPosition", ctypes.c_int32 * 2),
    ("dmDisplayOrientation", ctypes.c_uint32),
    ("dmDisplayFixedOutput", ctypes.c_uint32),
    ("dmColor", ctypes.c_short),
    ("dmDuplex", ctypes.c_short),
    ("dmYResolution", ctypes.c_short),
    ("dmTTOption", ctypes.c_short),
    ("dmCollate", ctypes.c_short),
    ("dmFormName", ctypes.c_wchar * 32),
    ("dmLogPixels", ctypes.c_uint16),
    ("dmBitsPerPel", ctypes.c_uint32),
    ("dmPelsWidth", ctypes.c_uint32),
    ("dmPelsHeight", ctypes.c_uint32),
    ("dmDisplayFlags", ctypes.c_uint32),
    ("dmDisplayFrequency", ctypes.c_uint32),
    ("dmICMMethod", ctypes.c_uint32),
    ("dmICMIntent", ctypes.c_uint32),
    ("dmMediaType", ctypes.c_uint32),
    ("dmDitherType", ctypes.c_uint32),
    ("dmReserved1", ctypes.c_uint32),
    ("dmReserved2", ctypes.c_uint32),
    ("dmPanningWidth", ctypes.c_uint32),
    ("dmPanningHeight", ctypes.c_uint32)
]

def get_monitor_refresh_rate():
    c = wmi.WMI()
    for monitor in c.Win32_VideoController():
        return monitor.MaxRefreshRate
    return None

refresh_rate = get_monitor_refresh_rate()
if refresh_rate is not None:
    print(f"Monitor refresh rate: {refresh_rate} Hz")
else:
    print("Cannot Detremine the Monitor Refresh Rate.")
sleep(10)

Upvotes: 0

Glyph
Glyph

Reputation: 31910

On macOS, you can use pyobjc to query the refresh rate of all the attached displays. You'll need the Cocoa (i.e. "AppKit") framework for this:

$ python3 -m venv screen-res
$ . ./screen-res/bin/activate
$ pip install pyobjc-framework-Cocoa

then, in Python:

from AppKit import NSScreen

for each in NSScreen.screens():
    print(f"{each.localizedName()}: {each.maximumFramesPerSecond()}Hz")

On my system, this produces:

LG HDR WQHD+: 120Hz
Built-in Retina Display: 120Hz

(Which is correct, my displays are indeed both set to a 120Hz refresh rate.)

On Linux, you can use python-xlib:

from Xlib import display
from Xlib.ext import randr
d = display.Display()
default_screen = d.get_default_screen()
info = d.screen(default_screen)

resources = randr.get_screen_resources(info.root)
active_modes = set()
for crtc in resources.crtcs:
    crtc_info = randr.get_crtc_info(info.root, crtc, resources.config_timestamp)
    if crtc_info.mode:
        active_modes.add(crtc_info.mode)

for mode in resources.modes:
    if mode.id in active_modes:
        print(mode.dot_clock / (mode.h_total * mode.v_total))

Associating the appropriate screen index number with the place you want your PyOpenGL window to open up on is left as an exercise for the reader :).

(I won't duplicate Anurag's answer for Windows here, especially since I can't test it, but that's how you would do it on that platform.)

Upvotes: 1

Dragonwarrior
Dragonwarrior

Reputation: 1

You can use the pygame clock

fps = 60
clock = pygame.time.Clock()

At the end of the code: clock.tick(fps)

Upvotes: -4

Anurag Uniyal
Anurag Uniyal

Reputation: 88845

I am not sure about the platform you use, but on window you can use ctypes or win32api to get details about devices e.g. using win32api

import win32api

def printInfo(device):
    print((device.DeviceName, device.DeviceString))
    settings = win32api.EnumDisplaySettings(device.DeviceName, -1)
    for varName in ['Color', 'BitsPerPel', 'DisplayFrequency']:
        print("%s: %s"%(varName, getattr(settings, varName)))

device = win32api.EnumDisplayDevices()
printInfo(device)

output on my system:

\\.\DISPLAY1 Mobile Intel(R) 945GM Express Chipset Family
Color: 0
BitsPerPel: 8
DisplayFrequency: 60

Upvotes: 11

Related Questions