Python: Button command + '&' - python

I got an error at this code:
The error is in my function settings() in the Button() command. but I don't got any plan how to fix it, sorry. I can't put the 3 commands in an external function, cause it wouldn't get the variables...
from turtle import *
from tkinter import *
reset()
hastrail = 1
def moveup():
setheading(90)
forward(5)
def movedown():
setheading(270)
forward(5)
def moveright():
setheading(0)
forward(5)
def moveleft():
setheading(180)
forward(5)
def turnleft():
left(18)
def turnright():
right(18)
def forw():
forward(5)
def backw():
backward(5)
def trailrem():
global hastrail
if hastrail == 1:
penup()
hastrail = 0
else:
pendown()
hastrail = 1
def settings():
color(str(colorchooser.askcolor(title = "Change a line color")[1]),str(colorchooser.askcolor(title = "Change a fill color")[1]))
tk = Tk ()
tk.resizable(0,0)
tk.title("Shape, Shapesize, Pensize")
tk.geometry("400x90")
listbox = Listbox(tk)
listbox.place(x=0,y=0,width=200,height=90)
listbox.insert(1,"arrow")
listbox.insert(2,"turtle")
listbox.insert(3,"circle")
listbox.insert(4,"square")
listbox.insert(5,"triangle")
shsi = Scale(tk,width = 10,orient = HORIZONTAL)
shsi.place(x=200,y=0,width=200,height=30)
trsi = Scale(tk,width = 10, orient = HORIZONTAL)
trsi.place(x=200,y=30,width=200,height=30)
Button(tk,text="Save",command = lambda:shape(str(listbox.get(ACTIVE)))&shapesize(int(shsi.get()))&pensize(int(trsi.get()))).place(x=200,y=60,width=200,height=30)
onkeypress(moveup,"Up")
onkeypress(movedown,"Down")
onkeypress(moveright,"Right")
onkeypress(moveleft,"Left")
onkeypress(turnleft,"a")
onkeypress(turnright,"d")
onkeypress(forw,"w")
onkeypress(backw,"s")
onkeypress(trailrem,"t")
onkeypress(settings,"c")
listen()
mainloop()
Pls tell me what I've done wrong // fix it pls.

If you're trying to string together multiple expressions using the & operator, it isn't likely to work well, unless all of your function calls return integers, which isn't the case here. I don't recommend it, but you can put each command as a separate element of a collection such as a list or tuple:
Button(tk,text="Save",command = lambda:[
shape(str(listbox.get(ACTIVE))),
shapesize(int(shsi.get())),
pensize(int(trsi.get()))
]).place(x=200,y=60,width=200,height=30)
I can't put the 3 commands in an external function, cause it wouldn't get the variables
Ordinarily, this is true. But if you define the second function inside the first, all of its variables will still be visible.
def settings():
def save_button_clicked():
shape(str(listbox.get(ACTIVE)))
shapesize(int(shsi.get()))
pensize(int(trsi.get()))
#rest of `settings` code goes here...
Button(tk,text="Save",command = save_button_clicked).place(x=200,y=60,width=200,height=30)

Related

Python CLR Winforms - Passing data between .NET Winforms

I have a fairly simple task that has eluded me when using Python to generate and automate .NET WinForms. How do I pass data between forms?
I've tried everything: using global variables, using immutable strings, etc. and nothing seems to stick. Can someone show me an example, send me a link, or let me know what I am doing wrong? I have been at this for over a week and frustration is starting to mount.
Below is a (sloppy) example of taking data from one form - a string - and sending it to another form in a Textbox.
MYSTRING = ''
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Windows.Forms import *
from System.Drawing import *
class MyForm(Form):
def __init__(self):
self.Text1 = TextBox()
self.Button1 = Button()
self.Button1.Location = Point(0, self.Text1.Bottom + 10)
self.Button1.Text = 'Send'
self.Controls.Add(self.Text1)
self.Controls.Add(self.Button1)
self.Button1.Click += self.Button1_Click
def Button1_Click(self, sender, args):
MYSTRING = self.Text1.Text
self.TopLevel = False
f2 = MyForm2()
f2.Show()
self.TopLevel = True
class MyForm2(Form):
def __init__(self):
self.Text2 = TextBox()
self.Controls.Add(self.Text2)
self.Load += self.MyForm2_Load
def MyForm2_Load(self, sender, args):
self.Text2.Text = MYSTRING
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
Application.Run(MyForm())
So, I figured it out...again.
I had to set a python global variable within one of my events that triggers an event, like so...
def dgvExpanderInfo_CellDoubleClick_Event(self, sender, args):
global SelectedExpanderData_List
...
...then I could access whatever is in that globabl variable - in this case it was a list.
def MyForm2_Form_Load_Event(self, sender, args):
self.textbox1.Text = SelectedExpanderData_List[0]
self.textbox2.Text = SelectedExpanderData_List[1]
self.textbox3.Text = SelectedExpanderData_List[2]
...
I hope this helps others as I have found no real documentation on this anywhere.

How can I have imported modules access tkinter widgets and variables?

I had this Cafe Management System whom I've separated the gui and functions into modules.
Here are some snippets:
main.py
from tkinter import *
import checkbox_operation
import receipt_operation
class cafemanagementsystem:
def __init__(self, cms):
self.cms = cms
cms.title("Cafe Management System")
self.b1var = IntVar(value=1)
self.b1v = StringVar()
self.b1v.set("0")
self.b1 = Checkbutton(self.bevmenu, command=self.check, text="Latte", variable=self.b1var, onvalue=1, offvalue=0).grid()
self.b1a = Entry(self.bevmenu, bd=2, textvariable=self.b1v)
self.b1a.grid()
self.rcpt = Text(self.rcptmain, width=50, height=30, bd=4)
self.rcpt.grid()
self.btnrcpt = Button(self.rcptbtn, command=receipt_operation.receipt, text="Receipt").grid()
self.btnrst = Button(self.rcptbtn, command=receipt_operation.reset, text="Reset").grid()
def check(self):
checkbox_operation.check(self)
def receipt(self):
receipt_operation.receipt(self)
checkbox_operation.py
def check(cafemanagementsytem_inst):
if b1var.get() == 1:
b1a.config(state=NORMAL)
elif b1var.get() == 0:
b1a.config(state=DISABLED)
b1v.set("0")
receipt_operation.py
def receipt():
rcpt.insert(END, "Offical Receipt\n")
rcpt.insert(END, "Latte \t\t\t\t" + b1v.get() + "\n")
My problem is that I can't get check() and receipt() to work. Also, def check(self) and def receipt(self) gives the following error:
TypeError: check()/receipt() takes 0 positional arguments but 1 was given
Are there any solutions for this? Also, please tell me if the way I wrote the code contributed to the problem as I've been stuck in this problem for almost a week.
You need to pass the proper variables into those other functions. I'm wondering why you have checkbox_operation in a separate file, when it should be part of the class. It's not good practice that those external functions need to have such detailed knowledge of the internal workings of the class.
...
def check(self):
checkbox_operation.check(self)
def receipt(self):
receipt_operation.receipt(self)
def check(cafe):
if cafe.b1var.get() == 1:
cafe.b1a.config(state=NORMAL)
elif cafe.b1var.get() == 0:
cafe.b1a.config(state=DISABLED)
cafe.b1v.set("0")
def receipt(cafe):
cafe.rcpt.insert(END, "Offical Receipt\n")
cafe.rcpt.insert(END, "Latte \t\t\t\t" + cafe.b1v.get() + "\n")

How can I test a function that is embedded in a method

I recently started doing python. The course I was on ended with an introduction to testing with doctest. I have written a program that uses Tkinter to display widgets and it works :-) . I am using version 3.7. However, testing it is another matter. I can test simple functions and methods, but I hit difficulties when I have a function inside a method. I am pasting below a stripped-down version of what I am trying to achieve. I tried first with doctest and it threw up an error:
"AttributeError: 'function' object has no attribute 'c_square'".
# counter.py
from tkinter import *
import doctest
count = 0
delay = 1000
class MyClass:
def __init__(self, master):
master.geometry("1000x500")
master.resizable(0, 0)
master.title("Display a counter")
frame1 = Frame(master)
frame1.pack()
label1 = Label(frame1, font = ('Courier', 15 , 'bold'))
label1.grid(row = 0, column = 0)
self.my_counter(label1)
label2 = Label(frame1, font = ('Courier', 15 , 'bold'))
label2.grid(row = 0, column = 1)
self.square_of_count(label2)
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text = string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_c_square(number):
"""
>>> test_c_square(2)
4
"""
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font = ('Courier', 15 , 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
""" # main body commented out for test purposes.
root = Tk()
a = MyClass(root)
root.mainloop()
"""
doctest.testmod(verbose=True)
if __name__ == "__main__":
main()
I am using a separate test function, so that I can initialise my counter.
Then someone suggested that I try unittest, so I wrote this :
import unittest
import counter
class TestCounter(unittest.TestCase):
counter.count = 2
print("count = ", counter.count)
def square_of_count(self):
result = counter.c_square()
self.assertEqual(result, 4)
result = counter.c_square()
self.assertNotEqual(result, 3)
if __name__ == '__main__':
unittest.main()
This runs without throwing up any errors, the purpose of it is to set a value to the variable 'count' and read back the result. But I get the same response whatever value I test for, so I do not believe it is working right. I also tried variations on a theme, but I just got error messages.
Can someone please point out what I am doing wrong, I have looked about various forums and tutorials but have not seen this question asked before.
I would appreciate an answer that is easy to follow, I am asperger / dyslexic and find it difficult to learn new material. A correction with explanation would be most helpful. Thank you.
First of all, avoid this kind of nesting the functions. In your particular case I would highly suggest refactoring of a code in manner of creating some help private methods which you will call from the main ones, or even create whole new utility class:
class Util:
def _init_(self):
self.name = "Utility"
def add_two_numbers(self, first, second):
if(isinstance(first, int) and isinstance(second, int)):
return first+second
class SomeFancyClass:
def __init__(self):
self.util = Util()
self.constant = 4
# This method recursively increments a counter and displays the count.
def my_fancy_math(self, first, second):
return self.constant * self.util.add_two_numbers(first, second)
FancyVar = SomeFancyClass()
print(FancyVar.my_fancy_math(5, 6))
In case you dont want to change your code (for some reason), there is extremely dirty way to access your inner function. Again, a bit stupidly modified example made from your code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# counter.py
from tkinter import *
import doctest
import types
count = 0
delay = 1000
class MyClass:
def __init__(self, smth1):
self.something = smth1
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text=string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def test_function1(self, first, second):
return first+second
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_function(self, st1):
print(st1)
def test_c_square(number):
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font=('Courier', 15, 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
doctest.testmod(verbose=True)
if __name__ == '__main__':
# main()
print('done')
test_function = types.FunctionType(MyClass.square_of_count.__code__.co_consts[1],
{}, None, (), ())
obj = MyClass("Hi")
sum1 = test_function("", 1, 2)
print(sum1)

Python GUI shuts down when i use infinite loop

I tried to make a Clicker and I used an infinite loop, so I would raise my Variable every second. But every time I use the Button, my program crashes.
Do you have any advice how I prevent that, because I have no idea what is really happening.
import time
from tkinter import *
class Clicker :
#updates the Label
def AK_CLabel(self):
self.ClickerLabel.configure(text="Du hast " + str(self.Clicks))
#Generates Clicks
def Klicken(self):
self.Clicks += 1
self.AK_CLabel()
#raises price of Helping Elf and raises the clicks per second
def HElf(self) :
if(self.Clicks >= self.priceHElf) :
self.Clicks -= self.priceHElf
self.priceHElf = self.priceHElf * 1.2
self.Elfs += 1
self.Elfhilft()
self.AK_CLabel()
#Should make the Clicks go up by the amount of Elfs, but if I use the Button the Programm shuts down
def Elfhilft(self):
while (not time.sleep(5)):
self.Clicks = self.Bitcoins1 + self.Elfs
time.sleep(1)
def __init__(self, master):
self.master = master
self.master.title = "Der Klicker"
self.Elfs = 0
self.priceHElf = 30
self.Clicks = 30
#Buttons and Label
self.DerKnopf = Button(text = "Clicks", command = self.Klicken)
self.ClickerLabel = Label(text = "You have " +str(self.Clicks))
self.HelferElf = Button(text = "A helping Fairy", command = self.HElf)
self.DerKnopf.pack()
self.ClickerLabel.pack()
self.HelferElf.pack()
root = Tk()
my_gui = Clicker(root)
root.mainloop()
Firstly, in your example bitcoins1 is undeclared. I assume this is just a variable name you forgot to change before posting, so I renamed it to clicks in order to replicate your issue.
Second, you have your Elfhilft() function using sleep(), which is causing issues with your Tkinter app. Tkinter uses its own loop system to handle real-time stuff, and sleep will cause that loop to stall in most cases. I suggest you use an implementation of after (How to create a timer using tkinter?) in order to replicate the autoclicker-esque function I assume you're trying to implement. As an example:
def autoclick(self):
self.clicks = self.clicks + self.Elfs
#In main app / __init__()
root.after(1000, self.autoclick) # updates auto-clicks every second

Python turtle : Create a redo function

I know how to undo a drawing step in python turtle with turtle.undo(). But how can I make a Redo function ?
from tkinter import *
...#Just some other things
def undoStep():
turtle.undo()
def redoStep():
#What to put here
root.mainloop()
To make a redo function, you need to keep track of the each action, in a list actions for example. You will also need a variable i that tells you where you are in that list and each time you call undoStep, decrease i by one. Then redoStep has to perform the action actions[i]. Here is the code:
import turtle
actions = []
i = 0
def doStep(function, *args):
global i
actions.append((function, *args))
i += 1
function(*args)
def undoStep():
global i
if i > 0:
i -= 1
turtle.undo()
def redoStep():
global i
if i >= 0 and i < len(actions):
function, *args = actions[i]
function(*args)
i += 1

Categories