Need help understanding how to initialize classes in tkinter python - python

I'm creating a program that can trade currency using the binance API.
It works as intended (irrelevant code not included)
My problem is that I now want to make is possible to create several instances of the class Trade, in new pop up windows. I'm having trouble understanding how to achieve this in terms of creating new instances of the class Trade. Also I'm pretty sure that my use of self: self = Trade(top) dosen't make any sense (even though it works).
To sum it up:
I want to be able to click a button that starts a new instance of Trade(), so that I can use the methods in the class for two different trading routines at the same time in the same instance of the program. How?
I'll appreciate any form of help, including suggesting me to read up on something.
I'm sorry if im too noob.
Thx in advance.
class Trade(Frame):
stop_trading = False
amount_orders = 0
after_id = 0
def __init__(self, master=None):
Frame.__init__(self, master)
def change_orders(self):
if list_variable4.get() == 'TRUE':
if self.check_open_order() == False or self.amount_orders<2:
if self.delete_open_orders() == True and self.stop_trading != True:
self.create_orders()
...
def cron():
self.amount_orders += 1
if self.amount_orders > int(trade_cap_box.get(0.0, tk.END)):
message_window.insert(tk.END,'\nTrade Cycle Cap reached with {} trades'.format(self.amount_orders - 1))
cap_stop_trading()
if self.stop_trading != True:
message_window.insert(tk.END,'\nTrading Cycle Started{}'.format(self.amount_orders))
interval = int(rate_of_check_box.get(0.0, tk.END))
print('Trading!')
self.change_orders()
self.after_id = top.after(interval*1000*60, cron)
def start_trading():
self.amount_orders = 0
self.stop_trading = False
cron()
top = Tk()
top.geometry("600x500")
top.title('Trade Cron Job')
self = Trade(top)
message_window = Text(top, height=5, width=65)
message_window.place(x = 40,y = 10)
trading_symbol_box = Text(top, height=1, width=20)
trading_symbol_box.place(x = 200,y = 130)
default_trading_symbol = (self.config_data['configs']['symbol'])
if default_trading_symbol:
trading_symbol_box.insert(END, default_trading_symbol)
else:
trading_symbol_box.insert(END, "")
trading_symbol_labels = Label(top, text='Trading Symbol')
trading_symbol_labels.place(x = 40,y = 130)
start_value_box = Text(top, height=1, width=20)
start_value_box.place(x = 200,y = 160)
start_value_box.insert(END, 0)
start_value_labels = Label(top, text='Start Value To Progress From')
start_value_labels.place(x = 40,y = 160)
and so on...
top.mainloop()

You need to create an instance of Toplevel, then add the instance of Trade to that window.
def new_window():
window = Toplevel()
trade_frame = Trade(window)
trade_frame.pack(fill="both", expand=True)
...
new_window_button = Button(top, text="New Window", command=new_window)

Related

get a value of an textbox in tkinter while app is running

Hello i try to write a desktop app with tkinter for typing speed test i search but i cant find my answer is the any way to check the value of user entry in Textbox while app is running ? i need to compare user entry with test text i try to put the function before main loop when i init class but its just check the entry one time and also i try to use window.after()
this is my full code and problem is running last function
def run_test():
random_number = random.randint(1, 5)
test = session.query(data).filter(database.Database.id == random_number).first()
return test
class UserInterFace:
def __init__(self):
customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("green")
self.window = CTk()
self.window.title("Typing Speed Test Application")
self.window.resizable(False, False)
self.window.config(padx=50, pady=50)
self.window.geometry("1000x700")
self.test = run_test()
self.wrong_entry = 0
self.correct_entry = 0
self.test_running = True
self.start_count = 5
self.start_test_btn = None
self.timer = None
self.start_test_time = None
self.end_test_time = None
self.user_input = []
self.get_ready_label = CTkLabel(master=self.window,
font=timer_font,
text="Get ready Test will be start in :",
text_color="#609EA2")
self.count_down_label = CTkLabel(master=self.window,
font=count_down_font,
text=str(self.start_count),
text_color="#820000")
self.label_test = CTkLabel(master=self.window,
font=my_font2,
text="",
wraplength=900,
)
self.best_score_record = CTkLabel(master=self.window,
font=my_font1,
text_color="#609EA2",
text="")
self.type_area = CTkTextbox(master=self.window,
width=900,
height=200)
self.main()
self.tset_user_text(self.test.text, self.user_input)
self.window.mainloop()
def start_test(self, test):
self.start_test_time = time.time()
self.get_ready_label.grid_forget()
self.count_down_label.grid_forget()
test_id = test.id
test_text = test.text
test_record = test.record
self.label_test.configure(text=test_text)
if test_record == 0:
test_record = "No Record Yet"
else:
test_record = f"Best Record : {test_record}"
self.best_score_record.configure(text=test_record)
self.best_score_record.grid(row=0, column=0)
self.label_test.grid(row=1, column=0, pady=(20, 0))
self.type_area.grid(row=2, column=0, pady=(20, 0))
self.type_area.focus_set()
self.user_input = self.type_area.get("1.0", END)
def main(self):
self.start_test_btn = CTkButton(master=self.window,
text="Start Test",
command=lambda: self.start_time(),
height=100,
width=300,
font=my_font1)
self.start_test_btn.grid(row=0, column=0, padx=(300, 0), pady=(250, 0))
def start_time(self):
if self.start_count >= 0:
self.start_test_btn.grid_forget()
self.get_ready_label.grid(row=0, column=0, pady=(50, 100), padx=(200, 0))
self.count_down_label.grid(row=1, column=0, padx=(200, 0))
self.count_down_label.configure(text=self.start_count)
self.start_count -= 1
self.timer = self.window.after(1000, self.start_time)
else:
self.window.after_cancel(self.timer)
self.start_test(self.test)
def tset_user_text(self, test_text, user_text):
print("test")
test_text_list = list(test_text)
user_text_list = list(user_text)
if len(test_text_list) <= len(user_text_list):
self.test_running = False
self.end_test_time = time.time()
for n in range(len(test_text_list)):
if test_text_list[n] == user_text_list[n]:
self.correct_entry += 1
else:
self.wrong_entry += 1
Okay, so take this with a grain of salt because I can't test this on CustomTkinter, but you should be able to bind an event to your textbox like so:
# call a method called 'on_type' whenever a key is released in the text area
self.type_area.bind('<KeyRelease>', self.on_type)
You can define a callback method to handle this event. Thanks to the binding above, the event parameter is passed to your callback automatically when the event is triggered
def on_type(self, event):
print(event) # do whatever you need to do
FYI: binding to '<KeyRelease>' avoids (some) issues with key repeat caused by held keys

is there a way to grid an extra button while running your program in tkinter correctly?

I'm making an mp3 player app and I want the user to be able to add playlists (which will be buttons in a grid system.
Like so.
However in this state when I'm trying to add a playlist button this happens:
The top buttons and the button i just added get squeezed off and the scrollbar is stuck (I can't use it)
I've tried refreshing by self.playlist_frame.update_idletasks() after running create_playlists() but it doesn't seem to change anything
this is my code so you can test it:
import os
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
class MyApp:
def __init__(self):
self.root = tk.Tk()
self.width = self.root.winfo_screenwidth()
self.height = self.root.winfo_screenheight()
self.height = self.root.winfo_screenheight() - int(self.height / 13)
self.root.geometry(f'{self.width}x{self.height}')
self.root.title("Mp3")
self.c = '#14141D'
self.playlists_buttons_list = []
self.playlists = {}
self.helping_d = {}
self.main = ttk.Notebook(self.root)
self.playlists_tab = tk.Frame(self.main)
self.playlist_menu_frame = tk.Frame(self.playlists_tab, bg=self.c)
self.playlists_canvas = tk.Canvas(self.playlists_tab, bg=self.c)
self.playlist_frame = tk.Frame(self.playlists_canvas, bg=self.c)
self.playlists_scrollbar = ttk.Scrollbar(self.playlists_tab, orient='vertical',
command=self.playlists_canvas.yview)
self.add_playlist_win = tk.Toplevel(self.root)
self.add_playlists_button = tk.Button(self.playlist_frame)
self.default_img = Image.open('images/default.png').resize((75, 72))
self.default_img = ImageTk.PhotoImage(self.default_img)
self.add_img = Image.open('images/add.png').resize((50, 50))
self.add_img = ImageTk.PhotoImage(self.add_img)
self.widgets()
self.root.mainloop()
def widgets(self):
self.playlists_tab.place(height=self.height, width=self.width, x=0, y=0)
self.main.add(self.playlists_tab, text="Playlists")
self.main.pack(expand=1, fill="both")
self.playlist_frame = tk.Frame(self.playlists_canvas, bg=self.c)
self.playlists_canvas.create_window((0, 0), window=self.playlist_frame, anchor='center')
self.playlists_canvas.config(bg=self.c)
self.playlists_canvas.place(height=int(self.height / 1.428), width=self.width, x=0, y=int(self.height / 9))
self.add_playlists_button = tk.Button(self.playlists_canvas, image=self.add_img, bg=self.c, bd=0,
command=self.add_playlists)
self.add_playlists_button.place(x=1284, y=75)
self.playlists_scrollbar.pack(side='right', fill='y')
self.playlists_canvas.config(yscrollcommand=self.playlists_scrollbar.set)
self.playlists_canvas.bind('<Configure>', lambda e: self.playlists_canvas.configure(
scrollregion=self.playlists_canvas.bbox('all')))
if os.path.getsize('playlistsnames.txt') != 0:
lines = open('playlistsnames.txt', 'r', encoding='utf-8').read().splitlines()
for i in lines:
self.playlists[i] = []
self.create_playlists()
def create_playlists(self):
self.playlists_buttons_list = []
for i in range(len(self.playlists.keys())):
self.playlists_buttons_list.append(tk.Button(self.playlist_frame, bg=self.c,
text=' ' + list(self.playlists.keys())[i].split('!')[0],
fg='white', image=self.default_img, height=280, width=300))
row = 0
column = 0
for i in self.playlists_buttons_list:
if column > 3:
row += 1
column = 0
if column > 7:
row += 1
column = 0
i.grid(row=row, column=column)
column += 1
def get_name(self):
self.name_of_plst = self.plst_entry.get()
self.playlists[self.name_of_plst] = []
self.create_playlists()
with open('playlistsnames.txt', 'a', encoding='utf-8') as names_file:
names_file.write(self.name_of_plst + '!\n')
def add_playlists(self):
self.add_playlist_win = tk.Toplevel(self.root)
self.name_label = tk.Label(self.add_playlist_win, text='Name:', bg=self.c, fg='pink').pack()
self.plst_entry = tk.Entry(self.add_playlist_win)
self.plst_entry.pack()
self.confirm_btn = tk.Button(self.add_playlist_win, text='Confirm', bg=self.c, fg='pink',
command=self.get_name).pack()
self.add_playlist_win.mainloop()
MyApp()
I should also mention that because I store the playlist names in a file called playlistnames.txt when I rerun the program I can see all the playlist buttons plus the one I created before and things work just fine.
So what I want is making the grid update and work while running the app without having to rerun the app of course
My playlistsnames.txt file has this format:
rock!
metal!
chill!
rap!
jazz!
blues!
hard rock!
trap!
Any suggestions would be helpful!
Thanks in advance!

My canvas doesnt let me scroll python

I was creating a youtube manager for my personal use, and it was going decently well, until I hit a brick wall with the UI.
Here's the code:
class Application(ttk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.create_widgets()
def create_widgets(self):
nb = ttk.Notebook(self)
page1 = ttk.Frame(nb, width= 300)
#page1 = ttk.Frame(self, width= 300)
nb.add(page1, text='One')
#page1.grid()
nb.grid()
frames = {}
labels = {}
lk_btns = {}
cmt_btns = {}
mk_wch_btns = {}
dwld_btns = {}
i = 0
scrollbar = ttk.Scrollbar(page1)
#scrollbar.grid(row = 0,column = 1,sticky = "ns")
scrollbar.pack(side = "right",fill = "y")
listbox = tk.Canvas(page1,yscrollcommand = scrollbar.set,)
#listbox.grid(row = 0,column = 0,sticky = "nsew")
listbox.pack(side = "left",fill = "both")
for v in test.getLatestVids():
frm = ttk.Frame(listbox)
frm.grid(row=i, column=1,sticky = "E")
lb = ttk.Label(frm, text=convert65536(v["snippet"]["title"]))
lb.grid(row = 0,rowspan = 4,column=0,sticky = "E")
labels[i] = lb
download = ttk.Button(frm, text="Download")
download.grid(row = 1,column=1,sticky = "W")
dwld_btns[i] = download
mwatched = ttk.Button(frm, text="Mark Watched")
mwatched.grid(row = 2,column=1,sticky = "W")
mk_wch_btns[i] = mwatched
like = ttk.Button(frm, text="Like")
like.grid(row = 1,column=2,sticky = "W")
lk_btns[i] = like
comment = ttk.Button(frm, text="Comment")
comment.grid(row = 2,column=2,sticky = "W")
cmt_btns[i] = comment
frames[i] = frm
i += 1
scrollbar.config(command=listbox.yview)
listbox.configure(scrollregion=(-400, -400, 400, 400))
#self.quit = tk.Button(self, text="QUIT", fg="red",
# command=root.destroy)
root = tk.Tk()
app = Application(master=root)
app.mainloop()
PS1: The "convert65536" method is a method for handling the emojis in youtube titles. I found it here.
PS2: The "test.getLatestVids" method is an external method I made that returns a list of dictionaries.
The problem here is that the code thinks there is a lot of space, and does'nt use the scrollbar instead. I tried to make this work by limiting the size of "page1", but I failed to do so.
Here are some screenshots:
In fullscreen
Seeing the entire list thanks to multiple desktops
Items added to a canvas with pack, place or grid will not scroll. The only things that will scroll on a canvas are windows added with create_window.
The most common solution is to add one frame to the canvas, and then pack, place, or grid widgets inside the frame. See http://stackoverflow.com/a/3092341/7432.
If you're creating a vertical list of text and widgets, an even simpler solution is to use a text widget, which allows you to embed widgets with the window_create method.

Volume Slider using Tkinter

I'm new to coding, and I am attempting to create a juke box for a school project, but I'm struggling to create a slider that will edit the volume. I'm just unsure where to start to get the volume to actually change as I move the slider.
I'm using VLC lib.
import vlc
import random
from tkinter import *
import threading
song = ""
instance = vlc.Instance()
def get_songs():
global song
global x
global songs
songs = filedialog.askopenfilenames()
x = 0
song = songs[x]
print(songs)
commence(song)
def pause_resume():
player.pause()
def commence(song):
global player
global x
player = instance.media_player_new()
media = instance.media_new(song)
player.set_media(media)
player.play()
def next_song():
if x >= len(songs):
print("Error: Can't go any further")
x = 0
return
player.stop()
song = songs[x]
commence(song)
window = Tk()
window.geometry("600x600")
window.title('JukeBox')
#pause_button = Button(window, text = "Next", command = next_song)
#pause_button.grid(row=1, column = 2)
Button(window, text="Start", command=get_songs).grid(column=1,row=1)
Button(window, text="Next", command=next_song).grid(column=1,row=2)
pause_button = Button(window, text = "Pause/Resume", command = pause_resume)
pause_button.grid(row=3, column = 1)
menubar = Menu(window)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_separator()
filemenu.add_command(label="Open", command=get_songs())
filemenu.add_command(label="Exit", command=window.destroy)
menubar.add_cascade(label="File", menu=filemenu)
window.config(menu=menubar)
vol = Scale(window,from_ = 0,to = 1,orient = HORIZONTAL ,resolution = .1,)
vol.grid(row = 1, column = 2)
window.mainloop()
I understand I'm not using the best coding practices, but this way I can actually understand what I have written.
Set the command parameter when creating the Scale widget:
def set_volume(v):
global vol
global player
# either get the new volume from given argument v (type: str):
# value = int(v)
# or get it directly from Scale widget (type: int)
value = vol.get()
player.audio_set_volume(value)
vol = Scale(..., command=set_volume)
My mate was able to help me with this by simply adding self in the required paramaters of the function, no clue why it helps and thanks everyone for trying, much appreciated.
def show_value(self):
global player
i = vol.get()
player.audio_set_volume(i)
vol = Scale(window,from_ = 0,to = 100,orient = HORIZONTAL ,resolution = 1,command = show_value)
vol.place(x=75, y = 300)
vol.set(50)

tkinter button double use

I'm new here and new in PY, I'm trying to write a simple GUI with Tkinter (py 2.7.10) where there are two buttons: the first one starts printing stuff and the second one quits.
I'd like the first button to change the text after the first click from "START" to "STOP" and of course to stop the loop, so I can pause instead of closing and reopen every time.
Also feel free to give any advice to improve it :)
I hope it's clear, here is the code.
import random, time
from Tkinter import *
START, STOP = "start", "stop"
class AppBase:
def __init__(self, root):
self.myRoot = root
self.frame1 = Frame(root)
self.frame1["background"] = "LightSteelBlue"
self.frame1.pack()
self.delay = Scale(self.frame1, from_=100, to=0)
self.delay.pack(side = LEFT, padx=5, pady=15)
self.label0 = Label(self.frame1, text="Notes", background="LightSteelBlue", foreground="darkblue")
self.label0.pack(padx=5, pady=15)
self.label1 = Label(self.frame1, text="NOTE", background="LightSteelBlue", foreground="SteelBlue")
self.label1.pack(padx=30, pady=10)
self.label2 = Label(self.frame1, text="STRING", background="LightSteelBlue", foreground="SteelBlue")
self.label2.pack(padx=30, pady=7)
self.label3 = Label(self.frame1, text="FINGER", background="LightSteelBlue", foreground="SteelBlue")
self.label3.pack(padx=30, pady=7)
self.puls1 = Button(self.frame1)
self.puls1.configure(text = "Start", background = "CadetBlue", borderwidth = 3, command = self.generate_notes)
self.puls1.pack(side = LEFT, padx=5, pady=15)
self.puls2 = Button(self.frame1)
self.puls2.configure(text = "Exit", background = "CadetBlue", borderwidth = 3)
self.puls2.pack(side = LEFT, padx=5, pady=15)
self.puls2.bind("<Button-1>", self.close_all)
self.notes_process=1
def generate_notes(self):
self.notes = ['DO','DO#','RE','RE#','MI','MI#','FA','FA#','SOL','SOL#','LA','LA#','SI','SI#']
self.strings = ['1^ corda','2^ corda','3^ corda','4^ corda','5^ corda','6^ corda']
self.fingers = ['Indice','Medio','Anulare','Mignolo']
self.note = random.randrange(0, len(self.notes))
self.string = random.randrange(0, len(self.strings))
self.finger = random.randrange(0, len(self.fingers))
self.timer=self.delay.get()
if self.timer == '':
self.timer = 500
elif int(self.timer) < 1:
self.timer = 500
else:
self.timer=int(self.delay.get())*100
self.label1["text"] = self.notes[self.note]
self.label2["text"] = self.strings[self.string]
self.label3["text"] = self.fingers[self.finger]
self.myRoot.after(self.timer, self.generate_notes)
def close_all(self, evento):
self.myRoot.destroy()
self.myRoot.quit()
def main():
master = Tk()
master.title("Notes")
appBase = AppBase(master)
master.mainloop()
main()
I found a solution, thanks to everybody for their help and of course if you want to keep talking about different and (sure) better way to do, you are more than welcome!
Here my solution:
step 1, add this to the button:
self.puls1.bind("<Button-1>", self.puls1Press1)
step 2, add a new variable:
self.active = True
step 3, create a new function:
def puls1Press1(self, evento):
if self.puls1["text"] == "Start":
self.puls1["text"] = "Stop"
self.active = True
else:
self.puls1["text"] = "Start"
self.active = False
step 4, modify the function that I want to stop:
def generate_notes(self):
if self.active == True:
[some code]
[some code]
else:
return
You need to save the return value of the after, so that you can use it when you cancel the loop using after_cancel(the_return_value_of_after).
def generate_notes(self):
if self.puls1['text'] == 'Start':
# Change button text to Stop, and call the original loop function
self.puls1['text'] = 'Stop'
self._generate_notes()
else:
# cancel timer
self.puls1['text'] = 'Start'
self.myRoot.after_cancel(self.timer_handle)
def _generate_notes(self):
...(old codes)..
self.timer_handle = self.myRoot.after(self.timer, self._generate_notes)
StringVar() from variable class can be used to update text as well as a looping condition. Example code:
ButtonText=StringVar()
ButtonText.set("START")
button1 = tkinter.Button(self.frame1, text=ButtonText, width=25, command= lambda: do_something(ButtonText))
Elsewhere where you are looping check for the value of the variable:
My_Loop():
if(ButtonText.get()=="STOP"):
break
else:
#some print statements
Now in function do_something(ButtonText), which will be called after each button press, change the string to "STOP" or vice versa :
do_something(ButtonText):
if(ButtonText.get()=="START): #Change text
ButtonText.set("STOP")
else:
ButtonText.set("START") #Change text and call function to loop again
My_Loop()
Hope this helps.

Categories