In a script, that I am writing I need a button with a little trash bin as an icon on it. I use the code shown below:
# Python 3.7.1
import tkinter as tk
master = tk.Tk()
photo = tk.PhotoImage(file="bin.png")
icon_button = tk.Button(master, image=photo)
icon_button.pack()
The following error occurs:
_tkinter.TclError: image "pyimage1. doesn't exist
Since I specified bin.png as the image file, I cannot really understand how pyimage1 is specified in the error.
After some debugging, I realized, that the PhotoImage returns the string pyimage1, and therefore gives "pyimage1" as a parameter to the Button, but I still don't know how to fix my issue.
The problem is that Relative path won't be accepted, i.e. if you have your bin.png in C:\ then you should do as-
tk.PhotoImage(file='C:\\bin.png')
Now, if you still want to use relative paths then the following will do-
import tkinter as tk
import os
Win = tk.Tk()
Img = tk.PhotoImage(file=os.path.abspath('bin.png')
tk.Button(Win, image=Img).pack()
Win.mainloop()
Or use this-
import sys, os
def get_path(file):
if not hasattr(sys, ''):
file = os.path.join(os.path.dirname(__file__), file)
return file
else:
file = os.path.join(sys.prefix, file)
return file
It simply just gets the full path of a file.
Now, use the function-
...file=get_path('bin.png'))
Related
Tkinter doesn't open the image. We can ask the opening incorrectly, we need help. I need it to open the image through the menu. be sure to use pil, as the image can be anything. There are no errors in the syntax. Thank you = )
from tkinter import Tk, Frame, Menu, Canvas, PhotoImage
import easygui
from PIL import Image, ImageFilter, ImageTk
def input_file():
a = easygui.fileopenbox(filetypes=["*.jpg"])
original = Image.open(a)
original = original.resize((799, 799), Image.ANTIALIAS)
photoimg = ImageTk.PhotoImage(original)
canvas = Canvas(root, width=799, height=799)
imagesprite = canvas.create_image(10, 10,anchor='nw', image=photoimg)
canvas.pack()
return (imagesprite)
root = Tk()
root.title("Sputnikeca")
#root.iconbitmap('путь к иконке')
root.geometry("800x800+0+0")
my_menu = Menu(root)
root.config(menu=my_menu)
# Create a menu item
file_menu = Menu(my_menu)
my_menu.add_cascade(label = "Файл", menu=file_menu)
file_menu.add_command(label = "Импорт...", command=input_file())
file_menu.add_separator()
file_menu.add_command(label = "Выход", command=root.quit)
root.mainloop()
Here is what you have to do to solve the issue:
def input_file():
global photoimg #keeping a reference
a = easygui.fileopenbox(filetypes=["*.jpg"])
original = Image.open(a).resize((799, 799), Image.ANTIALIAS) #calling it all in one line
photoimg = ImageTk.PhotoImage(original)
canvas = Canvas(root, width=799, height=799)
imagesprite = canvas.create_image(10, 10,anchor='nw', image=photoimg)
canvas.pack()
return imagesprite
and then later remove the () around your function:
file_menu.add_command(label = "Импорт...", command=input_file)
What is being done?
In the first set of code im keeping a reference to the image so the image is not garbage collected by python. You can do so either by saying imagesprite.image = photoimg or global photoimg on top of the function. I also resized the image in the same line that I opened the image, to reduce codes.
And in the second set of codes, im just removing () so that the function is not called(invoked) before choosing the menu item.
And also tkinter itself has a filedialogbox that works like your easygui.fileopenbox(filetypes=["*.jpg"]), read some docs here
from tkinter import filedialog
a = filedialog.askopenfilename(title='Choose a file',initialdir='C:/',filetypes=(('All Files','*.*'),("JPEG
Files",'*.jpeg')))
Hope this helped you solve the error, do let me know if any doubts.
Cheers
If I am not mistaken, your menu opens as soon as you run the application, not when you click the import button.
It's because you need to pass the callback to the add_command, but you're calling the method instead
file_menu.add_command(label = "Import...", command=input_file())
Remove the () from input_file(). just pass input_file. it will not call the method directly anymore.
file_menu.add_command(label = "Import...", command=input_file)
My script, using Tkinter to create a window, gets a bitmap image with PyWin32, convert the bitmap into a Pillow Image. Then save it to test.png.
The code:
import os
from tkinter import Tk, Frame, Button
import win32gui
import win32ui
from ctypes import windll
from PIL import Image
root = Tk()
frame = Frame(root, bg="#ff0000")
button = Button(frame, bg="#7c7c7c")
button.pack(pady=10, padx=10)
frame.pack(fill="both", expand=True)
root.update()
hwnd = win32gui.GetParent(root.winfo_id())
# Change the line below depending on whether you want the whole window
# or just the client area.
left, top, right, bot = win32gui.GetClientRect(hwnd)
# left, top, right, bot = win32gui.GetWindowRect(hwnd)
w = right - left
h = bot - top
hwndDC = win32gui.GetWindowDC(hwnd)
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()
saveBitMap = win32ui.CreateBitmap()
saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
saveDC.SelectObject(saveBitMap)
# Change the line below depending on whether you want the whole window
# or just the client area.
result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 1)
# result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 0)
print(result)
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)
im = Image.frombuffer(
'RGB',
(bmpinfo['bmWidth'], bmpinfo['bmHeight']),
bmpstr, 'raw', 'BGRX', 0, 1)
win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)
if result == 1:
#PrintWindow Succeeded
im.save("test.png")
# root.wm_protocol("WM_DELETE_WINDOW", lambda: os.kill(os.getpid(), 0))
root.mainloop()
Also my idea is to have to get an image of the window, even another window overlaps it.
Even when the window is minimized.
This is the PyCharm output:
1
Process finished with exit code -1073740771 (0xC000041D)
It crashes when closing the window.
Does anyone know what's going wrong?
By the way, it seems it's happening with this bit of code: root.update(). #interflexo said that import win32ui is doing it. I think there's a conflict with these two.
Just adding this import at top of my code
import win32ui
triggers this behavior.
I want to make a simple GUI that will allow user to pick an excel file to load the data from that will later be used for math calculations. Both modules work correctly when separate. But when I try to use my GUI as an import into my main file I am unable to access the needed var without calling the class method which in turn iterates it. It is troublesome because it is supposed to use this function only after the button press.
Is there something fundamentally wrong that I am doing?
GUI script
import tkinter as tk
import tkinter.filedialog as tkf
class TestClass():
def __init__(self, master):
frame = tk.Frame(master)
frame.pack()
self.dialogButton = tk.Button(frame, text="choose", command=self.chooseFile)
self.dialogButton.pack(side=tk.BOTTOM)
def chooseFile(self):
global filename
filename = tkf.askopenfilename()
print(filename)
Import script
import tkinterTest as tt
import tkinter as tk
root = tk.Tk()
classObject = tt.TestClass(root)
var = classObject.chooseFile()
print(var)
root.mainloop()
I want to access the path string only with the GUI so that it gives me the string only after I press the button to select the file not right after the program starts.
Python3 gives me this or other errors, whatever method i use to import tkinter.
I searched online a solution to my problem but none worked. I am running the latest version of Ubuntu.
#!/usr/bin/env python3
from tkinter import *
def main():
main_window = tkinter.Tk()
main_window.title("free communism here")
click_function = print("WEWE")
communism_button = tkinter.button(text = "click for free communism", command = click_function, height = 40, width = 120)
communism_button.pack()
tkinter.mainloop()
main()
The result is:
Traceback (most recent call last):
File "communism button.py", line 10, in <module>
main()
File "communism button.py", line 4, in main
main_window = tkinter.Tk()
NameError: name 'tkinter' is not defined.
I can't figure out why the program doesn't work. It should display a button and if you press it, it should display "WEWE". Sorry for my probably bad english.
The problem lies in the fact that you use from tkinter import * and then use the button function as tkinter.Button. When you use from xxx import * you don't use the 'xxx' package name anymore (so just Button()). Otherwise just use import tkinter, after which you do use tkinter.Button().
I personally prefer import xxx for larger scripts, because it's more clear where a method comes from.
Besides that, your code still has another problem with your 'click_function'. You should make that an actual function. And tkinter.Button() is with a capital 'B'
import tkinter
def click_function():
print("WEWE")
def main():
main_window = tkinter.Tk()
main_window.title("free communism here")
communism_button = tkinter.Button(text = "click for free communism", command = click_function, height = 40, width = 120)
communism_button.pack()
main_window.mainloop() # call here main_window instead of tkinter
main()
Try this way:
#!/usr/bin/env python3
from tkinter import *
def main():
main_window = Tk()
main_window.title("free communism here")
click_function = print("WEWE")
communism_button = Button(text = "click for free communism", command = click_function, height = 40, width = 120)
communism_button.pack()
main_window.mainloop()
main()
what I want to do is to select multiple files
using the tkinter filedialog
and then add those items to a list.
After that I want to use the list to process
each file one by one.
#replace.py
import string
def main():
#import tkFileDialog
#import re
#ff = tkFileDialog.askopenfilenames()
#filez = re.findall('{(.*?)}', ff)
import Tkinter,tkFileDialog
root = Tkinter.Tk()
filez = tkFileDialog.askopenfilenames(parent=root,title='Choose a file')
Now, I am able to select multiple files,
but I dont know how to add those filenames to the list.
any ideas?
askopenfilenames returns a string instead of a list, that problem is still open in the issue tracker, and the best solution so far is to use splitlist:
import Tkinter,tkFileDialog
root = Tkinter.Tk()
filez = tkFileDialog.askopenfilenames(parent=root, title='Choose a file')
print root.tk.splitlist(filez)
Python 3 update:
tkFileDialog has been renamed, and now askopenfilenames directly returns a tuple:
import tkinter as tk
import tkinter.filedialog as fd
root = tk.Tk()
filez = fd.askopenfilenames(parent=root, title='Choose a file')
askopenfilenames
returns a tuple of strings, not a string.
Simply store the the output of askopenfilenames into filez (as you've done) and pass it to the python's list method to get a list.
filez = tkFileDialog.askopenfilenames(parent=root,title='Choose a file')
lst = list(filez)
>>> type(lst)
<type 'list'>
Putting together parts from above solution along with few lines to error proof the code for tkinter file selection dialog box (as I also described here).
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw()
root.call('wm', 'attributes', '.', '-topmost', True)
files = filedialog.askopenfilename(multiple=True)
%gui tk
var = root.tk.splitlist(files)
filePaths = []
for f in var:
filePaths.append(f)
filePaths
Returns a list of the paths of the files. Can be stripped to show only the actual file name for further use by using the following code:
fileNames = []
for path in filePaths:
name = path[46:].strip()
name2 = name[:-5].strip()
fileNames.append(name2)
fileNames
where the integers (46) and (-5) can be altered depending on the file path.
In Python 3, the way it worked for me was this (respect lowercase):
from tkinter.filedialog import askopenfilenames
filenames = askopenfilenames(title = "Open 'xls' or 'xlsx' file")
for filename in filenames:
# print or do whatever you want
I hope you find it useful!
Regards!