PySimpleGUI / PySimpleGUI

Python GUIs for Humans! PySimpleGUI is the top-rated Python application development environment. Launched in 2018 and actively developed, maintained, and supported in 2024. Transforms tkinter, Qt, WxPython, and Remi into a simple, intuitive, and fun experience for both hobbyists and expert users.
https://www.PySimpleGUI.com
Other
13.4k stars 1.83k forks source link

[BUG] Default position for windows too large for screen is entirely invisible. #3576

Open swight-prc opened 3 years ago

swight-prc commented 3 years ago

Type of Issues (Enhancement, Error, Bug, Question)

Bug

Operating System

Windows 10, Linux (Ubuntu 18.04)

Python version

3.7

PySimpleGUI Port and Version

Ports = tkinter, Qt, WxPython, Web tkinter

PySimpleGUI Version: 4.29.0

tkinter version: 8.6

You can get these by adding this to the top of your file and running it:

import PySimpleGUI as sg

print(sg)             # Location of your PySimpleGUI.py file
print(sg.version)     # PySimpleGUI version number
print(sg.tclversion_detailed)   # tkinter detailed version number (in PySimpleGUI version 4.29.0+)
print(sg.sys.version) # Python version number

The tkinter version number can be obtained using above code in version 4.29.0+. If your code is prior:

print(sg.tkinter.Tcl().eval('info patchlevel'))

Your Experience Levels In Months or Years

11mo Python programming experience 11mo Programming experience overall __no___ Have used another Python GUI Framework (tkinter, Qt, etc) previously (yes/no is fine)?

You have completed these steps:

Description of Problem / Question / Details

The default position of a window seems to be to have it centered in the visible area of the screen. I like that, it's a good plan. However, if a window is created whose dimensions are larger than the visible area, the entire window seems to be getting pushed offscreen.

Code To Duplicate

A short program that isolates and demonstrates the problem (i.e. please don't paste a link to your 400 line program.... instead paste your 10 line program in full).

Yes, it is a pain to narrow down problems, but it's part of the debugging process. Help me help you by providing something that can be executed so that work on getting you a fix or a workaround can immediately begin.

This pre-formatted code block is all set for you to paste in your bit of code:

Horizontally too large

import PySimpleGUI as sg

## Paste your code here

layout = [[sg.Text(str(a)) for a in range(1000)]]
window = sg.Window("Title", layout)
window()

Vertically too large

import PySimpleGUI as sg

layout = [[sg.Text(str(a))] for a in range(1000)]
window = sg.Window("Title", layout)
window()

Expected behavior

Either of:

Actual behavior:

jason990420 commented 3 years ago

Samething happened under

Note : Similar issue also on horizontal direction

import PySimpleGUI as sg

layout = [[sg.Text(str(a))] for a in range(33)] 
window = sg.Window("Title", layout, grab_anywhere=True)
window()

Here's my situation,

PySimpleGUI commented 3 years ago

The easiest way to get the most of your window shown as possible would be to locate your window at (0,0). You can do this by adding it as a parameter to your Window call:

This will create your window in the uppermost left corner of your screen.

    window = sg.Window('Window Title', layout, location=(0,0))
swight-prc commented 3 years ago

The easiest way to get the most of your window shown as possible would be to locate your window at (0,0). You can do this by adding it as a parameter to your Window call:

This will create your window in the uppermost left corner of your screen.

    window = sg.Window('Window Title', layout, location=(0,0))

Yes, that's a delightful workaround, but the default behavior is still buggy.

PySimpleGUI commented 3 years ago

PySimpleGUI tries to do the best solution it can for the developer by setting default parameters for you. The other approach is to force the user to indicate the parameter values every time. For some systems, the window may extend onto additional displays. The behavior isn't buggy. It's consistent.

PySimpleGUI commented 3 years ago

Maybe there is a computational error you're seeing? For the window too large example, it spans 3 of my monitors.

import PySimpleGUI as sg

## Paste your code here

layout = [[sg.Text(str(a)) for a in range(100)]]
window = sg.Window("Title", layout)
window()

I'll check to see if there's an error like a round happening.

PySimpleGUI commented 3 years ago

BTW, you win the clever code-snipped of the year award for your

import PySimpleGUI as sg

## Paste your code here

layout = [[sg.Text(str(a)) for a in range(1000)]]
window = sg.Window("Title", layout)
window()

Not many people pick up and use the ability to "call a window" in order to make it read. VERY clever of you.

PySimpleGUI commented 3 years ago

Oh.... I do see an off-screen situation....

swight-prc commented 3 years ago

BTW, you win the clever code-snipped of the year award for your

import PySimpleGUI as sg

## Paste your code here

layout = [[sg.Text(str(a)) for a in range(1000)]]
window = sg.Window("Title", layout)
window()

Not many people pick up and use the ability to "call a window" in order to make it read. VERY clever of you.

:) :) ty ty. Yeah, I had noticed that most people use the .read() method, but I I thought the call was more elegant, so until I find a difference in behavior, I'll use that.

I also like the add_row and add_rows methods, but they get a little wonky when you're changing values inside the window, so I don't use them in every circumstance. (You can't use it to add a progress bar, for example, because the progress bar is never set as a child of the window.)

At some point I may decide to jump on and do a little developing here; if I do, I may look into that behavior and push a possible solution. But not right now! But anyway, back to the topic at hand.

I had not considered multiple screens; appearing on another screen might be reasonable behavior in that case. I wonder if there's a way to determine the total available viewing space before setting the position?

PySimpleGUI commented 3 years ago

There's no real value in calling add_row or add_rows directly. Better to build your layout in your local space and then pass the entire layout over.

You're welcome to submit enhancement idea and if you learn something about where to get sizes of things, that's fine to enter into the issue of course. But the project does not take pull requests. Want to make sure you're aware of this before you ging off and investing a lot of time into something that won't be used. I don't want to waste your time.

I use negative values and values larger than the screen size to locate items on 3 different monitors I have set up. tkinter processes them as one giant monitor if you use values that are logically out of bounds. When I startup my "rainmeter" style programs, I use these offsets as wher I place them:

            run_py(r'C:\Python\PycharmProjects\PSG\User Submitted Programs\Weather-App2\weather_widget.py', '3165,400')
            run_py( r'C:\Python\PycharmProjects\PSG\MikesDemos\Mike_LED_Clock_Weather.py', '3100,765')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_psutil_Dashboard.py', '2660,37')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_Drive_Usage.py', '3300,27')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_RAM_Square.py', '2735,462')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Dashboard.py', '-500,330')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Utilization.py')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Square.py', '2900,462')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Top_Processes.py', '2967,43')
            run_py( r'C:\Python\PycharmProjects\PSG\MikesDemos\Mikes_Launcher_PyCharm_Edits.py')

My primary monitor is only 2660 x 1440 so you can clearly see that tkinter addresses thing relative to (0,0) being the upper left of the main display.

swight-prc commented 3 years ago

There's no real value in calling add_row or add_rows directly. Better to build your layout in your local space and then pass the entire layout over.

You're welcome to submit enhancement idea and if you learn something about where to get sizes of things, that's fine to enter into the issue of course. But the project does not take pull requests. Want to make sure you're aware of this before you ging off and investing a lot of time into something that won't be used. I don't want to waste your time.

I use negative values and values larger than the screen size to locate items on 3 different monitors I have set up. tkinter processes them as one giant monitor if you use values that are logically out of bounds. When I startup my "rainmeter" style programs, I use these offsets as wher I place them:

            run_py(r'C:\Python\PycharmProjects\PSG\User Submitted Programs\Weather-App2\weather_widget.py', '3165,400')
            run_py( r'C:\Python\PycharmProjects\PSG\MikesDemos\Mike_LED_Clock_Weather.py', '3100,765')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_psutil_Dashboard.py', '2660,37')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_Drive_Usage.py', '3300,27')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_RAM_Square.py', '2735,462')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Dashboard.py', '-500,330')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Utilization.py')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Square.py', '2900,462')
            run_py( r'C:\Python\PycharmProjects\PSG\DemoPrograms\Demo_Desktop_Widget_CPU_Top_Processes.py', '2967,43')
            run_py( r'C:\Python\PycharmProjects\PSG\MikesDemos\Mikes_Launcher_PyCharm_Edits.py')

My primary monitor is only 2660 x 1440 so you can clearly see that tkinter addresses thing relative to (0,0) being the upper left of the main display.

I think there's a semantic value in building the window using add_row and add_rows, because it makes it more clear what you're doing. Python code should be human-readable whenever possible, and I think using those methods improves my code in that respect. But that's just my opinion.

As far as the application not accepting pull requests, that is of course up to you. I think it puts undue weight on your dev team's shoulders for what is, after all, a free application, but it is still your call. I do appreciate your saving me the trouble, though.

Yes, it does appear that tkinter is basing positioning on your primary monitor.

How are you determining the default location?

PySimpleGUI commented 3 years ago

I agree that building your layout by rows is valuable at times. You'll find it in many of the "Generated Layouts" demo. My suggestion is to steer away from making the calls directly into the Window.add_row and instead do an append call with your own layout. It's still just as clear, or likely more clear.

For example, this code builds a layout of checkboxes.

def choose_locations(locations, chosen_locations):
    locations = list(locations)
    if not chosen_locations:
        defaults = DEFAULT_LOCATIONS
    else:
        defaults = chosen_locations
    max_col = 7
    row = []
    cb_layout = []
    for i, location in enumerate(sorted(locations)):
        row.append(sg.CB(location, size=(15,1), pad=(1,1), font='Any 9', key=location, default=True if location in defaults else False))
        if (i+1) % max_col == 0:
            cb_layout += [row]
            row = []
    cb_layout += [row]

    layout = [[sg.T('Choose Locations')]]
    layout += cb_layout
    layout += [[sg.B('Ok', border_width=0, bind_return_key=True), sg.B('Cancel', border_width=0)]]

    window = sg.Window('Choose Locations', layout, icon=ICON, keep_on_top=True, border_depth=0)
    event, values = window.read()
    window.close()

The resulting window looks something like this:

image

I like to use the += operator when building layouts. It's a clear way to show that rows are being added to a layout.

I calculate the default location based on the size of the newly created window.