I would like to do scrolling in my photo editing program. But something is not working for me. The code was in theory based on one of the stackoverflow entries and I can't identify the problem. I have tried to remake it in various ways. _inbound_to_mousewheel prints nicely and so does _un_to_mousewheel. The one responsible directly for scrolling doesn't even print.
Is it possible to do a zoom in such a project, and if not, does it need to be rebuilt?
Main window file:
import sys
import tkinter as tk
from tkinter import filedialog, Frame
from PIL import ImageTk, Image
from gui.menu_bar import MenuBar
from gui.workspace import Workspace
def close_all_windows():
sys.exit()
class MainForm(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("myPhotoEditor by Sebastian KÄ…kolewski")
self.geometry("1000x850")
self.protocol("WM_DELETE_WINDOW", close_all_windows)
self.menu_bar = MenuBar(self)
self.config(menu=self.menu_bar)
# region Workspace
self.workspace_frame = Frame(self)
self.workspace_frame.pack(expand=True, fill="both", side="left")
self.workspace = Workspace(self.workspace_frame)
self.workspace.pack(fill="both", expand=True)
file_url = filedialog.askopenfilename()
img = Image.open(file_url)
self.workspace.image = ImageTk.PhotoImage(img)
self.workspace.create_image(0, 0, image=self.workspace.image, anchor='nw')
self.workspace_frame.bind('<Enter>', self._bound_to_mousewheel)
self.workspace_frame.bind('<Leave>', self._unbound_to_mousewheel)
# endregion
def _bound_to_mousewheel(self, event):
print("_bound_to_mousewheel")
self.workspace_frame.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbound_to_mousewheel(self, event):
print("_unbound_to_mousewheel")
self.workspace_frame.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event):
print("_on_mousewheel")
self.workspace_frame.yview_scroll(int(-1 * (event.delta / 120)), "units")
Workspace file:
from tkinter import Canvas, Scrollbar
class Workspace(Canvas):
def __init__(self, master=None):
Canvas.__init__(self, master)
self.master = master
workspace_hbar = Scrollbar(self.master, orient="horizontal")
workspace_hbar.pack(side="bottom", fill="x")
workspace_hbar.config(command=self.xview)
workspace_vbar = Scrollbar(self.master, orient="vertical")
workspace_vbar.pack(side="right", fill="y")
workspace_vbar.config(command=self.yview)
self.config(xscrollcommand=workspace_hbar.set, yscrollcommand=workspace_vbar.set)
Related
Well, I'm adding many buttons to my Canvas called "itemsFrame" in order to test the ScrollBar, but it doesn't work
Well, I haven't tried much because I don't know about the subject, I've investigated how to do it but it only comes out with small buttons without being able to resize them
from tkinter import Frame, Label, Button, Entry, messagebox, ttk, Scrollbar, Canvas
import base64
import json
class WatchNewsFrame(Frame):
name = "WatchNewsFrame"
def __init__(self, parent):
super().__init__()
self.Parent = parent
self.initializecomponents()
pass
def set_news(self):
data = json.load(open(self.file))["News"]
cont = 1
for key in range(10):
Panel = Button(self.itemsFrame)
Panel.config(bg="#656565", activebackground="#808080")
Panel.place(relwidth=.95, relheight=0.245, rely=.028+key*0.25, relx=.5, anchor="n")
pass
def initializecomponents(self):
Frame.__init__(self, self.Parent)
self.itemsFrame = Canvas(self)
self.ItemsScrooll = Scrollbar(self, orient="vertical")
# this frame
self.config(background=self.Parent["background"])
self.place(relwidth=0.95, relheight=0.95, relx=0.5, rely=0.5, anchor="center")
# ItemsScrooll
self.ItemsScrooll.pack(side="right", fill="y")
# itemsFrame
self.itemsFrame.config(bg="#606060", highlightbackground="#FFFFFF", yscrollcommand=self.ItemsScrooll.set)
self.itemsFrame.place(relheight=0.85, relwidth=0.9, relx=0.5, rely=0.5, anchor="center")
self.itemsFrame.bind_all("<MouseWheel>", self.on_mouse_wheel)
self.ItemsScrooll.config(command=self.itemsFrame.yview)
# events
self.set_news()
pass
pass
I want to resize a frame inside my canvas, so that the frame covers the whole window.
I did some googleing and saw some people are using a resize function, but this doesn't work for me.
I get the following error message:
_tkinter.TclError: invalid boolean operator in tag search expression
This is my code:
import tkinter as tk
from tkinter import ttk
class MainGUI:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('400x400')
self.root.title("A simple GUI")
self.canvas = tk.Canvas(self.root, background='GREEN',width=900,height=300,scrollregion=(0,0,500,2000))
self.scrollbar=tk.Scrollbar(self.canvas,orient="vertical",command=self.canvas.yview)
self.scrollbar.pack(side="right",fill="y")
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.canvas.bind('<Configure>', lambda e: self.canvas.configure(scrollregion = self.canvas.bbox("all")))
self.main = tk.Frame(self.canvas,bg='BLUE')
self.canvas.create_window((0,0), window=self.main, anchor="nw")
self.canvas.pack(side=tk.TOP,fill=tk.BOTH,expand=True)
self.canvas.bind("<Configure>", self.resize_frame)
for _ in range(30):
MyCoolFrame(self.main)
def resize_frame(self, e):
canvas_width = e.width
self.canvas.itemconfig(self.main, width = canvas_width)
class MyCoolFrame:
def __init__(self,master):
self.master = master
self.frame = tk.Frame(self.master,bg='RED')
for i in range(5):
tk.Label(self.frame,text=f'Cool Label {i}').pack(side=tk.LEFT,padx=2,pady=10)
self.frame.pack(side=tk.TOP,pady=10)
a = MainGUI()
a.root.mainloop()
I am building a script having one counter and an image. Both are in different canvas on single window. I am trying to update the canvas image once the timer stops. Below is my code. I am not getting whats wrong with this
from Tkinter import *
import Tkinter as tk
import stopwatch
import stone_image
class App():
def __init__(self, root):
self.root = root
self.root.configure(background="yellow")
global stoneImagePanel
stopwatchPanel = tk.Canvas(self.root, background="yellow")
stoneImagePanel = tk.Canvas(self.root, background="yellow")
stopwatchPanel.grid(row=0, column=0, columnspan=4, sticky="e")
stoneImagePanel.grid(row=1, column=0, rowspan=2, columnspan=4, sticky="news")
self.stoneImage_canvas(stoneImagePanel)
self.stopWatch_canvas(stopwatchPanel)
def stopWatch_canvas(self, parent):
stopwatch.timerStart(parent, 500)
stoneImagePanel.after(500, self.update(stoneImagePanel))
def stoneImage_canvas (self, parent):
displayImage = stone_image.DisplayImage(parent)
displayImage.stoneImg('images/stone.jpg')
def update(self, parent):
displayImage = stone_image.DisplayImage(parent)
displayImage.stoneImg('images/UP.png')
if __name__ == "__main__":
root = Tk()
app = App(root)
root.mainloop()
Neither the stopwatch is working smoothly nor the image is updating. Please help.
I am trying to develop a Python Tkinter widget that opens a window displaying a photo and allows the user to scroll through the photos using a scroll bar. For context, the idea is to be able to scroll through a timer-series of photographs.
So far I've been able to make a Tkinter canvas displaying an image, and a Tkinter "Scale" slider, but I am having trouble combining them to meet my goal. The result of the below code is an empty canvas window and a separate slider. The slider works and prints its position when moved, but no photo ever loads. I was hoping that when the bar was moved to position 3, photo 3 would load.
Any idea what I'm missing?
import Tkinter as tk
from PIL import ImageTk, Image
from Tkinter import *
class ImageCanvas(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.canvas = Canvas(self, width=720, height=480, bd=0)
self.canvas.grid(row=0, column=0, sticky='nsew', padx=4, pady=4)
self.root = tk.Tk()
self._job = NONE
self.slider = tk.Scale(self.root, from_=0, to=3, orient = "horizontal", command=self.updateValue)
self.slider.pack()
self.root.mainloop()
def updateValue(self, event):
if self._job:
self.root.after_cancel(self._job)
self._job = self.root.after(500, self.result)
def result(self):
self._job=None
print self.slider.get()
returnedValue = self.slider.get()
class ImgTk(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.main = ImageCanvas(self)
self.main.grid(row=0, column=0, sticky='nsew')
self.c = self.main.canvas
self.currentImage = {}
self.load_imgfile(images[ImageCanvas.returnedValue()])
def load_imgfile(self, filename):
self.img = Image.open(filename)
self.currentImage['data'] = self.img
self.photo = ImageTk.PhotoImage(self.img)
self.c.xview_moveto(0)
self.c.yview_moveto(0)
self.c.create_image(0, 0, image=self.photo, anchor='nw', tags='img')
self.c.config(scrollregion=self.c.bbox('all'))
self.currentImage['photo'] = self.photo
images = ['/Users/Evan/Documents/Temp/4744.png', '/Users/Evan/Documents/Temp/4750.png', '/Users/Evan/Documents/Temp/4757.png']
app = ImgTk()
A couple suggestions may get you on the right track. Move the self.root.mainloop() out of the ImageCanvas class and put it at the end, after app = ImgTk(), as simply mainloop(), so it only get's called ones per instance of your app.
Also, ImageCanvas class doesn't have a method called returnedValue, and the result method doesn't return any value. So, add return returnedValue to the result method. Then ImageCanvas.returnedValue() would need to be ImageCanvas.result(), or you could just say self.main.result().
After making these changes, the first image displays, more work will need to be done to get the other images to load.
I am trying to make a on-button click event in a Tkinter window. I have a Tkinter Window on which there are buttons. Pressing one of those buttons,opens up a new Tkinter Window using Toplevel. This window would have a Scrollbar and some other buttons with images on it which can be vertically scrolled down. I could create the two functionalities separately,i.e, I could embedd a button with an image on a Tkinter window and use the Scrollbar but was unable to call the same function with the previous Tkinter window.
The code I am using is -
from Tkinter import *
from ttk import *
class VerticalScrolledFrame(Frame):
def __init__(self, parent, *args, **kw):
Frame.__init__(self, parent, *args, **kw)
# create a canvas object and a vertical scrollbar for scrolling it
vscrollbar = Scrollbar(self, orient=VERTICAL)
vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
canvas = Canvas(self, bd=0, highlightthickness=0,
yscrollcommand=vscrollbar.set)
canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
vscrollbar.config(command=canvas.yview)
# reset the view
canvas.xview_moveto(0)
canvas.yview_moveto(0)
# create a frame inside the canvas which will be scrolled with it
self.interior = interior = Frame(canvas)
interior_id = canvas.create_window(0, 0, window=interior,
anchor=NW)
def _configure_interior(event):
# update the scrollbars to match the size of the inner frame
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the canvas's width to fit the inner frame
canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
def _configure_canvas(event):
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the inner frame's width to fill the canvas
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind('<Configure>', _configure_canvas)
#if __name__ == "__main__":
class SampleApp(Tk):
def __init__(self, *args, **kwargs):
#from Tkinter import *
print "in constructor"
import Tkinter
import ImageTk
import Image
import cv2
import numpy as np
import cv2.cv as cv
import math
import tkFileDialog
import tkMessageBox
import Tkinter as tk
root = Tk.__init__(self, *args, **kwargs)
def Print():
print "print function"
self.frame = VerticalScrolledFrame(root)
self.frame.pack()
self.label = Label(text="Shrink the window to activate the scrollbar.")
self.label.pack()
compare_button_path = "compare-button.jpg"
image_compare = Image.open(compare_button_path)
image_compare.thumbnail((70,45))
photo_compare = ImageTk.PhotoImage(image_compare)
button = tk.Button(self.frame, width=120, height=40, image=photo_compare,fg='black',bg='medium turquoise', activebackground='indian red',cursor="hand2",bd=6,relief=RAISED, compound=tk.LEFT, text="Compare",command = Print)
button.image = photo_compare
button.pack(side=LEFT)
buttons = []
for i in range(10):
buttons.append(Button(self.frame.interior, text="Button " + str(i)))
buttons[-1].pack()
app = SampleApp()
app.mainloop()
The above written function gives a pretty good result.
But how do I call this function on a button click from another Tkinter window? Changing the initial declaration of root to root = Tk() instead of root = Tk.init(self, *args, **kwargs) throws a
RuntimeError: maximum recursion depth exceeded while calling a Python object.
If I try to keep the function in some other file and import it into my original Tk file and create the object of that class on a button click, the second file gets automatically called during complilation of the original Tk file.
Can somebody please suggest a way out.
I really don't understand your question, even after asking for clarification. You finally wrote in the comments of the question "I simply want to open a tkinter window with buttons and images, on a button click from another Tkinter window".
I don't see what's preventing you from doing that. The only thing I see wrong with your code is that you're simply not creating an instance of Toplevel (well, except for a confusing set of imports). Other than that, your code should work.
For example, if you modify your sample app to look something like this, you can open as many windows as you want:
class SampleApp(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
b = Button(self, text="Open a new window", command=self.open_new)
b.pack()
def open_new(self):
top = Toplevel()
self.frame = VerticalScrolledFrame(top)
self.frame.pack()
def Print():
print "print function"
button = Button(self.frame, text="Compare",command = Print)
button.pack(side=LEFT)
buttons = []
for i in range(10):
buttons.append(Button(self.frame.interior, text="Button " + str(i)))
buttons[-1].pack()