Quick Project Summary: Make a python widget using Tkinter that displays data from several json and txt files. Needs to work in Windows.
Where I'm At: Everything is going great with the json files. But I'm running into trouble with the txt files. I can parse the information I need out of the necessary files with this code:
from Tkinter import *
import re
results = open("sample_results.txt", "r")
for line in results:
if re.match("(.*)test(.*)", line):
print line
if re.match("(.*)number(.*)", line):
print line
if re.match("(.*)status(.*)", line):
print line
if re.match("(.*)length(.*)", line):
print line
Problem: It displays all the data in the command shell NOT in a seperate widget.
I would like to simply move all of this information from the command shell to a text box widget (or a tkmessage widget but I feel that the text box would be more appropriate). A very long google search process gave me lots of code that doesn't work - any tips? Thanks!
Note: This is NOT all the code - just the part I need help fixing
Here's what I think you want. You want your application to open files and parse them out. For each parsed line, you would like it to insert the text (or append the text) to a text control. I would create a method for each file type to do the parsing. Then I would loop over each file and call the parser as appropriate. When you are finished parsing, you can call
self.textbox.insert(tkinter.END, parsed_text)
Another way to do this is to redirect stdout to your text control and then print the parsed line. I find this latter approach to be a bit more flexible, especially when I want to call a separate program with subprocess and read its output bit by bit. Here's one way to do it with Tkinter:
import ScrolledText
import sys
import tkFileDialog
import Tkinter
########################################################################
class RedirectText(object):
""""""
#----------------------------------------------------------------------
def __init__(self, text_ctrl):
"""Constructor"""
self.output = text_ctrl
#----------------------------------------------------------------------
def write(self, string):
""""""
self.output.insert(Tkinter.END, string)
########################################################################
class MyApp(object):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
self.root = parent
self.root.title("Redirect")
self.frame = Tkinter.Frame(parent)
self.frame.pack()
self.text = ScrolledText.ScrolledText(self.frame)
self.text.pack()
# redirect stdout
redir = RedirectText(self.text)
sys.stdout = redir
btn = Tkinter.Button(self.frame, text="Open file", command=self.open_file)
btn.pack()
#----------------------------------------------------------------------
def open_file(self):
"""
Open a file, read it line-by-line and print out each line to
the text control widget
"""
options = {}
options['defaultextension'] = '.txt'
options['filetypes'] = [('all files', '.*'), ('text files', '.txt')]
options['initialdir'] = '/home'
options['parent'] = self.root
options['title'] = "Open a file"
with tkFileDialog.askopenfile(mode='r', **options) as f_handle:
for line in f_handle:
print line
#----------------------------------------------------------------------
if __name__ == "__main__":
root = Tkinter.Tk()
root.geometry("800x600")
app = MyApp(root)
root.mainloop()
One approach is to use a simple tkinter label:
# somewhere in your main class, I suppose:
self.log_txt = tkinter.StringVar()
self.log_label = tkinter.Label(self.inputframe, textvariable=self.log_txt, justify=tkinter.LEFT)
self.log_label.pack(anchor="w")
Then, a really simple approach for putting text into that label:
def log(self, s):
txt = self.log_txt.get() + "\n" + s
self.log_txt.set(txt)
Alternatively, you can use a tkinter.Text widget. In that case you can insert text with the insert method:
self.textbox = tkinter.Text(parent)
self.textbox.insert(tkinter.END, "some text to insert")
One resource I like is http://effbot.org/tkinterbook/text.htm. Unfortunately it is quite hard to go from that text to working Python code :(
Here is a little example program with an ugly little tkinter GUI that adds text to a textbox:
#!/usr/bin/env python
try:
import tkinter
except ImportError:
import Tkinter as tkinter
import _tkinter
import platform
class TextBoxDemo(tkinter.Tk):
def __init__(self, parent):
tkinter.Tk.__init__(self, parent)
self.parent = parent
self.wm_title("TextBoxDemo")
self.textbox = tkinter.Text(self)
self.textbox.pack()
self.txt_var = tkinter.StringVar()
self.entry = tkinter.Entry(self, textvariable=self.txt_var)
self.entry.pack(anchor="w")
self.button = tkinter.Button(self, text="Add", command=self.add)
self.button.pack(anchor="e")
def add(self):
self.textbox.insert(tkinter.END, self.txt_var.get())
if __name__ == '__main__':
try:
app = TextBoxDemo(None)
app.mainloop()
except _tkinter.TclError as e:
if platform.system() == 'Windows':
print(e)
print("Seems tkinter will not run; try running this program outside a virtualenv.")
Related
I am trying to run a script in python that is using multiprocessing. Everything works ok, but I want it to make a bit more complex. In the example below, I don't know how to call a function from the class that needs the root as an argument as the root is defined in another function. I would appreciate some help or advice.
The code that I am using is the following one:
import tkinter as tk, time
from multiprocessing import Process
from tkinter import filedialog, ttk
class Example():
def __init__ (self, parent)
self.parent = parent
canvas = tk.Canvas(self.parent)
self.button = tk.Button(self.parent, command = self.onStart)
self.pbar = ttk.Progressbar(self.parent, mode = 'indeterminate', length = 100)
def pbar_start(self):
self.pbar.pack()
self.pbar.start()
def files(self):
self.filena = filedialog.askopenfilenames(initialdir="/", title = "Select file", filetypes = (("comma separated file","*.csv"), ("all files", "*.*")))
return filena
def onStart():
self.p1 = Process(target = work)
self.p1.start()
def work():
time.sleep(5) # I put time just to show that I don't want the progressbar to start immediately
app = Example(root) # here if I call root is giving me an error as expected, but I don't know how I can do it
app.pbar_start()
file = app.filena()
#do some work
def main():
root = tk.Tk()
app = Example(root)
root.mainloop()
if __name__ == "__main__":
main()
I have tried to place work under the main but it didn't work because when I tried to click the button another window popped up.
Thank you for your help.
I would like to create a program which does the following thing via a GUI:
1.) Choose a directory in which some new directories will be created
2.) give those new directories names by using an entry widget.
Since the program is rather going to be large, I would like to split up my code into several modules which causes me some problems
What I have done so far is the following thing:
I have a "main"-program using.py
import os, sys
import Tkinter
import tkFileDialog
#import own modules
import Gui
root = Tkinter.Tk()
root.withdraw()
directory='some path'
tempdir = tkFileDialog.askdirectory(parent=root, initialdir=directory,
title='Please choose a location for your directory')
n2=Gui.DirectoryCreator()
n2.mainloop()
The module Gui looks like this
import Tkinter as tk
class DirectoryCreator(tk.Tk):
text=''
def __init__(self):
tk.Tk.__init__(self)
self.label=tk.Label(self, text='Enter the name of the directory')
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Name Of Folder",width=15, command=self.on_button)
self.label.grid(row=0,column=0)
self.button.grid(row=0,column=2)
self.entry.grid(row=0,column=1)
def on_button(self):
text= self.entry.get()
self.quit()
Now, the point is that I somehow need to get the value of the string 'text' in the module using.py. If I try something like n2.text, the streing n2.text is simply empty, e.g. n2.text="". How can I get this string?
In on_button, use self.text = self.entry.get(). Just using text is like declaring a new variable instead of using the text already bound to the DirectoryCreator instance.
def on_button(self):
self.text= self.entry.get()
self.quit()
I wrote a script in a .py file that I would like to call from another main file of my program. But when I do that, it does not initialize and give the same output as when runned directly.
here's the code of the main file where I import the subTest file as a module and call it when the user clicks on a button:
#!/usr/bin/python
import tkinter as tk
from tkinter import ttk
import subTest
from subTest import SubTest
class Window(tk.Tk):
def __init__(self, parent):
tk.Tk.__init__(self, parent)
tk.Tk.wm_title(self, "Test")
self.parent = parent
self.initialize()
def initialize(self):
self.geometry("600x300+30+30")
label = tk.Label(self, text="Test")
label.pack(pady=20,padx=10)
self.button = ttk.Button(self, text='gotosubtest', command = self.callsubtest)
self.button.pack()
def callsubtest(self):
app = SubTest(None)
app.mainloop()
if __name__ == "__main__":
window = Window(None)
window.mainloop()
and here's the code of the subTest file containing an Entry text box which should be initialized at 320. This is a simplified example of the problem. when subTest is executed directly, this Entry default value is shown in the text box. But when subTest is called from the main, the value is not shown.
Any idea what's wrong with my code? thanks in advance to all useful tips for a python beginner ;)
#!/usr/bin/python
import tkinter as tk
from tkinter import Entry
class SubTest(tk.Tk):
def __init__(self, parent):
tk.Tk.__init__(self, parent)
tk.Tk.wm_title(self, "SubTest")
self.parent = parent
self.initializesubtest()
def initializesubtest(self):
self.geometry("510x480")
self.minx = tk.DoubleVar()
self.minx.set(320)
Entry(self, textvariable=self.minx,width=5).grid(row=21,column=1)
tk.Label(self, text="Min X").grid(row=22,column=1)
if __name__ == "__main__":
app = SubTest(None)
app.mainloop()
You can only have a single instance of Tk in a program. When you use that other module you are creating a second root window. For you to be able to use that second module in the first, it cannot create its own root window.
The scenario is that i want to:
-Open a specific text file
-Import text from text file to be shown in a text widget
-Then the text from the text widget to then replace what was in the text file before, with what is currently in the text widget.
Currently i have worked out how to open the specific text file into the text widget and for it to be displayed however i can not figure out how to do the last step.
I have tried to define a 'Save' function however have not got anywhere, you can see this below.
Current code for step 1 and 2:
class PropertynewsA(Propertynews):
def __init__(self):
Propertynews.__init__(self)
def save():
file.write(txt)
file.close()
messagebox.showinfo('Saved!','Your Message has been Saved')
self.delete
file = open('PropertynewsA.txt', 'r+') #Text file i am using
with open('PropertynewsA.txt') as file: # Use file to refer to the file object
data = file.read() #date=current text in text file
#Text widget
Time = strftime("%d %b %Y\n")#getting gmt time
txt = Text(self.GenericGui,height=14, width=53,font=('TkDefaultFont',12)) #Creating text widget
txt.insert('1.0',data) #showing text from text file in widget
txt.tag_configure('format', background='lightblue', font='helvetica 14 bold', relief='raised')
txt.focus()
txt.place(x=8,y=40) #places text widget
If anyone can assist me here that would be great
Cheers guys
Once you know how the Widget indices work and you know the insert and get methods on the Text widget:
starting_text = "THIS WOULD COME FROM A FILE"
...
textbox = TEXT_WIDGET_SETUP_ALREADY
textbox.insert("1.0",starting_text)
...
ending_text = textbox.get("1.0","end-1c")
The tricky part is accessing the text while the program is closing but not after the widget is destroyed (or you get a _tkinter.TclError: invalid command name ".4384096888" error):
import tkinter as tk
class Text(tk.Text):
def destroy(self):
global ending_text
ending_text = self.get("1.0","end-1c")
super(Text,self).destroy()
although if you use from tkinter import * notation you will need to call your class something other then Text as well as probably not using ending_text as a global variable, but that was the easiest way to show how to do it.
This is the full code I used for testing with IO, although if you don't understand how to work with files already there are references elsewhere.
import tkinter as tk
filename = "test.txt"
class Text(tk.Text):
def destroy(self):
global ending_text
ending_text = self.get("1.0","end-1c")
super(Text,self).destroy()
try:
with open(filename) as f:
text = f.read()
except IOError:
text = ""
root = tk.Tk()
textbox = Text(root)
textbox.insert("1.0",text)
textbox.grid()
#this would probably just be put in the destroy method
def finish(event=None):
with open(filename,"w") as f:
f.write(ending_text)
textbox.bind("<Destroy>",finish) #this will happen after Text.destroy() so textbox.get() fails if used from this point
root.mainloop()
I created a simple user interface that will allow you to open the text file of your choice from a file dialog. I prefer to set the options of this later apart for scalability reasons (in case you would love, in the future, to read document files instead, for instance):
# Opening file options
self.file_options={}
self.file_options['defaultextension'] = '.txt'
self.file_options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
self.file_options['parent'] = self.parent
self.file_options['title'] = 'Open a text file'
self.file_options['initialdir']='/home/'
I am runing Linux, so in case you're on MS Windows OS, you may change self.file_options['initialdir']='/home/' to whatever directory path you want. Note that you can also remove it, in which case the file dialog window will prompt you to the directory where you are running the application, by default.
The method initialize_user_interface() does what its name reflects. Mainly, it offers a comfortable way to exit the application on a click and choose the file to read:
self.filemenu.add_command(label="Open",command=self.text_replacement)
self.filemenu.add_command(label="Exit",command=self.parent.quit)
You can then add a Text widget. Preferably, it is better to have a scrollable text zone in case you stumble on a large content file.
For this, you need to create the scrollbar, and attach it to the Text widget because the Text widget do not maintain its own scrollbars.
Here is the complete program:
'''
Created on Feb 25, 2016
#author: begueradj
'''
import Tkinter # Tkinter -> tkinter in Python3
import Tkconstants
import tkFileDialog
class Begueradj(Tkinter.Frame):
""" Get text file content and past it into a scrollable Text widget.
Replace the content of the file with the pre-existing Text widget content.
"""
def __init__(self,parent):
""" Set some class variables:
mainly the file dialog interface options.
"""
Tkinter.Frame.__init__(self,parent)
self.parent=parent
# Opening file options
self.file_options={}
self.file_options['defaultextension'] = '.txt'
self.file_options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
self.file_options['parent'] = self.parent
self.file_options['title'] = 'Open a text file'
self.file_options['initialdir']='/home/'
self.initialize_user_interface()
def initialize_user_interface(self):
""" Design of the user interface.
It mainly consists of a bar menu and a horizontally & vertically
scrollable Text widget in case the text file to read is large.
"""
self.parent.title("Text replacement")
# Set the bar menu and its items
self.menubar=Tkinter.Menu(self.parent)
self.filemenu=Tkinter.Menu(self.menubar,tearoff=0)
self.filemenu.add_command(label="Open",command=self.text_replacement)
self.filemenu.add_command(label="Exit",command=self.parent.quit)
self.menubar.add_cascade(label="File",menu=self.filemenu)
self.parent.config(menu=self.menubar)
self.parent.grid_rowconfigure(0,weight=1)
self.parent.grid_columnconfigure(0,weight=1)
# Set the horizontal and vertical scrollbars
self.hscrollbar=Tkinter.Scrollbar(self.parent,orient=Tkconstants.HORIZONTAL)
self.hscrollbar.grid(row=1,column=0,sticky=Tkinter.E+Tkinter.W)
self.vscrollbar=Tkinter.Scrollbar(self.parent)
self.vscrollbar.grid(row=0,column=1,sticky=Tkinter.N+Tkinter.S)
# Set the Text widget and make it scrollable
self.text=Tkinter.Text(self.parent,wrap=Tkinter.NONE,bd=0,
xscrollcommand=self.hscrollbar.set,
yscrollcommand=self.vscrollbar.set)
self.text.grid(row=0,column=0,sticky=Tkinter.E+Tkinter.W+Tkinter.S+Tkinter.N)
self.text.insert("1.0","Original text here")
self.hscrollbar.config(command=self.text.xview)
self.vscrollbar.config(command=self.text.yview)
def text_replacement(self):
""" Return the name of a file
opened in read mode
"""
self.filename = tkFileDialog.askopenfilename(**self.file_options)
if self.filename:
self.original=self.text.get("0.0","end-1c")
print self.original
with open(self.filename) as self.filetoread:
self.txtfilecontent=self.filetoread.read()
self.filetoread.close()
self.text.delete("1.0", Tkinter.END) # Erase the previous Text widget content
self.text.insert("1.0", self.txtfilecontent)
with open(self.filename,'w') as self.filetowrite:
self.filetowrite.write(self.original)
self.filetowrite.close()
def main():
""" Main method to be executed.
Instantiate Begueradj class
"""
root=Tkinter.Tk()
b=Begueradj(root)
root.geometry("300x250+300+300")
root.mainloop()
if __name__=="__main__":
""" Run the application
"""
main()
Application demo:
The demo consists of 3 screenshots showing:
Original text set into the Text widget and a file dialog window to pick up the file to read.
Loading the content of file1.txt into Tkinter.Text widget
Check if the original file of the Text widget is saved (replaces) in file1.txt
I have a tkinter menu that lets the user choose some functions. I would like if the output of that functions was presented on a texbox in Tkinter instead of the Shell. Im very unexperienced with Tkinter. I donĀ“t have any ideia how to do it..
Some of the functions require inputs of the user, is it possible for the user to input directly from Tkinter Gui?
The code for the menu of the program:
the functions: situacaocorrente(), findfuncionario(), verhistorico() are not presented here.
CODE
from Tkinter import Tk, Frame, Menu, Label, Text
import sys
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.output = Text(self)
self.output.pack()
sys.stdout = self
self.initUI()
def initUI(self):
self.parent.title("High Flex")
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="Procurar funcionario", command=self.procurarfuncionario)
fileMenu.add_command(label="Ver Historico", command=self.historico)
fileMenu.add_command(label="Verificar Onde se encontram os funcionarios", command=self.funcionariosturno)
fileMenu.add_command(label="Sair", command=self.onExit)
menubar.add_cascade(label="INICIAR", menu=fileMenu)
def funcionariosturno(self):
situacaocorrente()
def procurarfuncionario(self):
findfuncionario()
def historico (self):
verhistorico()
def onExit(self):
self.quit()
def write(self, txt):
self.output.insert(END,str(txt))
def main():
root = Tk()
root.geometry("250x150+300+300")
app = Example(root)
root.mainloop()
You can use Entry() to get user input. See more on: An Introduction to Tkinter
I don't know what functions output you try to put in self.output - from external program in shell or from python function.
sys.stdout = self works only with Python functions like print