import Tkinter as tk
import guiOpMenu2
class Omenu(object):
def __init__(self):
self.app = tk.Tk()
self.app.title('test1')
self.OpMenu()
self.btn()
def OpMenu(self):
self.op = tk.StringVar()
self.opt =['1', '2']
self.men = tk.OptionMenu(self.app, self.op, *self.opt)
self.men.pack()
def btn(self):
self.btn_btn = tk.Button(self.app, text='newGui', command=self.test)
self.btn_btn.pack()
def test(self):
win = guiOpMenu2.Omenu2()
win = Omenu()
win.app.mainloop()
import Tkinter as tk
class Omenu2(object):
def __init__(self):
self.app = tk.Tk()
self.app.title('test1')
self.OpMenu2()
def OpMenu2(self):
self.op2 = tk.StringVar()
self.opt2 =['2', '3']
self.men2 = tk.OptionMenu(self.app, self.op2, *self.opt2, command=self.test)
self.men2.pack()
def test(self, num):
print self.op2.get()
print num
Clicking on the button newGui displays the new window, but the selected value does not show up on the second optionmenu widget. When I do print self.op2.get() or print num it does print the selected value though. What can be done to make the second optionmenu behave properly?
The issue occurs because in Omenu2 class, you are creating a new Tk() app.
Also, unless the .mainloop() is called for the application owning a component, its widgets would not get updated.
Also, I don't think you really need a new Tk() app itself. If you want the new option menu to come in a new window, you should use tk.Toplevel() .
Example -
The guiOpmenu2.py -
import Tkinter as tk
class Omenu2(object):
def __init__(self, app):
self.app = app
self.master = tk.Toplevel(app)
self.master.title('test1')
self.OpMenu2()
def OpMenu2(self):
self.op2 = tk.StringVar()
self.opt2 =['2', '3']
self.men2 = tk.OptionMenu(self.master, self.op2, *self.opt2, command=self.test)
self.men2.pack()
def test(self, num):
print self.op2.get()
print num
Your main script -
import Tkinter as tk
import guiOpMenu2
class Omenu(object):
def __init__(self):
self.app = tk.Tk()
self.app.title('test1')
self.OpMenu()
self.btn()
def OpMenu(self):
self.op = tk.StringVar()
self.opt =['1', '2']
self.men = tk.OptionMenu(self.app, self.op, *self.opt)
self.men.pack()
def btn(self):
self.btn_btn = tk.Button(self.app, text='newGui', command=self.test)
self.btn_btn.pack()
def test(self):
win = guiOpMenu2.Omenu2(self.app)
win = Omenu()
win.app.mainloop()
Related
I'm trying to make this code close all windows which are opened on windows class. At this moment it only closes few of them. Code works perfectly, but it just dont remove all windows which needs to be removed. Can someone please help me to make this script working?
import tkinter as tk
from tkinter import *
from PIL import Image, ImageTk
import webbrowser
import time
import random
def closeall():
global close
close = True
self = selfstr
parent = parentstr
Window.__init__(self, parent)
class Window(tk.Toplevel):
def __init__(self, parent):
if close == True:
self.destroy()
else:
global selfstr
selfstr = self
global parentstr
parentstr = parent
plusminus_list = ["+", "-"]
plusminus = random.choice(plusminus_list)
plusminus2 = random.choice(plusminus_list)
location = random.randint(1, 1000)
location2 = random.randint(1, 1000)
super().__init__(parent)
self.geometry(f'256x256{plusminus}{location}{plusminus2}{location2}')
self.title('NOESCAPE')
frame = Frame(self, width=256, height=256)
frame.pack()
frame.place(anchor='center', relx=0.5, rely=0.5)
img_list = ["jeff2", "jeff3", "jeff4", "jeff5", "jeff6"]
randomimg = random.choice(img_list)
img = ImageTk.PhotoImage(Image.open(f"{randomimg}.jpg"))
label = Label(frame, image = img)
label.pack()
def on_closing():
plusminus_list = ["+", "-"]
onlywayout()
plusminus = random.choice(plusminus_list)
plusminus2 = random.choice(plusminus_list)
location = random.randint(1, 1000)
location2 = random.randint(1, 1000)
img_list = ["jeff2", "jeff3", "jeff4", "jeff5", "jeff6"]
randomimg = random.choice(img_list)
img = ImageTk.PhotoImage(Image.open(f"{randomimg}.jpg"))
Window(self)
self.protocol("WM_DELETE_WINDOW", on_closing)
self.mainloop()
So you cannot access all Window instances you created for some reason? Then you could save a list with all instances in the Window class as a class attribute. With this list you should be able to destroy all Window instances. Your approach with using the constructor and global variables is a very bad coding style and you shouldn't do anything like this.
Here I created a classmethod so that you don't need the extra function closeall():
import tkinter
class Window(tkinter.Toplevel):
instances = [] # class attribute
def __init__(self, parent):
super().__init__(parent)
self.instances.append(self) # save current instance to the list
# ...
#classmethod
def destroy_all_instances(cls):
for window in cls.instances:
window.destroy()
# Destroy all Window instances:
Window.destroy_all_instances()
I am having a little trouble with this project that I am working on. My project is this GUI application. In my test.py file, I call another file that contains instructions for another GUI window. This is where I am having trouble. In the test.py file, if you click run, a small window will appear. Click TEST in the small window. Then another window will appear that contains text fields if you enter numbers into the text fields for the window and then click enter. My IDE gets these error messages. It says that " ValueError: could not convert string to float: ' ' " My question is how do I fix this so that I do not get this error message? It is supposed to print the input that was entered into the window. I have two files, test.py, and model_objects.py. If you run model_objects.py by itself, it works perfectly. But when I try to import this file into test.py, it does not want to work right. This is programmed in Python. Also, my model_objects.py file is placed in a folder called util in the project. The values that I entered are floating-point values. I am having trouble with this. If you can help, I would greatly appreciate it.
Here is my code:
model_objects.py (This is in a folder called util in the project.)
import tkinter as tk
from tkinter import ttk
from tkinter.ttk import Style
import numpy as np
from util import InputData
class Harmonic_Oscillator:
def __init__(self):
self.type = 0
self.name = "Harmonic Oscillator"
self.nparam = 2
self.label = ["\u03BC", "k"]
self.param = np.zeros(self.nparam, float)
def set_param(self, param_list):
for i in range(self.nparam):
self.param[i] = param_list[i]
return
class Morse_Oscillator:
def __init__(self):
self.type = 1
self.name = "Morse Oscillator"
self.nparam = 3
self.label = ["\u03BC", "De", "a"]
self.param = np.zeros(self.nparam, float)
def set_param(self, param_list):
for i in range(self.nparam):
self.param[i] = param_list[i]
return
class Test_Oscillator:
def __init__(self):
self.type = 2
self.name = "Test Oscillator"
self.nparam = 4
self.mu = 0
self.label = ["a", "b", "c", "d"]
self.param = np.zeros(self.nparam, float)
def set_param(self, param_list):
for i in range(self.nparam):
self.param[i] = param_list[i]
return
def model_prompt(potential_model):
window1 = tk.Tk()
style = Style()
window1.title('PyFGH Parameters')
box_length = 103
for q in range(3):
box_length = box_length + 33 * potential_model[q].nparam
box_len_str = '300x' + str(box_length)
window1.geometry(box_len_str)
entries = []
qvar = np.empty(3, dtype=list)
for i in range(3):
qvar[i] = []
j = 0
y = 5
for q in range(3):
for qparam in range(potential_model[q].nparam):
qvar[q].append(tk.StringVar())
ttk.Label(window1, text=potential_model[q].label[qparam] + " for Q:" + str(q + 1) + ":",
font=("Times New Roman", 15)).place(x=50, y=y)
# set text variable as q1var[j] , each entry will have separate index in the list
a1 = ttk.Entry(window1, textvariable=qvar[q][qparam], font=("Times New Roman", 10)).place(x=140, y=y)
j += 1
y += 35
def enter_button():
for q in range(3):
param_list = []
for qparam in range(potential_model[q].nparam):
param_list.append(qvar[q][qparam].get())
potential_model[q].set_param(param_list) # This is giving me error. Not working properly!!!
for q in range(3):
for qparam in range(potential_model[q].nparam):
print(potential_model[q].param[qparam])
InputData.output.items.model_data = potential_model
print(InputData.output.items.model_data)
window1.destroy()
enter = tk.Button(window1, text='Enter', bd='20', bg='green', fg='white',
command=enter_button).place(x=110, y=y)
window1.mainloop()
def output2():
sections = []
for i in range(3):
if InputData.output.items.v[i] == "Model-Harmonic Oscillator":
sections.append(Harmonic_Oscillator())
elif InputData.output.items.v[i] == "Model-Morse Oscillator":
sections.append(Harmonic_Oscillator())
elif InputData.output.items.v[i] == "Model-Test Oscillator":
sections.append(Harmonic_Oscillator())
#test = [Harmonic_Oscillator(), Morse_Oscillator(), Test_Oscillator()]
#model_prompt(test)
Here is another file called test.py
from util import InputData
from util import model_objects
from util import model_objects
from util.model_objects import Harmonic_Oscillator, Morse_Oscillator, Test_Oscillator, model_prompt
import tkinter as tk
def write_slogan():
test = [Harmonic_Oscillator(), Morse_Oscillator(), Test_Oscillator()]
model_prompt(test)
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame,
text="QUIT",
fg="red",
command=quit)
button.pack(side=tk.LEFT)
slogan = tk.Button(frame,
text="TEST",
command=write_slogan)
slogan.pack(side=tk.LEFT)
root.mainloop()
It's a bit esoteric, but the issue is this line in your model_prompt function:
qvar[q].append(tk.StringVar())
The quick fix would be:
qvar[q].append(tk.StringVar(window1))
The tkinter variable types' constructors accept an optional parameter - a handle to the window to which the associated entry widget is attached. If none is supplied, by default, it will pick the first tk.Tk window that was instantiated (in your case, that was root in test.py). The StringVars will update themselves whenever the event queue of the bound window has cleared. Since you spawned a new tk.Tk, this interrupted your root event queue, and since your variables were bound to root, they did not update despite text being entered in the entries.
If you wanted to be super proper, you should look into tk.Toplevel or tkinter.simpledialog to spawn child windows. Your program should never have more than one tk.Tk window in the first place.
i made a little example, i hope it matches yourr mainproblem. if you want to work with classes, in the most cases you need references.
from tkinter import *
class MainWindow(Tk):
def __init__(self):
super(MainWindow, self).__init__()
self.test = Test(self) # test class import
self.outputLbl = Label(self) # output Label
self.outputLbl.pack(side="top", fill="x", ipady=20)
class Test(Frame):
def __init__(self, parent):
super(Test, self).__init__()
self.parent = parent # you can use this way to call between classes
self._input = Entry(self.parent)
self._input.pack()
self._input.bind("<Return>", self.outputMW)
def outputMW(self, event): # function, when pressing return it gives changes the text in your label
var = self._input.get()
self.parent.outputLbl.config(text=var) # self.parent makes the reference to your other class
if __name__ == '__main__':
mw = MainWindow()
mw.geometry("500x500")
mw.mainloop()
I am building a real time monitoring project where information is given in the first window and that's keep on updating in the second window. I am trying to monitor the updated information in parallel from a different window using the same code, but as I pressed the new button and given the new information it is updating in the previous window also but I wanted monitor window to be completely different, so that I can monitor the different information in parallel using the same code. Please have a look at the sample code and help me with the ideas.
The sample code:
import time
import threading
import tkinter.messagebox
from tkinter import ttk
import queue
from tkinter import *
class Demo1:
data=[]
def __init__(self, master):#Python scrollbar on text widget
self.master = master
self.t=tkinter.Text(self.master,height=20,width=50)
self.t.grid(row=1, column=1)
self.button = tkinter.Button(self.master,height=3,width=10, text="OK", command = self.new_window)
self.button.grid(row=2,column=1)
def new_window(self):
self.inputValue=self.t.get("1.0",'end-1c')
Demo1.data1=self.inputValue.split("\n")
self.master.destroy() # close the current window
self.master = tkinter.Toplevel() # create another Tk instance
self.app = Demo2(self.master) # create Demo2 window
self.master.mainloop()
class Demo2:
t1 = []
s1 = True
display = []
display1 = []
i=0
kas = True
num=0
j1=0
def __init__(self, master):
self.master = master
self.button = tkinter.Button(self.master,height=2,width=11, text="new",command=self.new).place(x=0,y=0)
self.label = tkinter.Label(self.master, text="monitor", font=("Arial",20)).grid(row=0, columnspan=3)
cols = ('aa','bb')
self.listBox = ttk.Treeview(self.master, columns=cols)
for col in cols:
self.listBox.heading(col, text=col)
self.listBox.column(col,minwidth=0,width=170)
self.listBox.grid(row=1, column=0)
self.a()
def a(self):
self._img=tkinter.PhotoImage(file="green1.gif")
a=Demo1.data1
for i,(a) in enumerate(a): #here I have some function which runs repeatedlly
self.listBox.insert('', 'end',image=self._img, value=(a))
threading.Timer(1.0, self.a).start()
def new(self):
main()
def main():
root = tkinter.Toplevel()
app = Demo1(root)
root.mainloop()
if __name__ == '__main__':
main()
I have given the pppp information to monitor but as a pressed new button and added the xx information its updating in the previous window also. Please help me with the idea so that the link between these window will be vanished.
Output:
You have some major issues with your program. Including how you are trying to use your classes. The Toplevel() object was giving me issue, so I used Tk(). This should show you how to properly use the classes with the window. Most importantly your second window needs to be created from global not the first window. Also Demo1.data is a reference to your class definition not the actual data you loaded. I hope this example is helpful.
from tkinter import *
# your second window should be created in global
def create_demo2():
global app, app2
root2 = Tk()
app2 = Demo2(root2, app)
class Demo1:
def __init__(self, window):
self.window = window
self.data = ""
self.button = Button(self.window, text="New Window",
command=create_demo2)
self.button.pack()
def set_data(self):
self.data = "data"
class Demo2:
# you could just use app from global scope, but I like to pass so that it is explicit.
def __init__(self, window, app1):
self.window = window
self.button_set = Button(self.window, text="Set", command=app1.set_data)
self.button_use = Button(self.window, text="Use", command=self.use_data)
self.app = app1
self.label = Label(self.window)
self.button_set.pack()
self.button_use.pack()
self.label.pack()
def use_data(self):
self.label.configure(text=self.app.data)
root = Tk()
app = Demo1(root)
app2 = None
root.mainloop()
I am trying to execute a Tkinter ttk Button method while the button is pressed, meaning I want the method to keep executing when the button is pressed and stop when I release it, but i can't quite figure it out. Here is the code.
from tkinter import *
from tkinter import ttk
class stuff (object):
def __init__(self, master):
master.title("Grid Master")
master.frame_1 = ttk.Frame(master)
master.frame_1.pack()
master.configure(background = "#FFFFFF")
self.button = ttk.Button(master, text = 'Press', command = self.callback)
self.button.pack()
def callback(self):
print ("Hello world")
def main():
root = Tk()
loop = stuff(root)
root.mainloop()
if __name__ == '__main__':
main()
You can see in the code that the method only prints "Hello world" and I want this function to execute and keep going, printing Hello world until I release the button.
You can use root.after() to repeatedly schedule a job to perform the required task. Note that I have changed the button event to activate when the button is pressed, and to terminate the "after" job when the button is released.
try:
from tkinter import *
from tkinter import ttk
except ImportError:
# Python 2, probably
from Tkinter import *
import ttk
class stuff (object):
def __init__(self, master):
self._master = master
master.title("Grid Master")
master.frame_1 = ttk.Frame(master)
master.frame_1.pack()
master.configure(background = "#FFFFFF")
self.button = ttk.Button(master, text = 'Press')
self.button.bind("<Button-1>", self.button_pressed)
self.button.bind("<ButtonRelease-1>", self.button_released)
self.button.pack()
self.hello_world_frequency = 1 # milliseconds
def hello_world(self):
print ("Hello world")
self._job = self._master.after(self.hello_world_frequency, self.hello_world)
def button_pressed(self, event):
print ("Button down")
self.hello_world()
def button_released(self, event):
print ("Button released")
self._master.after_cancel(self._job)
def main():
root = Tk()
loop = stuff(root)
root.mainloop()
if __name__ == '__main__':
main()
You can make a custom repeating ttk button class that inherits from ttk.Button but adds basic repeating functionality.
Try this. you can use it like
self.button = RepeatButton(master, text='Press', command=self.callback)
and you can set the repeatdelay and repeatinterval arguments, which default to 300 and 100.
class RepeatButton(ttk.Button):
def __init__(self, *args, **kwargs):
self.callback = kwargs.pop('command', None)
self.repeatinterval = kwargs.pop('repeatinterval', 100)
self.repeatdelay = kwargs.pop('repeatdelay', 300)
ttk.Button.__init__(self, *args, **kwargs)
if self.callback:
self.bind('<ButtonPress-1>', self.click)
self.bind('<ButtonRelease-1>', self.release)
def click(self, event=None):
self.callback()
self.after_id = self.after(self.repeatdelay, self.repeat)
def repeat(self):
self.callback()
self.after_id = self.after(self.repeatinterval, self.repeat)
def release(self, event=None):
self.after_cancel(self.after_id)
I have a Window wich opens another window askig for the settings. But the BooleanVar I use to get the Checkbutton's state doesn't change. It does however when I call the settingswindow strait from the code without the other window.
This is the minimal code to get the
from tkinter import *
class MainWindow():
def __init__(self, master):
self.root = master
SettingsWindow()
self.root.mainloop()
class SettingsWindow():
def __init__(self):
rootSettings = Tk()
self.rebuild = BooleanVar()
chkRebuild = Checkbutton(rootSettings, text="rebuild", variable=self.rebuild, command=self.testFunc)
chkRebuild.pack()
rootSettings.mainloop()
def testFunc(self):
print(self.rebuild.get())
root = Tk()
mainWindow = MainWindow(root)
The output is always 0 when clicking on the checkbutton, evenso the output of BooleanVar is True or False.
What is the difference in calling SettingsWindow() from insite a class or outside? At least I think that is the reason it is not working.
I am using Pyhton3 in case there is a difference.
You can't have two instances of Tk. For your second window you need to create a Toplevel. You also should never call mainloop more than once in your entire program.
This is a sample example for how to solve the checkbutton's variable not changing issue.
Key: for the second window, should use Toplevel, not use Tk.
from tkinter import *
class MainWindow:
def __init__(self):
self.master = Tk()
self.fun = dict()
def set_ui(self):
Button(self.master, text='SecondWindow', command=self.fun).pack(side=LEFT)
self.master.mainloop()
class SecondWindow:
def __init__(self):
self.root = Toplevel()
self.var = BooleanVar()
self.set_ui()
def printf(self):
print(self.var.get())
def set_ui(self):
Checkbutton(self.root, text='press', variable=self.var, command=self.printf).pack(side=LEFT)
def call_second_window():
second_window = SecondWindow()
main_window = MainWindow()
main_window.fun = call_second_window
main_window.set_ui()