Why does my tkinter window and plot appear differently on different monitors, as well as before/after pyinstaller?

Question:

I’m developing a program with a tkinter GUI that has an embedded matplotlib bar chart. The program itself is sturdy, but the GUI gives me some weird issues.

On the PC in my office (windows 10, 1920×1080 monitor), running the program in sublime text shows a perfectly normal GUI. I then built the program into a single executable using pyinstaller, and running this also gives me perfectly normal results.

My office PC's perspective. Looks like this both before and after pyinstaller.

However, if I use a separate PC in my office connected to the same network (also windows 10, 3840×2160 monitor), that’s where I experience issues. Running it before pyinstaller, the window appears much smaller than my PC and the widgets are not scaled down.

Other PC, before pyinstaller

Running it after pyinstaller scales the widgets… but to a teeny tiny window.

Other PC, after pyinstaller

Below is my minimal reproducible example. Please let me know what I may be doing wrong. I’ve successfully built programs like this before, so I’m not sure why this one is giving such a fuss. Thanks in advance.

import tkinter as tk
import numpy as np

from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)

from matplotlib import animation as animation, pyplot as plt, cm
from tkinter import *

# window settings (size, color...)
root = tk.Tk()
root.geometry('678x600')

# settings for the plot size and layout
plt.rcParams["figure.dpi"] = 96  #figure_dpi
plt.rcParams["figure.figsize"] = [6.75, 4.0]

fig = plt.figure() # make a figure for our plot

# text box and label for user to enter desired pulse width
pulse_txt = tk.Text(root, height=1, width=6, font=("Arial", 14))
pulse_lbl = tk.Label(root, text="label label hi", bg="#EEEDEB")

# button to stop counting and export file with counts
end_count_btn = tk.Button(root, text="button", width=10)

# Link the matplotlib figure to our main window and specify its location
canvas = FigureCanvasTkAgg(fig, master=root)

canvas.get_tk_widget().place(relx = 0.02, rely = 0.25) ######

pulse_lbl.place(relx = 0.438, rely = 0.03)
pulse_txt.place(relx = 0.451, rely = 0.07)
end_count_btn.place(relx = 0.445, rely = 0.15)

ax = fig.add_subplot(111)

# create the plot and specify some starting axis info and the title
bars = plt.bar(np.linspace(1,1000,1000), np.zeros(1000), facecolor='#990000', width=1)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_title("plot")
ax.set_xlim([0,500])

# create the nifty toolbar below the plot
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()

root.mainloop()
exit(0)
Asked By: nhargus

||

Answers:

I was able to solve my issue outside of code. The problem was that python.exe and the .exe file that I build with pyinstaller were both using high DPI scaling behavior. Because of this, running the program on the PC with higher DPI resulted in all the widgets being shrunk by under-the-hood functionality.

To stop this from happening, you must do the following with python.exe as well as the .exe built by pyinstaller:

  • Right click on the .exe in explorer
  • Select Properties
  • Select the Compatibility tab
  • Select "Change high DPI settings"
  • Check the "Override high DPI scaling behavior" box
  • Click "OK", "Apply", "OK"

Running the executable after taking these actions results in a correctly sized application window.

Extra thanks to @Bryan Oakley for recommending I use the pack() or grid() methods instead of place() for arranging my widgets. I went with grid() which I found to be the easiest. Only caveat being, the toolbar widget has a pack() statement built in, so in order to get it to play nice with the rest of my widgets using grid(), I had to put the toolbar inside of a frame and use grid() to place that frame.

Answered By: nhargus