#๐Ÿ”’ Is Multi-Monitor support in Python truly as difficult as my searches have shown??

52 messages ยท Page 1 of 1 (latest)

spring gulch
#

I've been trying to build a multi-monitor screensaver for work. Every person has different layouts, so I need to build the canvas dynamically to account for them. The simple goal is to blank all the screens to black and then put something on the primary monitor. I've tried a few libraries, and it seems like pygame is the most stable. I have the primary monitor portion of the code working, but none of the other monitors will black out. I can't understand what my hangup is. Any help would be appreciated. Below is the code to pull and blank the monitors. As a reminder, when I run it, only the primary screen is being blacked out.

import tkinter as tk
import sceeninfo
    for monitor in screeninfo.get_monitors():
        root = tk.Tk()
        root.attributes('-fullscreen', True)
        root.configure(bg='black')
        root.overrideredirect(True)
        root.geometry(f"{monitor.width}x{monitor.height}+{monitor.x}+{monitor.y}")
        root.lift()
        root.wm_attributes("-topmost", True)
        canvas = tk.Canvas(root, bg='black', highlightthickness=0)
        canvas.pack(fill=tk.BOTH, expand=True)
open runeBOT
#

@spring gulch

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

rugged sedge
# spring gulch I've been trying to build a multi-monitor screensaver for work. Every person ha...

I'm pretty sure that root.Tk() always returns the same object - the tk control object, or a handle to it.

Anyway I don't see anything associating monitor with anything there.

Tk might not know about multiple monitors at all.

If the monitors form a single desktop space you might b able to choose geometries with "land" of different monitors. Eg a bigger x-value migh tshift the window to the adjacent monitor.

#

Centainly I've not seen any mention of choosing a display in the tk docs. I have worked on systems with multiple monitors bound to gether as one rectagular workspace.

spring gulch
# rugged sedge I'm pretty sure that `root.Tk()` always returns the same object - the tk control...

Hi - thanks for replying so quickly! It definitely sounds like I'm way off on this. So you can understand my thought process and correct me: I thought the purpose of tk was to create a GUI layer. I've done backend stuff for years, but never had to do anything with graphics, so I feel like a day one novice on this. Anyway.... I thought I needed to create a layer and then place the objects inside the layer. I'm using the monitor loop to figure out where the monitors are located in the layout so I can fill them with black accordingly.

For example, when I look at my three monitors,
monitor1: x=-1920, y=0, width=1920, height=1080
monitor2: x=0,y=0, width=1920, height=1080
monitor3: x=1920, y=0, width=1920, height=1080

I'm expecting the loop to place black boxes of 1920x1080px at -1920,0, 0,0, and 1920,0 respectively, only the primary box displays. I hope I explained that correctly.

glass spoke
rugged sedge
# spring gulch Hi - thanks for replying so quickly! It definitely sounds like I'm way off on t...

Ah, sounds like you're doing what I would have imagined is needed.

So tk is a decent gui/widget library shipped with the stdlib.

Usually you start the gui side of things by getting a tk root, like you did: app = Tk.root(). The app name doesn't really mean much - it's just your gateway object to the widgets. Calling it again just gets you the same thing back. Nothing is yet drawn.

You make a new top level thing by making a widget with no parent, typically a Frame.

This line:

root.geometry(f"{monitor.width}x{monitor.height}+{monitor.x}+{monitor.y}")

just fiddles the geometry of the root. I'm not sure that's meaningful, since it's not a drawn widget at all.

Make a new Frame in each loop pass, and set it's geometry.

#

... or a Toplevel() instead of a Frame().

rugged sedge
spring gulch
#

Wow, you'd never know I've been coding for 35 years... I feel like a drooling idiot reading this.. (Suddenly, I miss my c64!) uhm... If I understand you correctly, it sounds like I need to define the entire desktop first and then build the geometry from that. Since my primary monitor is monitor3, I'm effectively stepping on top of the other two each time I'm doing root.geometry=...

rugged sedge
#

Only 35?

spring gulch
#

well, cough

#

I was rounding down.

#

More like 45

#

lol

rugged sedge
#

Make 3 Toplevel widgets, each with a geometry for its particularl monitor.

rugged sedge
spring gulch
#

hehe

rugged sedge
#

The geometry of the overall desktop may depend on your OS and the layout of the logical space for each monitor. With Windows and MacOS I'd imagine they're adjacent. With some kind of vertical alignment. In X11 on eg Linux things can be .... more flexible (and/or broken); the monitors are a window to an aea of the desktop, and they can overlap.

spring gulch
#

Luckily for now I only need to worry about Windows.

rugged sedge
#

Well I'd hope they were side by side, logically speaking. The screeninfo stuff should tell you that.

spring gulch
#

Yep, I'm pulling that information. I've been moving my screens all over creating weird layouts just to see how they report.

rugged sedge
#

Can you drag a window so that' it's partially on one monitor and partially on another?

spring gulch
#

No, it doesn't allow for that. It causes them to dock, but never overlap or have gaps between them.

rugged sedge
#

๐Ÿ˜ฆ

rugged sedge
#

That may just be a "window manager" thing. Anyway, shou;dn't affect your stuff.

spring gulch
#

You said window, and I was thinking of the screens themselves in the display layouts.

rugged sedge
#

I was thinking an app window.

spring gulch
#

Yes, I can overlay a window across multiple screens.

rugged sedge
#

Right. That pretty much confirms that it's one big logcial desktop.

spring gulch
rugged sedge
#

I guess. But making a top level widget with a geometry based in the "overall desktop" geometry should work?

You could create some sort of Monitor class to represent the monitors, make a list of them from the monitors reported by the screeninfo. Might be helpful, if only to translate per-monitor geometries <-> desktop-wide geometry. Like:

monitors = Monitor.from_screeninfo(...the-screeninfo...)
left = monitors[0]
top0 = Toplevel(geometry=left.global_geometry(left.dx,left.dy,0,0))

to make a Toplevel widget the size of monitor 0 positioned at 0,0 on monitor 0.

spring gulch
# rugged sedge I guess. But making a top level widget with a geometry based in the "overall des...

I'm trying to figure that out now. The problem I ran into earlier is that the first reported monitor isn't necessarily the one that's topleft/right.. it could easily be in the middle depending on the user. I did this to try and build the dimensions, and create a black box of that size (didn't work):

        if (monitor.x<minX):
            minX=monitor.x
        if (monitor.y<minY):
            minY=monitor.y
        if ((monitor.x+monitor.width)>maxX):
            maxX=(monitor.x+monitor.width)
        if ((monitor.y+monitor.height)>maxY):
            maxY=(monitor.x+monitor.height)
rugged sedge
#

Or key=lambda M: (M.x,M.y) just in case the monitors are vertically stacked or something.

spring gulch
rugged sedge
spring gulch
#

Only that I'm an idiot.

#

I wondered if there was a way to sort the monitors from screeninfo and simplify this, but I'm still very green with respect to Python.

rugged sedge
#

That sorted() thing should do it. You understand the lambda?

heady jolt
spring gulch
#

I'm not excusing myself..

spring gulch
#

Thanks for all your help! I haven't quite got it working, but it's time for me to step up and read the info you gave me to see if I can work the rest out.

rugged sedge
#

Enjoy. Let us know how it goes.

#

Got that tkdocs URL bookmarked?

spring gulch
open runeBOT
#
Python help channel closed for inactivity

This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.