Python: Tkinter/ttk themed Message Box

2019-02-09 03:26发布

问题:

I started making a GUI with Tkinter and I added the module tkMessageBox as well. But recently I discovered that importing the module ttk gives more 'up-to-date' results: buttons and texts boxes appear with the actual style of the current OS. This is: Windows 10 buttons are plain and blue-lighted, and not those shaded gray blocky buttons from previous versions.

But unfortunately, I can't find a way to use this ttk themed widgets on the common Dialog Boxes (the ones which I imported from tkMessageBox). So OK/Cancel dialogs (for instance) still appear with a theme that doesn't belongs to Windows 10.

All the documentation I check brings me to Tkinter.

回答1:

The Tk messagebox on Windows is the system provided messagebox. Tk does not create a messagebox using Tk buttons and frames but shows the stock dialog provided by the Windows API.

To check your report here I ran up Tcl/Tk 8.6, Python 3.4 and Powershell and got each to show a messagebox. As you can see Tcl/Tk comes up looking as we would expect but both Python and Powershell are defaulting to the old style non-themed look and feel.

The reason for this is most likely to do with embedded manifests in the executable that launches this. The Tcl/Tk wish executable contains a manifest resource that states the application supports the themed common controls library. The python.exe and pythonw.exe files have no such resources. The necessary manifest is embedded in the Tk86.dll file that is used by tkinter but I think this needs to be associated with the executable. I tested this hypothesis by opening the pythonw.exe file with Visual Studio and replacing the existing RT_MANIFEST resource with the one extracted from the Tk86.dll. With a suitable manifest in place the Python tkinter messagebox comes up properly themed:

Supposedly this manifest can be provided as an XML file in the same folder as the executable but in testing this that did not seem to work. I had to actually embed the manifest in the executable resources.

See "Enabling Visual Styles" for more information on manifest resources.



回答2:

An easier way to get properly themed dialog boxes is by compiling your python scripts into .exe files using pyinstaller. (py2exe might also work, but I haven't used that module in a while and don't plan on going back if I don't have to...)

Error message when running as a python script:

Error message when running as an .exe:

I tried forcing a different theme with ttk.Style().theme_use('clam'), however the dialog boxes don't seem to conform to those themes. It must default to the user's system's style. Still better than the windows 98 feel! for the record, I tested on a computer running windows 7 with Python 2.7.

EDIT

It appears you can add a manifest file using the --manifest option in pyinstaller, however it appears that this isn't very applicable anyways since it seems pyinstaller does that for you.

If you need themed dialog boxes that prompt the user for input, consider using the ttk themed version of tkSimpleDialog called ttkSimpleDialog (link). Full Disclosure: I made the modifications to the original tkSimpleDialog module.



回答3:

From the docs:

Starting with Tk 8.5, the ttk module became available. This module replaces much (but not all) of the original Tkinter machinery. Use this module to gain these advantages:
  • Platform-specific appearance. In releases before Tk 8.5, one of the commonest complaints about Tk applications was that they did not conform to the style of the various platforms.

  • The ttk module allows you to write your application in a generic way, yet your application can look like a Windows application under Windows, like a MacOS app under MacOS, and so on, without any change to your program.

  • Each possible different appearance is represented by a named ttk theme. For example, the classic theme gives you the appearance of the original Tkinter widgets described in the previous sections.

ttk uses the system styles to represent something. Tkinter does not. It is its own style.