Android平台下Python/Kivy/Pyjnius获取屏幕分辨率方法问询
在Kivy Android应用中正确获取屏幕分辨率的方法
你遇到的问题主要有两个核心原因:一是DisplayMetrics实例没有被正确填充设备数据,二是获取屏幕信息的时机过早,另外getDeviceDensity()确实不是DisplayMetrics的官方方法,应该用density属性来替代。下面给你几个可行的解决方案:
一、修复Pyjnius的DisplayMetrics调用方式
直接实例化DisplayMetrics不会自动填充设备的真实显示数据,你需要通过Android的WindowManager来获取当前显示的Metrics信息。修改后的代码如下:
from kivy.app import App from kivy.uix.button import Button from kivy.utils import platform from kivy.core.window import Window myheight = -100 mywidth = -100 myDPI = -100 gDPI = -100 Window.fullscreen = True if platform == 'android': from jnius import autoclass, cast # 获取Android核心类 Activity = autoclass('android.app.Activity') DisplayMetrics = autoclass('android.util.DisplayMetrics') WindowManager = autoclass('android.view.WindowManager') # 获取当前Activity实例 activity = cast('android.app.Activity', Activity.mActivity) # 获取WindowManager服务 window_manager = activity.getSystemService(WindowManager.WINDOW_SERVICE) # 获取默认Display对象 display = window_manager.getDefaultDisplay() metrics = DisplayMetrics() # 关键步骤:调用getMetrics填充真实数据 display.getMetrics(metrics) # 正确获取属性值 gDPI = metrics.density # 设备密度系数(如1.0、2.0等) myheight = metrics.heightPixels mywidth = metrics.widthPixels myDPI = metrics.densityDpi class MainApp(App): def build(self): b = Button( text=f"Height: {myheight}\nWidth: {mywidth}\nDPI: {myDPI}\ndensity: {gDPI}\nWindow.size: {Window.size}", color=[0,0,0,1] ) return b MainApp().run()
二、利用Kivy自身Window获取(推荐)
Kivy的Window其实可以获取真实分辨率,但要注意获取时机——不能在App启动前直接获取,应该在App的on_start方法或者build方法之后执行,因为Window需要时间完成初始化。示例代码:
from kivy.app import App from kivy.uix.button import Button from kivy.core.window import Window from kivy.utils import platform class MainApp(App): def build(self): Window.fullscreen = True self.button = Button(color=[0,0,0,1]) return self.button def on_start(self): # 此时Window已完成初始化,可获取真实尺寸 window_width, window_height = Window.size dpi = None density = None if platform == 'android': # 结合Pyjnius获取DPI信息 from jnius import autoclass, cast Activity = autoclass('android.app.Activity') DisplayMetrics = autoclass('android.util.DisplayMetrics') activity = cast('android.app.Activity', Activity.mActivity) metrics = DisplayMetrics() activity.getWindowManager().getDefaultDisplay().getMetrics(metrics) dpi = metrics.densityDpi density = metrics.density else: dpi = Window.dpi density = Window.density self.button.text = ( f"Window Size: {window_width}x{window_height}\n" f"DPI: {dpi}\n" f"Density: {density}" ) MainApp().run()
三、直接调用SDL2获取屏幕信息
Kivy底层基于SDL2,你可以用ctypes直接调用SDL2的API获取显示模式信息,这种方法更贴近底层,适合对精度要求高的场景:
from kivy.app import App from kivy.uix.button import Button from kivy.utils import platform import ctypes class MainApp(App): def build(self): self.button = Button(color=[0,0,0,1]) return self.button def on_start(self): if platform != 'android': self.button.text = "此方法仅适用于Android平台" return # 加载SDL2动态库 sdl2 = ctypes.CDLL('libSDL2.so') # 定义SDL_DisplayMode结构体 class SDL_DisplayMode(ctypes.Structure): _fields_ = [ ("format", ctypes.c_uint32), ("w", ctypes.c_int), ("h", ctypes.c_int), ("refresh_rate", ctypes.c_int), ("driverdata", ctypes.c_void_p) ] # 获取主显示器的桌面显示模式 mode = SDL_DisplayMode() result = sdl2.SDL_GetDesktopDisplayMode(0, ctypes.byref(mode)) if result == 0: width = mode.w height = mode.h # 获取DPI相关数据 ddpi = ctypes.c_float() hdpi = ctypes.c_float() vdpi = ctypes.c_float() sdl2.SDL_GetDisplayDPI(0, ctypes.byref(ddpi), ctypes.byref(hdpi), ctypes.byref(vdpi)) self.button.text = ( f"SDL2 Screen Size: {width}x{height}\n" f"DDPI: {ddpi.value}\n" f"HDPI: {hdpi.value}\n" f"VDPI: {vdpi.value}" ) else: self.button.text = "SDL2获取屏幕信息失败" MainApp().run()
关键注意事项
- 获取时机:所有获取屏幕信息的操作都应该在
App的on_start方法中执行,或者在build方法之后,因为此时应用已经完成初始化,Window/Android系统的显示信息才会被正确加载。 - 全屏模式:务必设置
Window.fullscreen = True,否则Kivy可能会使用默认的窗口尺寸(比如800x480),导致获取的尺寸不准确。
内容的提问来源于stack exchange,提问作者lokapal
相关产品推荐
相关产品推荐

