Data from child window - python

In the imported code, the variable 'values' is set correctly with the date selected by the user.
The def selection is called at the exit of the calendar.
I'm stuck. I don't know how to catch it and use it in my main code.
Thanks a lot.
# MAIN CODE (simplified)
from tkinter import *
import calendarWidget
def manageCalendarWindow():
root4 = Tk()
data = {}
app = calendarWidget.Calendar(root4, data)
root4.mainloop()
manageCalendarWindow()
#how to get the date?
-.-.-.-.-.-.-.
# CALENDAR WIDGET (simplified)
class Calendar:
def setup(self, y, m)
(...)
for w, week in enumerate(self.cal.monthdayscalendar(y, m), 2):
for d, day in enumerate(week):
if day:
b = tk.Button(self.parent, width=1, text=day, relief = 'flat',\
command=lambda day=day:self.selection(day, calendar.day_name[(day-1) % 7]))
self.wid.append(b)
b.grid(row=w, column=d)
def selection(self, day, name):
self.day_selected = day
self.month_selected = self.month
self.year_selected = self.year
self.day_name = name
#data
self.values['day_selected'] = day
self.values['month_selected'] = self.month
self.values['year_selected'] = self.year
self.values['day_name'] = name
self.values['month_name'] = calendar.month_name[self.month_selected]
self.setup(self.year, self.month)
print(self.values) # <--- here the value is correct
self.parent.destroy()
-.-.-.-.-.-.-.-
THIS WORKS:
def manageCalendarWindow():
root4 = Tk()
data = {}
app = calendarWidget.Calendar(root4, data)
root4.mainloop()
return app
app=manageCalendarWindow()
print(app.year_selected,app.month_selected,app.day_selected)
THIS NOT:
class enterWindows():
def B_CalendarWindow(self):`
app=self.manageCalendarWindow()
print("year: ",app.year_selected)
print("and... this will never be printed!")
def manageCalendarWindow(self):
root4 = Tk()
data = {}
app = calendarWidget.Calendar(root4, data)
root4.mainloop()
return app

Everything local to the function manageCalendarWindow() is garbage collected when the function exits. This includes app (the class instance). You would have to return it to keep it alive. Note also that there is no self.month in the code you posted but I assume that comes from cutting the amount of code back for this post.
def manageCalendarWindow():
root4 = Tk()
data = {}
app = calendarWidget.Calendar(root4, data)
root4.mainloop()
return app
## or
## return app.day_name
app=manageCalendarWindow()
print(app.day_name)
## or
##day_name=manageCalendarWindow()
##print(day_name)

A simple proof-of concept program that gets a variable from a class instantiated within the class.
class SubClass():
def __init__(self):
self.variable="SubClass variable"
class MainClass():
def __init__(self):
app=self.instantiate_class()
print(app.variable) ## prints the string
def instantiate_class(self):
app=SubClass()
print("app =", app) ## not empty
return app
MainClass()

As mentioned in my comments, there can be only one mainloop in the code. The others will be simply ignored. So it's not possible to use it to wait for a response from a child window.
The solution I used is
app = myCalendar.Calendar(personal_path, root4, gui_language)
root4.wait_window(app.parent)
return app
The code opens the window and waits the result using wait_window().
Thanks all.
Ciao.

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 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)

Button binding in Kivy Python

I am wondering how to get my code to work. I have a class wich creates a popup window with buttons. Each button should be bound to subclass. But it doesnt work. What´s wrong with my code?
class chooser:
def __init__(self):
None
def show(self,title,options=["NOTHING"],size=(.5,.5)):
self.bts = {}
self.response = False
self.content = FloatLayout()
self.content.pos_hint = {"y":0,"x":0}
# create buttons
pos_cntr = 0
for opt in options:
self.bts[pos_cntr] = Button(text=opt)
self.bts[pos_cntr].size_hint = 1,float(1)/float(len(options))
self.bts[pos_cntr].pos_hint = {"x":0,"y":pos_cntr}
self.bts[pos_cntr].bind(on_press=self.canceldia)
self.content.add_widget(self.bts[pos_cntr])
print "bound"
pos_cntr += float(1)/float(len(options))
self.pop = Popup(title=title,content=self.content,auto_dismiss=False)
self.pop.size_hint = size
self.pop.open()
def canceldia(self,instance):
print "closing"
self.response = instance.text
self.pop.dismiss()
def getresponse(self):
return self.response
I have imported all needed modules.
I execute it so:
c = chooser()
c.show("hello","world",["welcome","close","nothing","example"])
I have create a root widget. The popup works fine and all is created nice but the buttons are not bound. Please help me!
In your loop, you always reference self.bts[pos_cntr], so you override it in every iteration. How about this?
for idx, opt in enumerate(options):
self.bts[idx] = Button(text=opt)
self.bts[idx].size_hint = 1,float(1)/float(len(options))
self.bts[idx].pos_hint = {"x":0,"y":pos_cntr}
self.bts[idx].bind(on_press=self.canceldia)
self.content.add_widget(self.bts[idx])

How to kill the sleeping thread and the main process instantly?

I've wrote an little app to scroll an stock market ticker into a Tkinter window and update the stock values every minute using a threading class.
If I closed the window the main process didn't stops, then I've implemented a method to close the window and stop the thread. But when I close the window the main process delay the stopping to the next call to the theading.run() method.
How can I get that an instant closing process?
The code:
# -*- coding: UTF-8 -*-
import tkinter as tk
import tkinter.messagebox
import time
import threading
from random import randint as randint, uniform as randlimit
# Here starts the program working process, until here was the GUI
# CONSTANTS
CHAR_UP = "\u25B2"
CHAR_DOWN = "\u25BC"
CHAR_EVEN = "="
UPDATE_TIME = 60
# INITIAL DATA, this must be changed to implement the load of a external source
stock_market = [["GOOG", "587.25", CHAR_UP, "(+12.14)"],
["AAPL", "237.14", CHAR_UP, "(+7.25)"],
["GTAT", "87.47", CHAR_DOWN, "(-1.18)"],
["KNDI", "167.32", CHAR_UP, "(+6.85)"],
["ORCL", "482.91", CHAR_DOWN, "(-24.65)"],
["FBOK", "327.67", CHAR_DOWN, "(-11.78)"],
["TWTR", "842.41", CHAR_UP, "(+15.45)"]]
class AplicationTkinter(tk.Frame):
"""
Class of tkinter.Frame subclass, Initializes the GUI
constants:
SPEED, the delay in millisecs of the scroll
attributes:
parent, the root Tk object
"""
SPEED = 250
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self._initGUI()
self._scroll_ticker()
self.parent.protocol("WM_DELETE_WINDOW",self.stop)
# or toplevel.protocol(...
def _initGUI(self):
"""
initGUI, draws the layout.
"""
# changes the window icon
self.parent.iconbitmap("tabla.ico")
self.parent.title("Stock Exchange Ticker")
# fix a status bar at the bottom of the window, for future improvements
self.status_bar = tk.Label(self.parent, text="", bd=1, relief=tk.SUNKEN,
anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
# content Frame for entry, for future improvements
self.frame = tk.Frame(self.parent)
self.frame.pack()
self.var_entry = tk.StringVar()
self.entry = tk.Entry(self.frame, textvariable=self.var_entry)
self.entry.pack()
self.var_entry.set("a default value")
str_ent_1 = self.entry.get()
# content LabelFrame to show the ticker scrolling line of text
self.label_frame = tk.LabelFrame(self.parent,
text="Ventana de Resultados")
self.label_frame.pack()
# creates an instance of the StockMarket class for contents the data
self.market_one = StockMarket(stock_market)
# the scrolling line of Text for show the data
self.txt_ticker_widget = tk.Text(self.label_frame, background='black',
height=1, width=56, wrap="none")
self.txt_ticker_widget.pack(side=tk.TOP, fill=tk.X)
self.txt_ticker_widget.tag_configure("up", foreground="green")
self.txt_ticker_widget.tag_configure("down", foreground="red")
self.txt_ticker_widget.tag_configure("even", foreground="white")
self.tag = {CHAR_DOWN: "down", CHAR_EVEN: "even", CHAR_UP: "up"}
def _scroll_ticker(self):
"""
scroll_ticker, inserts character by character in the Text widget
"""
self.txt_ticker_widget.configure(state=tk.NORMAL)
self.txt_ticker_widget.insert(tk.END,
self.market_one.get_next_character(),
self.tag[self.market_one.get_tag()])
# TODO simplify
self.txt_ticker_widget.see(tk.END)
self.txt_ticker_widget.configure(state=tk.DISABLED)
self.txt_ticker_widget.after(self.SPEED, self._scroll_ticker)
# recursive each interval of millisecs, constant SPEED
def stop(self):
if tk.messagebox.askokcancel("Quit?", "Are you sure you want to quit?"):
# self.destroy()
print("STOPPING !!")
self.market_one.thread_updating.stop()
self.destroy()
self.parent.quit()
class StockTicker():
"""
Class StockTicker, handle each stock symbol and their data
attributes:
symbol, string, the abbreviature of the securitie
price, string, the current price of the securitie
direction, string(1), is a character that indicates its las fix price
went up, down or even
change, string, is the value of the last change surrounded by '()',
the first character is '+' or '-'
"""
def __init__(self, list_data):
self.symbol, self.price, self.direction, self.change = list_data
def update_ticker(self):
"""
update_ticker, update the securitie price, direction and
change with random values
"""
flt_price = float(self.price)
if randint(0, 9) == 0:
self.direction = CHAR_EVEN
else:
increase_percent = randlimit(-5, 5)
# TODO implementar normalvariate(0, 0.02) o gauss(0, 0.02)
flt_change = flt_price * increase_percent / 100
flt_new_price = flt_price + flt_change
self.price = "{:.2f}".format(flt_new_price)
if flt_change < 0:
self.direction = CHAR_DOWN
elif flt_change == 0:
self.direction = CHAR_EVEN
else:
self.direction = CHAR_UP
self.change = "({:+.2f})".format(flt_change)
def ticker_to_text(self):
"""
ticker_to_text, returns a formatted string with all the data of
the securitie.
"""
return " | {} {} {} {} ".format(self.symbol, self.price,
self.direction, self.change)
class StockMarket():
"""
Class StockMarket, creates and handle a list of StockTicker objects,
and provide to the GUI of stuff for the scroll ticker
attributes:
smarket, list of StockTicker objects
thread_actualizar, Thread object to update the stock market
each time interval
"""
def __init__(self, l_inicial):
self.tickers = []
self.index = 0
self._load(l_inicial)
self.current_ticker = self._get_one_ticker()
self.thread_updating = UpdateThread(self)
self.thread_updating.start()
def _load(self, l_inicial):
"""
load_market, load the list with StockTicker object taking the data from
the initial source data.
"""
for data_ticker in l_inicial:
simple_ticker = StockTicker(data_ticker)
self.tickers.append(simple_ticker)
def update_market(self):
"""
update_market, update the objects of the list
"""
for ticker in self.tickers:
ticker.update_ticker()
def _get_one_ticker(self):
"""
get_one_ticker, getter function to return one securitie data in text
format and rotates to the next one
"""
self.one_ticker = self.tickers.pop(0)
self.tickers.append(self.one_ticker)
self.index = 0
return self.one_ticker.ticker_to_text()
def get_next_character(self):
"""
get_next_character, returns a character of one securitie
(if the securitie data is exhausted retrieve another securitie)
data to the GUI.
"""
if self.index == len(self.current_ticker):
self.current_ticker = self._get_one_ticker()
self.index = 0
character_symbol = self.current_ticker[self.index:self.index+1]
self.index += 1
return character_symbol
def get_tag(self):
return self.one_ticker.direction
class UpdateThread(threading.Thread):
"""
Class UpdateThread(), subclass of Thread, handle the time to the next
update of the stock market values
args:
market_1, a StockMarket class object to update
attributes:
my_check, string for debugging purpouses, it'll be implemented the
source data management the_market, StockMarket object that will
be updated
"""
def __init__(self, market_1):
self.my_check = " CHECK " # TODO replace with initial source data.
self.the_market = market_1
self.is_quit = False
threading.Thread.__init__(self)
def run(self):
"""
run, overrides the Thread run method, and calls the update_market
method of StockMarket class each interval
"""
time.sleep(UPDATE_TIME)
self.the_market.update_market()
print(" UPDATED!!!") # for debugging
if not self.is_quit:
self.run()
def stop(self):
"""
stop, for stopping the thread when event occurs
"""
self.is_quit = True
# STARTS THE PROGRAM
def main():
the_window = tk.Tk()
aplication = AplicationTkinter(the_window)
# init the GUI process
the_window.mainloop()
if __name__ == '__main__':
main()

NSMenuItem + Python + Dynamic Variables

I'm trying to get a dynamic label for a menu item in this. I've written the entire app in Python but honestly with how much NSMenuItem looks, I might as well rewrite it in Objc...
import objc
from Foundation import *
from AppKit import *
from PyObjCTools import AppHelper
class MyApp(NSApplication):
def finishLaunching(self):
# Make statusbar item
statusbar = NSStatusBar.systemStatusBar()
self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength)
self.icon = NSImage.alloc().initByReferencingFile_('icon.png')
self.icon.setScalesWhenResized_(True)
self.icon.setSize_((20, 20))
self.statusitem.setImage_(self.icon)
#make the menu
self.menubarMenu = NSMenu.alloc().init()
self.menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Click Me', 'clicked:', '')
self.menubarMenu.addItem_(self.menuItem)
self.quit = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Quit', 'terminate:', '')
self.menubarMenu.addItem_(self.quit)
#add menu to statusitem
self.statusitem.setMenu_(self.menubarMenu)
self.statusitem.setToolTip_('My App')
def clicked_(self, notification):
NSLog('clicked!')
if __name__ == "__main__":
app = MyApp.sharedApplication()
AppHelper.runEventLoop()
Did you try setTitle_?
def clicked_(self, notification):
self.menuItem.setTitle_("Clicked!")
or with a timer:
def finishLaunching(self):
# ...
self.timer = NSTimer.alloc().initWithFireDate_interval_target_selector_userInfo_repeats_(NSDate.date(), 1.0, self, 'tick:', None, True)
NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer, NSDefaultRunLoopMode)
self.timer.fire()
def tick_(self, arg):
self.menuItem.setTitle_("Tick %d!" % int(time.time()))
For live updates you probably need JGMenuWindow (SO: How to update NSMenu while it's open?)

Categories