Skip to content

Instantly share code, notes, and snippets.

@executionunit
Created June 17, 2021 20:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save executionunit/5a3464c710276157f82d2507db905d30 to your computer and use it in GitHub Desktop.
Save executionunit/5a3464c710276157f82d2507db905d30 to your computer and use it in GitHub Desktop.
Using Python and tkinter to build a simple output viewer for game dev build tools. See blog here: https://www.executionunit.com/blog/2012/10/26/using-python-and-tkinter-to-capture-script-output/
"""main script that builds the interface and calls main.py"""
import subprocess
import sys
from tkinter import Tk, Text, BOTH, W, N, E, S, END, INSERT, HORIZONTAL, VERTICAL, NONE, StringVar
from tkinter.ttk import Frame, Button, Style, Scrollbar, Checkbutton
from os.path import join, dirname
from datetime import datetime
mainpath = join(dirname(__file__), "main.py")
#there has got to be a better way to do this in windows.
pythonpath = "python"
if sys.platform == "win32":
pythonpath = "c:\python27\python.exe"
class AssetBuilder(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Asset Builder")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
#create a grid 5x4 in to which we will place elements.
self.columnconfigure(1, weight=1)
self.columnconfigure(2, weight=0)
self.columnconfigure(3, weight=0)
self.columnconfigure(4, weight=0)
self.columnconfigure(5, weight=0)
self.rowconfigure(1, weight=1)
self.rowconfigure(2, weight=0)
self.rowconfigure(3, weight=0)
#create the main text are with scrollbars
xscrollbar = Scrollbar(self, orient=HORIZONTAL)
xscrollbar.grid(row=2, column=1, columnspan=4, sticky=E + W)
yscrollbar = Scrollbar(self, orient=VERTICAL)
yscrollbar.grid(row=1, column=5, sticky=N + S)
self.textarea = Text(self, wrap=NONE, bd=0,
xscrollcommand=xscrollbar.set,
yscrollcommand=yscrollbar.set)
self.textarea.grid(row=1, column=1, columnspan=4, rowspan=1,
padx=0, sticky=E + W + S + N)
xscrollbar.config(command=self.textarea.xview)
yscrollbar.config(command=self.textarea.yview)
#create the buttons/checkboxes to go along the bottom
self.clearButton = Button(self, text="Clear")
self.clearButton.grid(row=3, column=1, padx=5, pady=5, sticky=W)
self.clearButton.bind("<ButtonRelease-1>", self.clearText)
self.verboseVar = StringVar()
verboseCheck = Checkbutton(self, text="Verbose", variable=self.verboseVar,
onvalue="-v", offvalue="")
verboseCheck.grid(row=3, column=2, padx=5, pady=5)
self.forceVar = StringVar()
forceCheck = Checkbutton(self, text="Force Build", variable=self.forceVar,
onvalue="-f", offvalue="")
forceCheck.grid(row=3, column=3, padx=5, pady=5)
self.buildbutton = Button(self, text="Build")
self.buildbutton.grid(row=3, column=4, padx=5, pady=5)
self.buildbutton.bind("<ButtonRelease-1>", self.doBuild)
#tags are used to colorise the text added to the text widget.
# see self.addTtext and self.tagsForLine
self.textarea.tag_config("errorstring", foreground="#CC0000")
self.textarea.tag_config("infostring", foreground="#008800")
def tagsForLine(self, line):
"""return a tuple of tags to be applied to the line of text 'line'
when being added to the text widet"""
l = line.lower()
if "error" in l or "traceback" in l:
return ("errorstring", )
return ()
def addText(self, str, tags=None):
"""Add a line of text to the textWidget. If tags is None then
self.tagsForLine will be used to assign tags to the line"""
self.textarea.insert(INSERT, str, tags or self.tagsForLine(str))
self.textarea.yview(END)
def clearText(self, event):
"""Clear all the text from the text widget"""
self.textarea.delete("1.0", END)
def moveCursorToEnd(self):
"""move the cursor to the end of the text widget's text"""
self.textarea.mark_set("insert", END)
def doBuild(self, event):
"""callback from the build button"""
self.moveCursorToEnd()
self.addText("Build Started %s\n" % (str(datetime.now())), ("infostring", ))
cmdlist = filter(lambda x: x if x else None,
[pythonpath, mainpath, self.verboseVar.get(), self.forceVar.get()])
self.addText(" ".join(cmdlist) + "\n", ("infostring", ))
proc = subprocess.Popen(cmdlist,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
while True:
line = proc.stdout.readline()
if not line:
break
self.addText(line)
#this triggers an update of the text area, otherwise it doesn't update
self.textarea.update_idletasks()
self.addText("Build Finished %s\n" % (str(datetime.now())), ("infostring", ))
self.addText("*" * 80 + "\n", ("infostring", ))
def main():
root = Tk()
root.geometry("650x400+300+300")
AssetBuilder(root)
root.mainloop()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment