Código de Python - Monitores

Filtrado por el tag: scripts
<<>>
sin imagen de perfil

Monitoresgráfica de visualizaciones


Python

Publicado el 29 de Julio del 2025 por Manuel (2 códigos)
1.675 visualizaciones desde el 29 de Julio del 2025
el programa es simple, en una PC con dos monitores, en la bandeja de sistema muestra un icono de color azul con 1 si esta activada la vista de los monitores en un solo monitor y el otro esta apagado, muestra 11 si ambos monitores estan en modo clon o copia y muestra 12 si estan en modo de escritorio extendido, tiene una frecuencia de actualizacion cada 60 segundos y ademas con el boton derecho se accede a un menu donde se puede actualizar manualmente y salir, cabe señalar de que una vez terminado y funcionando, el codigo lo pase por Gemini AI para que me hiciera observaciones para optimizar y de paso le coloca comentarios al codigo ademas de darle orden.

si te interesa puedes usarlo libremente, solo te pido que no quites los creditos

Requerimientos

esta en phyton y usa las librerias indicadas en el codigo

1.0

Publicado el 29 de Julio del 2025gráfica de visualizaciones de la versión: 1.0
1.677 visualizaciones desde el 29 de Julio del 2025
estrellaestrellaestrellaestrellaestrella
estrellaestrellaestrellaestrella
estrellaestrellaestrella
estrellaestrella
estrella

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import pystray
from PIL import Image, ImageDraw, ImageFont
import threading
import time
import ctypes
from ctypes import wintypes, Structure, byref, POINTER
 
# --- Definiciones de ctypes para la API de Windows ---
 
class DISPLAY_DEVICE(Structure):
    _fields_ = [
        ("cb", wintypes.DWORD),
        ("DeviceName", wintypes.WCHAR * 32),
        ("DeviceString", wintypes.WCHAR * 128),
        ("StateFlags", wintypes.DWORD),
        ("DeviceID", wintypes.WCHAR * 128),
        ("DeviceKey", wintypes.WCHAR * 128),
    ]
 
# Flags para StateFlags
DISPLAY_DEVICE_ATTACHED_TO_DESKTOP = 0x00000001 # El dispositivo es parte del escritorio
DISPLAY_DEVICE_PRIMARY_DEVICE = 0x00000004    # El dispositivo es la pantalla principal
 
class MonitorDetector:
    def __init__(self):
        self.user32 = ctypes.windll.user32
        self.last_mode = None
 
    def get_physical_monitor_count(self):
        """
        Cuenta el número de monitores físicos conectados y activos.
        Esto intenta ir más allá de la enumeración lógica del escritorio.
        """
        physical_monitors = set() # Usamos un conjunto para almacenar IDs de dispositivos únicos
 
        i = 0
        while True:
            display_adapter = DISPLAY_DEVICE()
            display_adapter.cb = ctypes.sizeof(DISPLAY_DEVICE)
            # Enumerar adaptadores de pantalla
            # El primer parámetro 'None' indica que estamos enumerando adaptadores.
            if not self.user32.EnumDisplayDevicesW(None, i, byref(display_adapter), 0):
                break # No hay más adaptadores
 
            # Verificar si el adaptador está activo (conectado al escritorio)
            if display_adapter.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP:
                j = 0
                while True:
                    display_monitor = DISPLAY_DEVICE()
                    display_monitor.cb = ctypes.sizeof(DISPLAY_DEVICE)
                    # Enumerar monitores conectados a este adaptador específico
                    # El primer parámetro es el nombre del adaptador.
                    if not self.user32.EnumDisplayDevicesW(display_adapter.DeviceName, j, byref(display_monitor), 0):
                        break # No hay más monitores en este adaptador
 
                    # Verificar si el monitor está activo y es parte del escritorio
                    if display_monitor.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP:
                        # Usamos DeviceID para identificar de forma única los monitores físicos.
                        # DeviceID suele ser único para el hardware físico.
                        physical_monitors.add(display_monitor.DeviceID)
                    j += 1
            i += 1
        return len(physical_monitors)
 
    def get_current_mode(self):
        """
        Obtiene el modo actual de la pantalla (individual, extendido, clonado)
        usando el conteo de monitores físicos y las métricas de pantalla virtual.
        """
        try:
            physical_monitor_count = self.get_physical_monitor_count()
 
            # Obtener métricas del sistema
            virtual_width = self.user32.GetSystemMetrics(78)  # SM_CXVIRTUALSCREEN (Ancho de la pantalla virtual)
            primary_width = self.user32.GetSystemMetrics(0)   # SM_CXSCREEN (Ancho de la pantalla principal)
 
            # Lógica para determinar el modo de pantalla
            if physical_monitor_count == 1:
                # Si solo se detecta un monitor físico
                return 1 # Monitor único
            elif physical_monitor_count > 1:
                # Si hay múltiples monitores físicos detectados
                if virtual_width > primary_width:
                    # Y el ancho virtual es mayor que el primario, es modo extendido.
                    return 12 # Modo extendido
                else:
                    # Si el ancho virtual es igual al primario, pero hay múltiples monitores físicos,
                    # significa que comparten el mismo espacio lógico, lo que indica el modo clonado.
                    return 11 # Modo clonado
            else:
                # Caso de respaldo para escenarios inesperados (ej. 0 monitores detectados)
                print(f"DEBUG: Modo desconocido. Monitores físicos detectados: {physical_monitor_count}")
                return self.last_mode if self.last_mode else 1 # Retorna el último modo conocido o 1 en caso de error
 
        except Exception as e:
            print(f"Error detectando el modo: {str(e)}")
            return self.last_mode if self.last_mode else 1 # En caso de error, retorna el último modo o 1
 
def create_text_icon(display_mode):
    """Crea un ícono con el número correspondiente al modo de pantalla"""
    icon_size = 150
    img = Image.new('RGBA', (icon_size, icon_size), (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)
 
    # Asignar colores según el modo
    if display_mode == 1:
        circle_color = 'dodgerblue'  # Azul para un solo monitor
        text = "1"
    elif display_mode == 11:
        circle_color = 'orange'      # Naranja para clonado
        text = "11"
    else:  # display_mode == 12
        circle_color = 'green'       # Verde para extendido
        text = "12"
 
    # Dibujar círculo de fondo
    draw.ellipse([(5, 5), (icon_size-5, icon_size-5)], fill=circle_color)
 
    # Configurar texto
    try:
        font = ImageFont.truetype("arial.ttf", size=int(icon_size*0.7))
    except:
        font = ImageFont.load_default()
 
    # Posicionar texto centrado
    text_bbox = draw.textbbox((0, 0), text, font=font)
    text_width = text_bbox[2] - text_bbox[0]
    text_height = text_bbox[3] - text_bbox[1]
 
    position = (
        (icon_size - text_width) / 2,
        (icon_size - text_height) / 2 # - icon_size*0.05
    )
 
    draw.text(position, text, fill="white", font=font)
    return img
 
class TrayApp:
    def __init__(self):
        self.detector = MonitorDetector()
        self.icon = None
        self.running = True
 
    def update_icon(self, icon=None):
        """Actualiza el ícono con el modo actual y el título."""
        current_mode = self.detector.get_current_mode()
        mode_text = {1: "Solo", 11: "Clonado", 12: "Extendido"}.get(current_mode, "Desconocido")
 
        if self.icon:
            # Solo actualiza si el icono ya ha sido inicializado por pystray
            self.icon.icon = create_text_icon(current_mode)
            self.icon.title = f"Modo: {mode_text}"
 
        self.detector.last_mode = current_mode
 
    def run(self):
        """Inicia la aplicación en la bandeja del sistema."""
        menu = pystray.Menu(
            pystray.MenuItem("Actualizar ahora", self.update_icon),
            pystray.MenuItem("Salir", self.stop),
            pystray.MenuItem("Créditos:", lambda: None),
            pystray.MenuItem("Manuel Cortes Isario", lambda: None)
        )
 
        # Inicializa el icono con el modo actual antes de ejecutar.
        initial_mode = self.detector.get_current_mode()
        initial_icon_image = create_text_icon(initial_mode)
        initial_mode_text = {1: "Solo", 11: "Clonado", 12: "Extendido"}.get(initial_mode, "Desconocido")
 
        self.icon = pystray.Icon(
            "monitor_tray",
            icon=initial_icon_image,
            title=f"Modo: {initial_mode_text}",
            menu=menu
        )
 
        # Inicia el hilo de actualización en segundo plano
        threading.Thread(target=self.monitor_thread, daemon=True).start()
        # La función setup se llama una vez que el icono está visible.
        self.icon.run(self.setup)
 
    def setup(self, icon):
        """Se ejecuta cuando el icono de la bandeja del sistema está visible."""
        icon.visible = True
        self.update_icon(icon) # Actualiza el icono una vez que está configurado
 
    def monitor_thread(self):
        """Hilo para la verificación periódica del modo de pantalla."""
        while self.running:
            self.update_icon()
            time.sleep(60) # Espera 60 segundos antes de la próxima verificación
 
    def stop(self, icon=None, item=None):
        """Detiene la aplicación de la bandeja del sistema."""
        self.running = False
        if self.icon:
            self.icon.stop()
 
if __name__ == "__main__":
    app = TrayApp()
    app.run()



Comentarios sobre la versión: 1.0 (0)


No hay comentarios
 

Comentar la versión: 1.0

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad

http://lwp-l.com/s7577