My main Python program (script to most) has elaborate import statements I'd rather not repeat in modules I import:
from __future__ import print_function # Must be first import
from __future__ import with_statement # Error handling for file opens
try:
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.font as font
import tkinter.filedialog as filedialog
import tkinter.messagebox as messagebox
PYTHON_VER="3"
except ImportError: # Python 2
import Tkinter as tk
import ttk
import tkFont as font
import tkFileDialog as filedialog
import tkMessageBox as messagebox
PYTHON_VER="2"
# print ("Python version: ", PYTHON_VER)
import subprocess32 as sp
import sys
import os
import time
import datetime
from PIL import Image, ImageTk, ImageDraw, ImageFont
import pickle
from random import shuffle
import getpass # Get user name for file storage
import locale # To set thousands separator as , or .
locale.setlocale(locale.LC_ALL, '') # Use '' for auto
# mserve modules
import location as lc # Home grown module
As my program/script approaches 5,000 lines I've come over to the light side / (Dark side?) and started using imported modules of my own design. The first module is called location.py but!, lo and behold I've had to repeat import statements already imported in the parent program mserve.
EG at header:
from __future__ import print_function # Must be first import
import getpass
import os
import pickle
import time
And just tonight on a new function I'm writing:
import Tkinter as tk
class MsgDisplay:
''' Text Widget with status messages
'''
def __init__(self, title, toplevel, width, height):
self.line_cnt = 0 # Message lines displayed so far
toplevel.update_idletasks() # Get up-to-date window co-ords
x = toplevel.winfo_x()
y = toplevel.winfo_y()
w = toplevel.winfo_width()
h = toplevel.winfo_height()
xd = (w/2) - (width/2)
yd = (h/2) - (height/2)
print('x:',x,'y:',y,'w:',w,'h:',h,
'width:',width,'height:',height,'xd:',xd,'yd:',yd)
''' Mount message textbox window at centered in passed toplevel '''
self.msg_top = tk.Toplevel()
self.textbox = tk.Text(self.msg_top, height=height, width=width)
self.msg_top.geometry('%dx%d+%d+%d'%(width, height, x + xd, y + yd))
# self.textbox.columnconfigure(0, weight=1)
# self.textbox.rowconfigure(0, weight=1)
self.textbox.pack()
self.textbox.insert(tk.END, "Just a text Widget\nin two lines\n")
def Update(self, msg_list):
self.textbox.insert(tk.END, "Just a text Widget\nin two lines\n")
time.sleep(.1)
def Close(self):
self.msg_top.destroy()
The new import I just added:
import Tkinter as tk
Is a shortcut / fudge because production version would need to be:
try:
import tkinter as tk
except ImportError: # Python 2
import Tkinter as tk
Before preaching python 2.7.12 is obsolete please note I'm using Ubuntu 16.04 whose EOL is 2021. Also note we use Windows 2008 Server at work and legacy systems written in COBOL are common so who cares?
I must be doing something wrong because a module that is imported should not have to import what parent already did? In a normal environment the child should know / inherent what the parent already knows.
As an aside, tonight's new class "MsgDisplay" should be in parent and not in child. It was simpler to put the class in the child rather than figuring out how a child could call a parent class.
I must be doing something wrong because a module that is imported should not have > to import what parent already did? In a normal environment the child should know > inherent what the parent already knows.
You are describing a cpp-like include system where declarations are just placed in order in a single translation unit. That doesn't apply to python. Importing the same module everywhere you use it is necessary. Think about importing as binding the modules contents to the local namespace. If you use module A contents in module B you need to import it in B even if module C already imports A and later B. Don't worry too much about performance. Once a module is loaded by python interpreter remaining imports are not very expensive.
Related
Im using PIL and TKinter to open an image. I do not understand why I'm getting this error
import os
import random
from PIL import Image
import time
from tkinter import *
root = Tk()
def timer(mins):
time.sleep(mins * 60)
def anmuViewer():
random_pic = (random.choice(os.listdir("D:/de_clutter/memez/anmu")))
openPic = Image.open('D:/de_clutter/memez/anmu/' + random_pic)
openPic.show()
timer(3)
start_btn = Button(root, text = "Start", command = anmuViewer)
start_btn.pack()
root.mainloop()
what should happen is a tkinter window should pop up with only a button called "start". When I click that button, a new window with the image should pop up. instead I get this error
line 17, in anmuViewer
openPic = Image.open('D:/de_clutter/memez/anmu/' + random_pic)
AttributeError: type object 'Image' has no attribute 'open'
Like Michael Butscher said,
"tkinter.Image" overwrites "PIL.Image" in your module's namespace. Avoid imports with *
But if you must use a wildcard import, importing tkinter before PIL should solve your problem
from tkinter import *
import os
import random
from PIL import Image
import time
from tkinter import *
from tkinter import messagebox
root = Tk()
messagebox.showinfo("Hello world", "you are the best")
root.mainloop()
Why do I have to have to import messagebox explicitly when I am import all using *
messagebox is a submodule of the tkinter package.
The wildcard import syntax doesn't import submodules, only the names that are defined in the tkinter package itself.
Therefore you need to import the messagebox submodule explicitly.
References
https://docs.python.org/3/library/tkinter.html#tkinter-modules
https://docs.python.org/3/reference/simple_stmts.html#the-import-statement
Relevant tkinter sources
https://github.com/python/cpython/blob/3.6/Lib/tkinter/__init__.py
https://github.com/python/cpython/blob/3.6/Lib/tkinter/messagebox.py
I for example i have 2 files, mother.py and child.py,
child.py is module that is imported in mother.py
Code in mother.py is:
from tkinter import *
from tkinter import ttk
from modules.child import LoginWindow
root = Tk()
window = LoginWindow(root)
root.mainloop()
Code in child.py is:
class LoginWindow:
def __init__(self, master):
self.master = master
self.content = ttk.Frame(self.master, padding=(20,30,20,30))
And when i do this it give me an error that says that tkk ( in last line of child.py ) is not defined but it is defined in mother.py ( line 2 ) why is not this working and what is the best way to make something like this work
An import in Python isn't like an "include" in other languages. The entire module is contained inside an object named after the module you imported. So, when you do this:
from modules.child import LoginWindow
The entire module is contained inside the object/variable LoginWindow. The "child" module in this case cannot see what variables are defined inside the module that imported it.
In the example in your question, you want to move:
from tkinter import ttk
To child.py.
I am using a calendar widget for Python. And I need to call the widget when a button is clicked.
The situation is that I cannot find what is the method in the calendar class that displays the widget itself.
The calendar class was taken from here:
http://www.eurion.net/python-snippets/snippet/Calendar_Date%20picker.html
Here are my imports:
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import time
import requests #needs to be installed
import pymysql #needs to be installed
import csv
import win32com.client #needs to be installed
from calendar import Calendar
import datetime
Here is the button creation:
# Calendar Buttons
calBut=ttk.Button(f2, width=4, text="Cal", command=Calendar.what_method?).grid(column=3,row=1, sticky=W)
As far as I know, I can just set the command of the button to call the widget display method located in the calendar class.
How to get the method that displays the calendar widget each time my button is clicked? None of the ones showing are displaying the widget.
Using Python 3.3.5
Spider
WinPython 3.3.5
**EDIT**
The program has tabs and the f2 indicates the tab where the button will be.
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import time
import requests #needs to be installed
import pymysql #needs to be installed
import csv
import win32com.client #needs to be installed
import datetime
from calendar import Calendar
import calendar
#################################
# Create Button Click Calendar
def callback():
root2=Toplevel(f2)
ttkcal = Calendar(root2,firstweekday=calendar.SUNDAY)
ttkcal.pack(expand=1, fill='both')
root2.update()
root2.minsize(root2.winfo_reqwidth(), root2.winfo_reqheight())
# Calendar Buttons
b=ttk.Button(f2, width=4, text="Cal", command=callback).grid(column=3,row=1, sticky=W)
When I press the button, it opens the calendar window, but it is empty. And the console gives me error:
TypeError: __init__() got multiple values for argument 'firstweekday
Thank you
Not so easy. The problem is that you mix the two GUI libraries. Therefore it is necessary two main event loops (at least): one for Tkinter code and one for PyQt code.
One way to do what you want - using subprocess and threading modules to run calendar.py in different thread. Example:
from tkinter import *
from tkinter import ttk
import subprocess
import threading
master = Tk()
def callback():
subprocess.call('python calendar.py')
b=ttk.Button(master, width=4, text="Cal", command=lambda:threading.Thread(target=callback).start()).grid(column=3,row=1, sticky=W)
mainloop()
Another way - creating Qt main event loop inside callback function (dirty solution):
from tkinter import *
from tkinter import ttk
from calendar import Calendar
import sys
from PyQt4 import QtGui
master = Tk()
def callback():
app = QtGui.QApplication(sys.argv)
gui = Calendar()
gui.show()
app.exec_()
b=ttk.Button(master, width=4, text="Cal", command=callback).grid(column=3,row=1, sticky=W)
mainloop()
EDIT: How to call widget.
First of all, look at this answer, and modify your ttkcalendar.py as kalgasnik suggested. Then try this:
from tkinter import *
from tkinter import ttk
from ttkcalendar import Calendar
import calendar
master = Tk()
def callback():
root2=Toplevel(master)
ttkcal = Calendar(root2,firstweekday=calendar.SUNDAY)
ttkcal.pack(expand=1, fill='both')
root2.update()
root2.minsize(root2.winfo_reqwidth(), root2.winfo_reqheight())
b=ttk.Button(master, width=4, text="Cal", command=callback).grid(column=3,row=1, sticky=W)
mainloop()
EDIT 2. Solving the problems
Ok, it seems I found all problems.
Actually, you import twice the same module - standard calendar module:
from calendar import Calendar
import calendar
But you do not import the class Calendar from ttkcalendar module (Do not forget to change it as described
here).
So, import should look like this:
import ttkcalendar
import calendar
Creating calendar (I changed the code a bit for clarity):
ttkcal = ttkcalendar.Calendar(root2,firstweekday=calendar.SUNDAY)
In your code, the main window is initialized twice:
line 15: master = Tk()
line 960: root = Tk()
You need to remove the first initialization.
You mix pack() and grid() in the same master window. According the docs, it is a bad idea:
Warning: Never mix grid and pack in the same master window. Tkinter
will happily spend the rest of your lifetime trying to negotiate a
solution that both managers are happy with. Instead of waiting, kill
the application, and take another look at your code. A common mistake
is to use the wrong parent for some of the widgets.
So, instead nb.pack(fill='both', expand='yes') you have to write something like this
nb.grid(column=0, row=0, sticky=(W, E))
Finally, here are links to the fixed code:
ttkcalendar.py (already modified, ready to use): https://gist.github.com/anonymous/5e0d973f57e185572df2
Your script with described modifications:
https://gist.github.com/anonymous/65cb808dc64e414c0c12
Where is the tkFileDialog module in Python 3? The question Choosing a file in Python with simple Dialog references the module using:
from Tkinter import Tk
from tkFileDialog import askopenfilename
but using that (after changing Tkinter to tkinter) in Python 3 gets:
Traceback (most recent call last):
File "C:\Documents and Settings\me\My Documents\file.pyw", line 5, in <module>
import tkFileDialog
ImportError: No module named tkFileDialog
The python 2.7.2 doc (docs.python.org) says:
tkFileDialog
Common dialogs to allow the user to specify a file to open or save.
These have been renamed as well in Python 3.0; they were all made submodules of the new tkinter package.
but it gives no hint what the new names would be, and searching for tkFileDialog and askopenfilename in the 3.2.2 docs returns nothing at all (not even a mapping from the old names to the new submodule names.)
Trying the obvious doesn't do jack:
from tkinter import askopenfilename, asksaveasfilename
ImportError: cannot import name askopenfilename
How do you call the equivalent of askopenfilename() in Python 3?
You're looking for tkinter.filedialog as noted in the docs.
from tkinter import filedialog
You can look at what methods/classes are in filedialog by running help(filedialog) in the python interpreter. I think filedialog.LoadFileDialog is what you're looking for.
You can try something like this:
from tkinter import *
root = Tk()
root.filename = filedialog.askopenfilename(initialdir = "E:/Images",title = "choose your file",filetypes = (("jpeg files","*.jpg"),("all files","*.*")))
print (root.filename)
root.withdraw()