Adding .txt, .png and other options for savecommand - python

So I have started a minor text editor project in python 3 and I have managed to add a save button with a function to save the document, but I want to add the options of choosing between .txt, .png and other for the save command. How could I do that?
from tkinter import * # Imports everything from tkinter
import tkinter
from tkinter import filedialog
class Window(Frame): # Frame is a class in tkineter and we are creating a
frame or a window
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master #Mainframe or main window
self.init_window()
def init_window(self): #
self.master.title("GUI") #windows title is GUI
self.pack(fill=BOTH, expand=1) # Adjust window as we want, but also
fill up the window as a defult
menu =Menu(self.master)
self.master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Open File')
file.add_command(label='New File')
file.add_command(label='Save as')
file.add_command(label='Save', command=self.file_save)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='Undo')
edit.add_command(label='Redo')
menu.add_cascade(label='Edit', menu=edit)
def file_save(self):
f = filedialog.asksaveasfile(mode='w', defaultextension=".txt")
if f is None:
return
text2save = str(text.get(1.0, END))
f.write(text2save)
f.close()
def client_exit(self):
exit()
root = Tk() #
root.geometry("400x300") #Specify the dimention of the window as 400 by
300
app = Window(root)
root.mainloop() # Generates our window for us

If you look at the documentation for asksaveasfile you can see there's a filetypes parameter. Simply fill that with a list of the file types you want.
filetypes_choices = [('Text file', '*.txt'), ('PNG Image File', '*.png')]
f = filedialog.asksaveasfile(mode='w', defaultextension=".txt", filetypes=filetypes_choices)

Related

tkinter class to class 'scroll' is not defined

I am trying to call multiple definitions and have each print their results to the ScrolledText.
If I define ScrolledText in the class MainPage, then the button OpenFile works fine , but the Menus commands do not with the 'scroll' is not defined error.
If I define ScrolledText in the class SampleApp, then the Menu OpenFile works fine , but the button commands do not with the 'scroll' is not defined error.
If I define both, then I get two scrolls that both work only in their own class.
How do I pass the scroll object between the 2 classes to use the same scroll in both class SampleApp and class MainPage?
#!/usr/bin/env python
# Python3.7.0
# Tkinter
import tkinter as tk # python 3
#from tkinter import ttk, font as tkfont, messagebox as mb, filedialog # python 3
from tkinter import ttk
import tkinter.scrolledtext as tkst
from tkinter.ttk import *
# Global scope
FilePath = "C:\Myfiles"
ScrollMsg = ""
# window definitions ----------------------------------
# Menu definitions ----------------------------------
def OpenFile(scroll): # Add a filedialog (file & directory chooser)
global FilePath, ScrollMsg
FilePath = "C:\Myfiles\file.txt"
print("filedialog path & file :\n", FilePath)
ScrollMsg = "filedialog path & file : " + FilePath
print ("SCROLL MESSAGE")
print ( ScrollMsg +"\n")
scroll.insert(tk.INSERT,ScrollMsg )
# ------------------------------------------------------
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.replace_frame(MainPage)
# scrolledtext
scroll = tkst.ScrolledText(self,width=90,height=15)
scroll.grid(column=0,row=15, columnspan = 6, sticky='W')
scroll.insert(tk.INSERT," OK here" +"\n")
# Menu for all frames ----------------------------------
menubar = tk.Menu(self)
# File
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label='Open', command=lambda: OpenFile(scroll))
menubar.add_cascade(label='File', menu=filemenu)
self.config(menu=menubar)
def replace_frame(self, frame_class):
"""Destroys current frame and replaces it with a new one."""
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.grid()
# FRAME CLASSES --------------------------------------
class MainPage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
lbl1 = tk.Label(self, text="File selection: ")
lbl1.grid(column=0, row=1)
lbl2 = tk.Label(self, text="File Path")
lbl2.grid(column=0, row=2)
_FP_ = Entry(self,width=30)
_FP_.insert(0,FilePath) #set the item
_FP_.grid(column=1, row=2)
btn = Button(self, text='OpenFile', command=lambda: OpenFile(scroll))
btn.grid(column=0, row=4)
# scrolledtext
'''
scroll = tkst.ScrolledText(self,width=90,height=15)
scroll.grid(column=0,row=15, columnspan = 6, sticky='W')
scroll.insert(tk.INSERT," OK here" +"\n")
'''
_FP_.focus() # Place cursor into File Name Entry
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I'm not sure I understand exactly what you're trying to accomplish, but think I can answer your question about having a ScrolledText that will work with both of the classes — SampleApp and MainPage — at the same time.
To do this I've added another class named SingleScroll which is what is known as a "singleton" class, because it restricts the number of instances of it that can be created to just a "single" one.
It's used by both SampleApp and MainPage just like a regular class, and the object returned from calling it is passed to the OpenFile() function as an argument for the Menu or Button commands in the respective classes.
import tkinter as tk # python 3
#from tkinter import ttk, font as tkfont, messagebox as mb, filedialog # python 3
from tkinter import ttk
import tkinter.scrolledtext as tkst
from tkinter.ttk import *
# Global scope
FilePath = r"C:\Myfiles"
ScrollMsg = ""
# window definitions ----------------------------------
# Menu definitions ----------------------------------
def OpenFile(scroll): # Add a filedialog (file & directory chooser)
global FilePath, ScrollMsg
FilePath = r"C:\Myfiles\file.txt"
print("filedialog path & file :\n", FilePath)
ScrollMsg = "filedialog path & file : " + FilePath
print("SCROLL MESSAGE")
print(ScrollMsg + "\n")
scroll.insert(tk.INSERT, ScrollMsg + "\n" )
# SHARED SCROLL CLASS (ADDED) --------------------------
class SingleScroll:
""" Singleton ScrolledText object. """
def __new__(cls, master):
if '_inst' not in vars(cls): # Create instance?
scroll = tkst.ScrolledText(master, width=90, height=15)
scroll.grid(column=0, row=15, columnspan=6, sticky='W')
scroll.insert(tk.INSERT, " OK here\n")
cls._inst = scroll
return cls._inst
# ------------------------------------------------------
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.replace_frame(MainPage)
scroll = SingleScroll(self) # ScrolledText
# Menu for all frames ----------------------------------
menubar = tk.Menu(self)
# File
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label='Open', command=lambda: OpenFile(scroll))
menubar.add_cascade(label='File', menu=filemenu)
self.config(menu=menubar)
def replace_frame(self, frame_class):
"""Destroys current frame and replaces it with a new one."""
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.grid()
# FRAME CLASSES --------------------------------------
class MainPage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
lbl1 = tk.Label(self, text="File selection: ")
lbl1.grid(column=0, row=1)
lbl2 = tk.Label(self, text="File Path")
lbl2.grid(column=0, row=2)
_FP_ = Entry(self,width=30)
_FP_.insert(0,FilePath) #set the item
_FP_.grid(column=1, row=2)
scroll = SingleScroll(master) # ScrolledText
btn = Button(self, text='OpenFile', command=lambda: OpenFile(scroll))
btn.grid(column=0, row=4)
_FP_.focus() # Place cursor into File Name Entry
if __name__ == "__main__":
app = SampleApp()
app.mainloop()

tkinter display new frame from menu

I'm trying to write my fisrt script in python & tkinter.
I block to display a new frame from a function (def onDisplay) when a click is made from menu bar button, but nothing append.
No error is display :-(
The new frame is made with dynamic checkboxes from text files:
txt file:
item1
item2
...
item100
A screen of the GUI:
Here my code:
from tkinter import Tk, Frame, Menu, Checkbutton, Text, TOP, BOTH, X, N, LEFT, BooleanVar
from tkinter.ttk import Frame, Label, Entry
import glob
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
#self.display_srv()
def initUI(self):
self.master.title("Submenu")
menubar = Menu(self.master)
self.master.config(menu=menubar)
fileMenu = Menu(menubar)
submenu = Menu(fileMenu)
submenu.add_command(label="lst1", command=self.onDisplay)
submenu.add_command(label="lst2")
submenu.add_command(label="lst3")
fileMenu.add_cascade(label='Listing', menu=submenu, underline=0)
fileMenu.add_separator()
fileMenu.add_command(label="Exit", underline=0, command=self.onExit)
menubar.add_cascade(label="File", underline=0, menu=fileMenu)
#The frame i tried to display
def onDisplay(self):
self.master.title("display it")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack(fill=X)
path = '/root/liste/*.txt'
files=glob.glob(path)
count = 0
for file in files:
with open(file, 'r') as lst_file:
for item in lst_file:
# Need to split all item by 10
Checkbutton(self, text=item.rstrip()).grid(row=count//10, column=count%10)
count += 1
def onClick(self):
if self.var.get() == True:
self.master.title("Checkbutton")
else:
self.master.title("")
def onExit(self):
self.quit()
def main():
root = Tk()
root.geometry("850x550+300+300")
app = Example()
root.mainloop()
if __name__ == '__main__':
Many thanks for any help
Regards,
The main problem is that you're mixing grid and pack in the same parent container. You are calling pack on frame1 but you are calling grid on the checkbuttons, and they both have a master or parent of self.
That can't work, because each of grid and pack will try to resize the container according to it's rules, triggering the other one to reconfigure according to it's rules, and so on until the end of time.
So, simply changing your call of .grid(...) to .pack(...) on the checkbuttons will fix that problem.
My guess is that you intended to put the checkbuttons inside frame1. If that's the case, you need to specify frame1 as the master for the checkbuttons. For readability and ease of debugging I also recommend placing the call to grid on a separate line. With that, you can continue to use grid for the checkbuttons and pack for everything else.
cb = Checkbutton(frame1, text=item.rstrip())
cb.grid(row=count//10, column=count%10)
I posted the correct code:
from tkinter import Tk, Frame, Menu, Checkbutton, Text, TOP, BOTH, X, N, LEFT, BooleanVar
from tkinter.ttk import Frame, Label, Entry
import glob
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
#self.display_srv()
def initUI(self):
self.master.title("Submenu")
menubar = Menu(self.master)
self.master.config(menu=menubar)
fileMenu = Menu(menubar)
submenu = Menu(fileMenu)
submenu.add_command(label="lst1", command=self.onDisplay)
submenu.add_command(label="lst2")
submenu.add_command(label="lst3")
fileMenu.add_cascade(label='Listing', menu=submenu, underline=0)
fileMenu.add_separator()
fileMenu.add_command(label="Exit", underline=0, command=self.onExit)
menubar.add_cascade(label="File", underline=0, menu=fileMenu)
def onDisplay(self):
self.master.title("display it")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack(fill=X)
path = '/root/liste/*.txt'
files=glob.glob(path)
count = 0
for file in files:
with open(file, 'r') as lst_file:
for item in lst_file:
cb = Checkbutton(frame1, text=item.rstrip())
cb.grid(row=count//10, column=count%10)
count += 1
def onClick(self):
if self.var.get() == True:
self.master.title("Checkbutton")
else:
self.master.title("")
def onExit(self):
self.quit()
def main():
root = Tk()
root.geometry("850x550+300+300")
app = Example()
root.mainloop()
if __name__ == '__main__':
main()

tkinter Python 3 Menu Error - Nothing Loads?

import sys
import time
import tkinter
from tkinter import *
import tkinter.messagebox as tm
from tkinter.filedialog import *
from sys import exit
class AppUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master, relief=SUNKEN, bd=2)
self.menubar = Menu(self)
filemenu = Menu(self.menubar, tearoff=0)
filemenu.add_command(label="New", command=self.NewFile)
filemenu.add_command(label="New", command=self.OpenFile)
self.menubar.add_cascade(label="File", menu=filemenu)
menu = Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Edit", menu=menu)
menu.add_command(label="Cut")
menu.add_command(label="Copy")
menu.add_command(label="Paste")
def OpenFile():
name = askopenfilename
askopenfilename()
def NewFile():
tm.showerror("ERROR", "Cannot Open New File!")
try:
self.master.config(menu=self.menubar)
except AttributeError:
self.master.tk.call(master, "config", "-menu", self.menubar)
self.canvas = Canvas(self, bg="white", width=400, height=400,
bd=0, highlightthickness=0)
self.canvas.pack()
root = Tk()
app = AppUI(root)
app.pack()
root.mainloop()
I can't seem to work this .py file, I am new-ish to coding with python, I have asked and looked about, but I can't seem to find the answer. I have tried to make a class with a menu in it, but the error seems to always say "self is not defined"
Thanks
You see nothing because your frame has a default size of 0x0 since there is nothing inside.
Frame.__init__(self, master, relief=SUNKEN, bd=2, width=200, height=200)
should make it visible. Furthermore, I advise you to make your AppUI class inherit from Tk or Toplevel instead of Frame so that you can directly use self.configure(menu=self.menubar) to display the menu.
Also, def OpenFile(): should be replaced by def OpenFile(self): otherwise you will get the error TypeError: OpenFile() takes 0 positional arguments but 1 was given when you call self.OpenFile() (and the same is true for NewFile).

Updating status bar with opened file name

With amazing help of other stackoverflow users I have made this code for reading out some data out of a gcode file and doing some calculations on it. It is almost done and the last 2 things I have problem with are:
1) I would like the status bar update to display message "File [name of the uploaded file] is uploaded" after the gcode file will be uploaded with the button.
2) I would like to make executable for the program so it can be standalone and work on Mac OS and Windows. I have downloaded and installed (I am on mac) pyinstaller and I am performing some actions on my .py file, the end result looks like ready applications but they don't work.
Thank you in advance for help and all the inputs, I am a complete newbie in python but I have already learned so much from you.
This is the sample gcode file for tests: sample GCODE
And this is the code:
from tkinter import *
import re
from tkinter import messagebox
from tkinter import filedialog
# Here, we are creating our class, Window, and inheriting from the Frame
# class. Frame is a class from the tkinter module. (see Lib/tkinter/__init__)
class Window(Frame):
# Define settings upon initialization. Here you can specify
def __init__(self, master=None):
# parameters that you want to send through the Frame class.
Frame.__init__(self, master)
#reference to the master widget, which is the tk window
self.master = master
#with that, we want to then run init_window, which doesn't yet exist
self.init_window()
# Load the gcode file in and extract the filament value
def get_filament_value(self, fileName):
with open(fileName, 'r') as f_gcode:
data = f_gcode.read()
re_value = re.search('filament used = .*? \(([0-9.]+)', data)
if re_value:
return float(re_value.group(1))
else:
return 0.0
def read_gcode(self):
root.fileName = filedialog.askopenfilename(filetypes = (("GCODE files", "*.gcode"), ("All files", "*.*")))
volume = self.get_filament_value(root.fileName)
mass = volume * 1.13
price = mass * 0.175
self.volume_text.set('Volume is {:.2f} cm3'.format(volume))
self.mass_text.set('Mass is {:.2f} g'.format(mass))
self.price_text.set('Price is {:.2f} DKK'.format(price))
def client_exit(self):
exit()
def about_popup(self):
messagebox.showinfo("About", "This software is created by Bartosz Domagalski and helps to find used filament parameters from Sli3er generated GCODE")
#Creation of init_window
def init_window(self):
# changing the title of our master widget
self.master.title("Filament Data")
# allowing the widget to take the full space of the root window
self.pack(fill=BOTH, expand=1)
# creating a menu instance
menu = Menu(self.master)
self.master.config(menu=menu)
# create the file object)
file = Menu(menu)
help = Menu(menu)
# adds a command to the menu option, calling it exit, and the
# command it runs on event is client_exit
file.add_command(label="Exit", command=self.client_exit)
help.add_command(label="About", command=self.about_popup)
#added "file" to our menu
menu.add_cascade(label="File", menu=file)
menu.add_cascade(label="Help", menu=help)
#Creating the labels
l_instruction = Label(self, justify=CENTER, compound=TOP, text="Load GCODE file to find volume, \n weight and price of used filament.")
l_instruction.pack()
#Creating the button
gcodeButton = Button(self, text="Load GCODE", command=self.read_gcode)
gcodeButton.pack()
# gcodeButton.place(x=60, y=50)
#Label of the used filament
l1 = Label(self, text="")
l1.pack()
l2 = Label(self, text="")
l2.pack()
l3 = Label(self, text="")
l3.pack()
self.volume_text = StringVar()
l = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.volume_text)
l.pack()
l4 = Label(self, text="")
l4.pack()
self.mass_text = StringVar()
m = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.mass_text)
m.pack()
l5 = Label(self, text="")
l5.pack()
self.price_text = StringVar()
p = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.price_text)
p.pack()
#status Bar
status = Label(self, text="Waiting for file... ", bd=1, relief=SUNKEN, anchor=W)
status.pack(side=BOTTOM, fill=X)
# root window created. Here, that would be the only window, but you can later have windows within windows.
root = Tk()
root.resizable(width=False,height=False);
root.geometry("220x300")
#creation of an instance
app = Window(root)
#mainloop
root.mainloop()

Scrollbar implemented into textbox

I'm trying to create a fairly simple e-reader, and I've managed to use tkinter to create something akin to one. But what I can't seem to work out is how to create a scrollbar to allow the user to scroll through the text at will. I can get it working in other pieces of coding, but I can't make it work within this program and I can't work out what the problem is. I've put my simple e-reader, without the attempted scrollbar below.
from Tkinter import *
import tkFileDialog
import ScrolledText
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("File dialog")
self.pack(fill=BOTH, expand=1)
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="Open", command=self.onOpen)
menubar.add_cascade(label="File", menu=fileMenu)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
def onOpen(self):
ftypes = [('Python files', '*.py'), ('All files', '*')]
dlg = tkFileDialog.Open(self, filetypes = ftypes)
fl = dlg.show()
if fl != '':
text = self.readFile(fl)
self.txt.insert(END, text)
def readFile(self, filename):
f = open(filename, "r")
text = f.read()
return text
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
def main():
root = Tk()
ex = Example(root)
root.geometry("300x250+300+300")
root.mainloop()
if __name__ == '__main__':
main()
Adding a scrollbar to a text widget requires you to do two things in addition to creating the actual widgets:
you must set the yscrollcommand attribute of the text widget to point to the set method of the scrollbar
you must set the command attribute of the scrollbar to point to the yview method of the text widget
For example:
self.text.configure(yscrollcommand=self.scrollbar.set)
self.scrollbar.configure(command=self.text.yview)
I've long wondered whether this could really be the answer to your question, but after the discussion in the comments, it seems it is: You just put the code creating the ScrolledText in the wrong place!
Try moving these three lines (that are now outside of the class, causing a NameError for self)
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
to where these lines are in your initUI method (replace these lines)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
With other words, in your initUI method, instead of creating a Text widget, create a ScrolledText. Also, change import ScrolledText to from ScrolledText import ScrolledText so that ScrolledText is the actual widget, and not the module defining the widget.

Categories

Resources