I'm rewriting my program in OOP and I'm faced with the problem that I can't turn to graphInA and graphInB in the calBut function. How can I implement this?
import customtkinter as CTtk
from tkinter import *
from tkinter import messagebox
from tkinter.ttk import Style
class App(CTtk.CTk):
def __init__(self):
super().__init__()
self.initUI()
self.checkNaN()
def initUI(self):
self.title("График функции")
CTtk.set_appearance_mode("dark")
CTtk.CTkLabel(text="Введите пределы интегрирования").grid(row=0,column=0)
CTtk.CTkLabel(text="до", width=50).grid(row=0,column=1)
CTtk.CTkLabel(text="и от", width=50).grid(row=0,column=3)
graphInA = CTtk.CTkEntry(width=50)
graphInA.grid(row=0, column=2)
graphInB = CTtk.CTkEntry(width=50)
graphInB.grid(row=0, column=4)
but = CTtk.CTkButton(text="Рассчитать", fg_color="black", width=50, command=self.calBut)
but.grid(row=0, column=5, padx=10)
def calBut(self):
if len(graphInA.get()) > 0 and len(graphInB.get()) > 0:
try:
float(graphInA.get())
float(graphInB.get())
except TypeError:
messagebox.showinfo("Ошибка", "Значение не число")
else: return 0
else:
messagebox.showinfo("Ошибка", "Введите значение")
app = App()
app.mainloop()
I wanted to use the function parameters, but I didn't figure it out
You have two options. You can bind the variables you want as instance variables on self (i.e. the application object)
self.graphInA = CTtk.CTkEntry(width=50)
# Then later ...
if len(self.graphInA.get()) > 0:
...
or you can write a lambda that explicitly closes around the variables you want.
def calBut(self, graphInA, graphInB):
...
# Then, to bind the command ...
but = CTtk.CTkButton(
text="Рассчитать",
fg_color="black",
width=50,
command=lambda: self.calBut(graphInA, graphInB),
)
Related
I'm tinkering with Tkinter and trying to check if my program is open on pressing a button, but the Tkinter is not updating my label. Why?
from win32gui import GetWindowRect, FindWindow
from tkinter import Tk, ttk, BooleanVar
class Bot:
root = Tk()
is_gta_open = BooleanVar(None, False)
def mta_open_string(self):
return "włączone" if self.is_gta_open.get() else "wyłączone"
def draw_gui(self):
frame = ttk.Frame(self.root, padding=10)
frame.grid()
ttk.Label(frame, text=f"Status gry: {self.mta_open_string()}").grid(column=0, row=0)
ttk.Button(frame, text="Odśwież", command=lambda: [self.try_finding_rect(), self.root.update()]).grid(column=1, row=0)
self.root.mainloop()
def try_finding_rect(self):
window_handle = FindWindow("Grand theft auto San Andreas", None)
if window_handle == 0:
self.is_gta_open.set(False)
return
self.is_gta_open.set(True)
def run(self):
self.try_finding_rect()
self.draw_gui()
if __name__ == "__main__":
Bot().run()
I'm updating the state using self.root.update method and using BooleanVar, so I don't know why this is not working.
I've put together a very minimal example app that should work as intended. I don't have a copy of GTA to test with so I used a different app, but it should function the same way with any app in principle:
import tkinter as tk
import ctypes
from tkinter import ttk
class Bot(tk.Tk): # init Tk
def __init__(self):
super.__init___()
APP_NAME = 'Grand theft auto San Andreas'
self.status_label = tk.Label(self, text='Press the button')
self.status_label.pack()
self.run_btn = ttk.Button(
self,
text='Click Me!',
command=lambda: self.check_for_app(APP_NAME)
)
self.run_btn.pack()
def check_for_app(app_name: str):
user32 = ctypes.WinDLL('user32')
if user32.FindWindowW(None, app_name):
self.status_label.config(text='Running')
else:
self.status_label.config(text='Not Running')
if __name__ == '__main__':
app = Bot()
app.mainloop()
Updating a variable won't change an f-string that uses the variable. You must explicitly configure the widget to show the new value.
To do that you'll need to keep a reference to the label widget, and then update the widget with the configure method.
def draw_gui(self):
...
self.status_label = ttk.Label(frame, text=f"Status gry: {self.mta_open_string()}")
self.status_label.grid(column=0, row=0)
...
def try_finding_rect(self):
...
self.is_gta_open.set(True)
self.status_label.configure(text=f"Status gry: {self.mta_open_string()}")
Personally I recommend using a proper method for the button rather than a complicated lambda. That will make the code easier to read and easier to debug.
For example:
def draw_gui(self):
...
ttk.Button(frame, text="Odśwież", command=self.update_status)
...
def update_status(self):
self.try_finding_rect(),
self.status_label.configure(text=f"Status gry: {self.mta_open_string()}")
i'm a new programmer and there are certainly several errors but this shouldn't be difficult to spot. I need to create a simple window with a field named "Concorrente 1:" and an entry field displayed by function named lacopertina(). I don't understand where is the error:
import tkinter as tk
from tkinter import *
from tkinter.ttk import *
from tkinter import ttk
class schermoiniziale(tk.Frame):
def lacopertina():
print(gio1)
#return (tot1)
def __init__(self):
global gio1
#tot1=0
#schermo1=Tk()
self.gio1=tk.StringVar()
lab1=ttk.Label(self, text="Concorrente 1:")
lab1.pack()
ent1=ttk.Entry(self, textvariable=self.gio1)
ent1.pack()
pulsante = ttk.Button(self, text="Inizio", textvariable=self.gio1, command=self.lacopertina)
pulsante.pack()
def main():
schermoiniziale().mainloop()
if __name__== "__main__":
main()
I would suggest you to go through some tutorials on Python OOP.
I have modified your code as below with some comment:
# avoid using wildcard import
import tkinter as tk
from tkinter import ttk
class schermoiniziale(tk.Frame):
def __init__(self, master, **kw):
# need to call __init__() of inherited class
super().__init__(master, **kw)
self.gio1 = tk.StringVar()
lab1 = ttk.Label(self, text="Concorrente 1:")
lab1.pack()
ent1 = ttk.Entry(self, textvariable=self.gio1)
ent1.pack()
# removed textvariable=self.gio1 as I think you actually don't need it
pulsante = ttk.Button(self, text="Inizio", command=self.lacopertina)
pulsante.pack()
def lacopertina(self):
# use .get() to get the content of a StringVar
print(self.gio1.get())
def main():
# need to create the root window before creating other widget
root = tk.Tk()
# pass root window as the parent of the widget
frame = schermoiniziale(root)
frame.pack()
# start the tkinter mainloop
root.mainloop()
if __name__== "__main__":
main()
MainTicTacToe.py
import tkinter as tk
import MenubarCommand as mbc
class Game(tk.Frame):
def __init__(self,parent):
tk.Frame.__init__(self,parent)
self.parnt=parent
# self.parnt.geometry('500x300')
self.parnt.title("Tic Tac Toe")
# self.pack()
menubar=tk.Menu(parent)
# 'settings' menu
settingsOption=tk.Menu(menubar, tearoff=0)
settingsOption.add_command(label='Player Settings', command=self.doit)
settingsOption.add_command(label='Board Settins', command=self.doit)
menubar.add_cascade(label='Setings', menu=settingsOption)
# without using this method, menubar isn't shown in Frame
self.parnt.config(menu=menubar)
def doit(self):
root=self.win()
set=mbc.playerSettings(root)
# print(set.p1name)
root.mainloop()
def win(self):
return tk.Tk()
def main():
root=tk.Tk()
Game(root)
root.mainloop()
main()
MenubarCommand.py
import tkinter as tk
class playerSettings(tk.Frame):
def __init__(self,parent=tk.Frame):
tk.Frame.__init__(self,parent)
self.parnt=parent
self.parnt.title("Player Setting")
self.p1name='Player 1'
self.p2name='Player 2'
self.p1symbol='x'
self.p2symbol='o'
# **********************************#
self.p1NameLabel = tk.Label(parent, text='Player 1: Name ')
self.p1NameLabel.grid(row=0, column=0)
self.p1NameEntry = tk.Entry(parent)
self.p1NameEntry.insert(0,self.p1name)
self.p1NameEntry.bind('<FocusIn>', lambda event:self.p1NameEntry.delete(0,'end'))
self.p1NameEntry.grid(row=0, column=1)
apply=tk.Button(parent, text="Apply Settings", fg='white', bg='gray', command=self.saveStat)
apply.grid(row=2, rowspan=1, columnspan=4)
def saveStat(self):
print('Settings Window Destroyed')
self.p1name=self.p1NameEntry.get()
print(self.p1name)
self.parnt.destroy()
I want to change the value of attribute of an instance in one file from the instance of another class in another file already created.
When I change default Player name in MenubarComman.py file, I want to access the changed name from MainTicTacToe.py class. How can I do this?
I'm new new in Python.
Thanks in Advance.
You problems stem from 2 instances of Tk(), and sloppy programming, i.e. sometimes you use parent, and sometimes self.parnt which is a bad habit to get into, so everything is changed to self.top so an error will pop up if any of those two remains.. You also have to have a way to signal when PlayerSetting() is finished. The way the program is structured, the only way that I know of is to check for "alive" using recursion. You could also have PlayerSettings call a function in Game() when finished, which would print the value. I have cleaned up your code and it works as I understand it should.. Note that the 2 classes are in the same file to make it easier to test and post here.
import tkinter as tk
##import MenubarCommand as mbc
class Game():
def __init__(self,parent):
self.parnt=parent
# self.parnt.geometry('500x300')
self.parnt.title("Tic Tac Toe")
# self.pack()
menubar=tk.Menu(parent)
# 'settings' menu
settingsOption=tk.Menu(menubar, tearoff=0, bg="yellow")
settingsOption.add_command(label='Player Settings', command=self.doit)
settingsOption.add_command(label='Board Settins', command=self.doit)
menubar.add_cascade(label='Setings', menu=settingsOption)
# without using this method, menubar isn't shown in Frame
self.parnt.config(menu=menubar)
def doit(self):
## do not open more than one Tk() instance
##root=self.win()
self.top=tk.Toplevel(self.parnt)
self.set_it=PlayerSettings(self.top)
self.get_variable()
##root.mainloop()
def get_variable(self):
""" check continuously if PlayerSettings has exited and
if so, get the Entry's value
"""
if self.set_it:
self.parnt.after(1000, self.get_variable)
else:
print("from Game", self.set_it.p1name)
def win(self):
return tk.Tk()
class PlayerSettings():
def __init__(self, parent):
self.top=parent
self.p1name='Player 1'
self.p2name='Player 2'
self.p1symbol='x'
self.p2symbol='o'
# **********************************#
self.p1NameLabel = tk.Label(self.top, text='Player 1: Name ', bg="lightblue")
self.p1NameLabel.grid(row=0, column=0)
self.p1NameEntry = tk.Entry(self.top)
self.p1NameEntry.focus_set()
self.p1NameEntry.insert(0,self.p1name)
##self.p1NameEntry.bind('<FocusIn>', lambda event:self.p1NameEntry.delete(0,'end'))
self.p1NameEntry.grid(row=0, column=1, sticky="nsew")
apply=tk.Button(self.top, text="Apply Settings", fg='white', bg='gray', command=self.saveStat)
apply.grid(row=2, rowspan=1, columnspan=4)
def saveStat(self):
self.p1name=self.p1NameEntry.get()
print(self.p1name)
print('Settings Window Destroyed')
self.top.destroy()
root=tk.Tk()
Game(root)
root.mainloop()
I am creating a Tkinter program that allows the user to enter text into a nice looking box rather than the python shell.
As I would like to use this in multiple programs I made into a function that can be used in other files.
I can get it to run in another file, but not import the variable here is my code.
File 1:
import tkinter as tk
def input_text(label_text, button_text):
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text=button_text, command=self.on_button)
self.label = tk.Label(self, text=label_text)
self.label.pack(side = 'top', pady = 5)
self.button.pack(side = 'bottom', pady = 5)
self.entry.pack()
def on_button(self):
answer = self.entry.get()
self.destroy()
w = SampleApp()
w.resizable(width=True, height=True)
w.geometry('{}x{}'.format(180, 90))
w.mainloop()
File 2:
import text_input as ti
from text_input import answer
ti.input_text('Enter some text', 'OK')
I get the error ImportError: cannot import name 'answer'
answer is a local variable withinbutton. If you want toimport` it, you need to make it a package attribute:
import tkinter as tk
global answer
def input_text(label_text, button_text):
class SampleApp(tk.Tk):
...
def on_button(self):
global answer
answer = self.entry.get()
However, this is a very strange way to access the data. Clean module design would likely have the object (SampleApp) at hand, and extract the answer with a method call for that app. More simply, why not just return that value from on_button?
def on_button(self):
answer = self.entry.get()
self.destroy()
return answer
... so your usage would be
response = my_app.on_button()
I'm writing a python script that requires the user to enter the name of a folder. For most cases, the default will suffice, but I want an entry box to appear that allows the user to over-ride the default. Here's what I have:
from Tkinter import *
import time
def main():
#some stuff
def getFolderName():
master = Tk()
folderName = Entry(master)
folderName.pack()
folderName.insert(END, 'dat' + time.strftime('%m%d%Y'))
folderName.focus_set()
createDirectoryName = folderName.get()
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
return
b = Button(master, text="OK and Close", width=10, command=callback)
b.pack()
mainloop()
return createDirectoryName
getFolderName()
#other stuff happens....
return
if __name__ == '__main__':
main()
I know next to nothing about tkInter and have 2 questions.
Is over-riding the default entry using global createDirectoryName within the callback function the best way to do this?
How can I make the button close the window when you press it.
I've tried
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
master.destroy
but that simply destroys the window upon running the script.
I don't know how experienced are you in Tkinter, but I suggest you use classes.
try:
from tkinter import * #3.x
except:
from Tkinter import * #2.x
class anynamehere(Tk): #you can make the class inherit from Tk directly,
def __init__(self): #__init__ is a special methoed that gets called anytime the class does
Tk.__init__(self) #it has to be called __init__
#further code here e.g.
self.frame = Frame()
self.frame.pack()
self.makeUI()
self.number = 0 # this will work in the class anywhere so you don't need global all the time
def makeUI(self):
#code to make the UI
self.number = 1 # no need for global
#answer to question No.2
Button(frame, command = self.destroy).pack()
anyname = anynamehere() #remember it alredy has Tk
anyname.mainloop()
Also why do you want to override the deafult Entry behavior ?
The solution would be to make another button and bind a command to it like this
self.enteredtext = StringVar()
self.entry = Entry(frame, textvariable = self.enteredtext)
self.entry.pack()
self.button = Button(frame, text = "Submit", command = self.getfolder, #someother options, check tkitner documentation for full list)
self.button.pack()
def getfolder(self): #make the UI in one method, command in other I suggest
text = self.enteredtext.get()
#text now has whats been entered to the entry, do what you need to with it