0

When I run certain scripts (contains tkinter or similar python packages) ArcGIS crashes. When I load or copy/paste the same code and run it in a Python window it runs without error.

Is there a problem in ArcGIS? I am using 10.4.1.

closed as off-topic by PolyGeo Oct 31 '17 at 22:18

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions seeking help to debug/write/improve code must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Providing a clear problem statement and evidence of a code attempt will help others to help you. See: How to create a Minimal, Complete, and Verifiable example." – PolyGeo
If this question can be reworded to fit the rules in the help center, please edit the question.

  • Thank you, But I face the same problem when I used "easygui" which is also a GUI for the Python within ArcGIS – A.Adel Saleh Oct 1 '16 at 16:20
  • 1
    I would think (based on @RichardFairhurst's comment) that your issues with EasyGUI are for the same reason - they likely conflict with ArcGIS as ArcGIS has its own GUI – Midavalo Oct 1 '16 at 18:48
3

I think the trick to using tkinter in Python is to run it from an external module, that way it isn't competing with the GUI components from the pythonaddins module. I do not take any credit for the tkinter GUI portion, as it was my colleague who figured it out, but here is a sample.

The GUI is dynamically created based on a list of text elements, and allows you to quickly update them all. In our templates, all of our header elements are prefixed with header_*. So to make this work, he saved out an external module called element_gui and I just imported it into my test add in and it works pretty smoothly. Here's the GUI code:

#-------------------------------------------------------------------------------
# Name:        module1
# Purpose:
#
# Author:      tylerjo
#
# Created:     08/04/2016
# Copyright:   (c) tylerjo 2016
# Licence:     <your licence>
#-------------------------------------------------------------------------------
import sys
import os
import Tkinter as tk
import tkFileDialog, tkMessageBox
import ttk
import csv

N,S,E,W = tk.N,tk.S,tk.E,tk.W


def main(in_els=[]):
    """Main function. Calls GUI.

    Required:
        in_els -- List of element objects

    """

    gui = GUI(els=in_els)
    gui.master.title("Update Elements")
    gui.master.minsize(width=500, height=150)
    gui.mainloop()

    return gui.outDict

class GUI(tk.Frame):

    def __init__(self, master=None, els=[]):
        tk.Frame.__init__(self,master)
        self.grid(sticky=N+S+E+W)
        tk.Grid.rowconfigure(self, 0, weight=1)
        tk.Grid.columnconfigure(self, 0, weight=1)

        self.elementList = els
        self.elDict = {}
        self.outDict = {}

        self.__createWidgets()

    def __createWidgets(self):

        top = self.winfo_toplevel()
        top.rowconfigure(0, weight=1)
        top.columnconfigure(0,weight=1)
        self.top = top

        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)

        self.f1 = tk.Frame(self, height=500, width=500, bg='gray')
        self.f1.grid(row=0, sticky=N+E+W+S, columnspan=2)
        tk.Grid.rowconfigure(self.f1, 0, weight=1)

        r1 = ['Element Name', 'Updated Value']
        for ci,cLabel in enumerate(r1):
            tk.Grid.columnconfigure(self.f1, ci, weight=1)
            tk.Label(self.f1, text=cLabel, borderwidth=1, width=20, relief=tk.GROOVE).grid(column=ci, row=0, sticky=N+E+W)

        for i, el in enumerate(self.elementList,1):
            tk.Label(self.f1, text=el.name, borderwidth=2).grid(column=0, row=i, sticky=E+W)
            self.elDict[el] = tk.StringVar()
            tk.Entry(self.f1, textvariable=self.elDict[el], justify=tk.CENTER).grid(column=1,row=i, sticky=E+W)

        self.saveButton = tk.Button(self, text="Send Updated Text Back To ArcMap", command=self.both_functions, width=30)
        self.saveButton.grid(row=4, column=0)

    def btnClick(self):
        """Get values from StringVar() objects and put into outDict
        """

        for el, newval in self.elDict.items():
            print newval.get()
            self.outDict[el] = newval.get()

        print self.outDict
        return self.outDict

    def _close(self):
        """Destroy GUI"""
        self.top.destroy()

    def both_functions(self):
        """For some reason I can't call _close within btnClick function.
        So both are called here
        """

        self.btnClick()
        self._close()


if __name__ == '__main__':
    main()

And here is how I consume it in my simple Add-In (just a toolbar with a button):

import arcpy
import pythonaddins
import os
import sys
sys.path.append(os.path.dirname(__file__))
import element_gui

class ButtonClass3(object):
    """Implementation for UpdateMapElmsTest_addin.button (Button)"""
    def __init__(self):
        self.enabled = True
        self.checked = False
        self.mxd = arcpy.mapping.MapDocument('current')
        print os.path.dirname(__file__)

    def onClick(self):
        elms = arcpy.mapping.ListLayoutElements(self.mxd, 'TEXT_ELEMENT', 'Header*')
        new_heads = element_gui.main(elms)
        for elm,new_text in new_heads.iteritems():
            elm.text = new_text
        arcpy.RefreshActiveView()

And here is what it looks like:

Example

I am not sure how stable this will be. It did crash a couple times when I had the Python window open, so it may still be trying to compete with pythonaddins for UI resources.

6

Tkinter is not compatible with any version of Arcmap desktop. As a script you are running pure python, and not using the ArcMap desktop application at all, which is why you are seeing different behavior. Esri has determined that tkinter and Arcmap desktop conflict in their messaging designs and they will not resolve the conflict, so tkinter is not supported while using desktop. As far as I know there is no compatible Python GUI that can be used within an ArcMap desktop session. At the User conferences, Esri staff has always answered that the only "GUI" for Python is a geoprocessing tool dialog connected to a Python Add-In or script or a Python Add-In toolbar that contains buttons, text boxes, and combo boxes.

  • 1
    This is what I always thought too. However, just last week a few coworkers actually got a Tkinter GUI to work within the context of a Python Add-In. Rather than including any of the Tkinter code in the Add-In source code, they had called it from a different stand alone module and wrapped it in a class and imported it into the Add-In. It worked like a charm. – crmackey Oct 3 '16 at 1:34
  • 1
    Please post that code as a possible answer. I'd like to see it. Since it is a workaround that bypasses arcpy, technically my answer is correct, but if a workaround exists then it would be nice to publicize that as an option, whether or not Esri would support or recommend using it. – Richard Fairhurst Oct 3 '16 at 14:27
  • I posted a sample solution. I wouldn't call this a workaround per se, but rather just trying to separate the processes. I say that, because if you think about it, when the module is called externally that has the tkinter GUI, it is being ran in the background (I think), while the Python Add-In framework itself (from the pythonaddins module, not arcpy) is being ran in the foreground which is how it displays the toolbar. By keeping tkinter separate, I think it kind of separates the processes on the main UI thread. – crmackey Oct 3 '16 at 16:15

Not the answer you're looking for? Browse other questions tagged or ask your own question.