pystray on MacOS to use run_detached, program crashed - macos

I am trying to use pystray to create a icon on tasktray, it is working on windows but now I am building one for Mac. I need the program minimize to tasktray on run on background. so I need to use icon.run_detached() instead of icon.run().
However, it keep crashing the app and I read the documents seems that I need to give some darwin_nsapplication = AppKit.NSApplication.sharedApplication() to the code but I really don't know how to implement this. here is my code.
import tkinter as tk
import time
import pystray
from tkinter import *
from tkinter import messagebox
from PIL import Image
import AppKit
`class Gui():
def __init__(self):
self.window = tk.Tk()
self.darwin_nsapplication = AppKit.NSApplication.sharedApplication()
self.image = Image.open("./images/noname.png")
self.menu = (
pystray.MenuItem('Show', self.show_window),
pystray.MenuItem('Quit', self.quit_window)
)
# Declaration of variables
self.hour=StringVar()
self.minute=StringVar()
self.second=StringVar()
# setting the default value as 0
self.hour.set("00")
self.minute.set("00")
self.second.set("00")
# Use of Entry class to take input from the user
hourEntry= Entry(self.window, width=3, font=("Arial",18,""),
textvariable=self.hour)
hourEntry.place(x=80,y=20)
minuteEntry= Entry(self.window, width=3, font=("Arial",18,""),
textvariable=self.minute)
minuteEntry.place(x=130,y=20)
secondEntry= Entry(self.window, width=3, font=("Arial",18,""),
textvariable=self.second)
secondEntry.place(x=180,y=20)
# button widget
btn = Button(self.window, text='Set Time Countdown', bd='5',
command= self.submit)
btn.place(x = 70,y = 120)
def submit(self):
try:
# the input provided by the user is
# stored in here :temp
temp = int(self.hour.get())*3600 + int(self.minute.get())*60 + int(self.second.get())
except:
print("Please input the right value")
while temp >-1:
# divmod(firstvalue = temp//60, secondvalue = temp%60)
mins,secs = divmod(temp,60)
# Converting the input entered in mins or secs to hours,
# mins ,secs(input = 110 min --> 120*60 = 6600 => 1hr :
# 50min: 0sec)
hours=0
if mins >60:
# divmod(firstvalue = temp//60, secondvalue
# = temp%60)
hours, mins = divmod(mins, 60)
# using format () method to store the value up to
# two decimal places
self.hour.set("{0:2d}".format(hours))
self.minute.set("{0:2d}".format(mins))
self.second.set("{0:2d}".format(secs))
# updating the GUI window after decrementing the
# temp value every time
self.window.update()
time.sleep(1)
# when temp value = 0; then a messagebox pop's up
# with a message:"Time's up"
if (temp == 0):
messagebox.showinfo("Time Countdown", "Time's up ")
# after every one sec the value of temp will be decremented
# by one
temp -= 1
def quit_window(self):
self.icon.stop()
self.window.destroy()
def show_window(self):
self.icon.stop()
self.window.protocol('WM_DELETE_WINDOW', self.withdraw_window)
self.window.after(0, self.window.deiconify)
def withdraw_window(self):
self.window.withdraw()
self.icon = pystray.Icon("name", self.image, "title", self.menu)
self.icon.run_detached()
if __name__ in '__main__':
app = Gui()
app.window.protocol('WM_DELETE_WINDOW', app.withdraw_window)
app.window.mainloop()`
I tried to add darwin_nsapplication to icon like self.icon = pystray.Icon("name", self.image, "title", self.menu,self.darwin_nsapplication)
But it is said 6 arguments are given, 2-5 are needed.

Related

How to get all installed font path?

How to get all installed font path with pywin32?
I can only find a way with registry key, but I would prefer to directly use GDI or DirectWrite.
Edit:
I am not sure, but from what I can see, here is how it would maybe be possible with GDI:
Create Factory: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-dwritecreatefactory
GetSystemFontCollection: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefactory-getsystemfontcollection
Do a for loop with GetFontFamilyCount: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontcollection-getfontfamilycount
GetFontFamily: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontcollection-getfontfamily
GetMatchingFonts (the param weight, stretch, style can be anything. These param seems to only change the order or the return list): https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontfamily-getmatchingfonts
Do a for loop with GetFontCount:https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontlist-getfontcount
GetFont: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontlist-getfont
CreateFontFace: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefont-createfontface
GetFiles: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontface-getfiles
GetReferenceKey: https://learn.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritefontfile-getreferencekey
Again DWriteCreateFactory but with uuidof IDWriteLocalFontFileLoader
GetFilePathFromKey: https://learn.microsoft.com/en-us/windows/win32/directwrite/idwritelocalfontfileloader-getfilepathfromkey
I found an solution.
I used DirectWrite API.
This code depends on pyglet librairy.
import sys
import time
from ctypes import byref, c_uint32, create_unicode_buffer
from pyglet.font.directwrite import (
DWriteCreateFactory,
DWRITE_FACTORY_TYPE_ISOLATED,
IDWriteFactory,
IDWriteFont,
IDWriteFontCollection,
IDWriteFontFace,
IDWriteFontFamily,
IDWriteFontFile,
IDWriteFontFileLoader,
IDWriteLocalFontFileLoader,
IID_IDWriteFactory,
IID_IDWriteLocalFontFileLoader,
)
from pyglet.libs.win32.types import c_void_p
from typing import List
def get_fonts_filepath() -> List[str]:
"""
Return an list of all the font installed.
"""
write_factory = IDWriteFactory()
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_ISOLATED, IID_IDWriteFactory, byref(write_factory)
)
fonts_path = set()
sys_collection = IDWriteFontCollection()
write_factory.GetSystemFontCollection(byref(sys_collection), 0)
collection_count = sys_collection.GetFontFamilyCount()
for i in range(collection_count):
family = IDWriteFontFamily()
sys_collection.GetFontFamily(i, byref(family))
font_count = family.GetFontCount()
for j in range(font_count):
font = IDWriteFont()
family.GetFont(j, byref(font))
font_face = IDWriteFontFace()
font.CreateFontFace(byref(font_face))
file_ct = c_uint32()
font_face.GetFiles(byref(file_ct), None)
font_files = (IDWriteFontFile * file_ct.value)()
font_face.GetFiles(byref(file_ct), font_files)
pff = font_files[0]
key_data = c_void_p()
ff_key_size = c_uint32()
pff.GetReferenceKey(byref(key_data), byref(ff_key_size))
loader = IDWriteFontFileLoader()
pff.GetLoader(byref(loader))
try:
local_loader = IDWriteLocalFontFileLoader()
loader.QueryInterface(
IID_IDWriteLocalFontFileLoader, byref(local_loader)
)
except OSError: # E_NOTIMPL
font.Release()
font_face.Release()
loader.Release()
pff.Release()
continue
path_len = c_uint32()
local_loader.GetFilePathLengthFromKey(
key_data, ff_key_size, byref(path_len)
)
buffer = create_unicode_buffer(path_len.value + 1)
local_loader.GetFilePathFromKey(key_data, ff_key_size, buffer, len(buffer))
font.Release()
font_face.Release()
loader.Release()
local_loader.Release()
pff.Release()
fonts_path.add(buffer.value)
family.Release()
sys_collection.Release()
write_factory.Release()
return list(fonts_path)
def main():
start = time.time()
fonts_path_dwrite = get_fonts_filepath()
print(time.time() - start)
print(fonts_path_dwrite)
if __name__ == "__main__":
sys.exit(main())

Automated Scheduling

When running the Function with no names on the input lists, it gives everyone the approtriate time based on the varible listed. If we have the input varibale have a name it gives everyone time off instead of just that indivudual.
There are some lists associated with this as well and that part works fine.
this is the required resources:
from openpyxl import Workbook
from datetime import timedelta, datetime
import random
def add_agents_w1():
num = 4
c = ["B","C","D","E","F"]
tow1 = input("IF anyone taking time off enter 1st
person now: \n")
tow12 = input("If someone else is taking time off enter
2nd person now: \n")
for x in tl:
ws1[f"A{num}"] = x
ws1[f"I{num}"] = x
for f in c:
if x in tow1 or tow12:
ws1[f'{f}{num}'] = "OFF"
else:
ws1[f"{f}{num}"] = s2t
num += 1
wb.save(dest_filename)

problem, backtesting with backtrader and btalib, It's not action as i tried, want to action as order buy if sma5>sma10 and sell when sma5<sma14

from btalib.indicators import sma
import pandas as pd
import backtrader as bt
import os.path #To manage paths
import sys # to find out the script name
import datetime
import matplotlib as plt
from backtrader import cerebro
from numpy import mod #for datetime object
df = pd.read_csv('C:/Users/User/Desktop/programming/dataset/coin_Bitcoin.csv',parse_dates=True, index_col='Date')
sma14 = btalib.sma(df, period = 14)
sma5 = btalib.sma(df, period=5)
class TestStrategy(bt.Strategy):
params = (
('exitbars', 5),
)
def log(self, txt, dt=None):
#Logging function fot this strategy
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
# To keep track of pending orders
self.order = None
self.buyprice = None
self.buycomm = None
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
return
if order.status in [order.Completed]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm: %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: #sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f'%
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Reject')
# Write down: no pending order
self.order = None
# Check if an order has been completed
# Attention: broker could reject order if not enough cash
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def next(self):
#sma = btalib.sma(df, period=30)
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
# Check if an order is pending ... if yes, we cannot send a 2nd one
if self.order:
return
# Check if we are in the market
#if not self.position:
# Not yet ... we MIGHT BUY if ...
if sma5[0] > sma14[0]:
# BUY, BUY, BUY!!! (with all possible default parameters)
self.log('BUY CREATE, %.2f' % self.dataclose[0])
# Keep track of the created order to avoid a 2nd order
self.order = self.buy()
else:
# Already in the market ... we might sell
if sma5[0] < sma14[0]:
# SELL, SELL, SELL!!! (with all possible default parameters)
self.log('S[enter image description here][1]ELL CREATE, %.2f' % self.dataclose[0])
self.order = self.sell()
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, 'C:/programming/AlgoTrading/backtest/BTC-USD-YF.csv')
data = bt.feeds.YahooFinanceCSVData(
dataname = datapath,
fromdate = datetime.datetime(2020,5,1),
todate = datetime.datetime(2021,6,1),
reverse = False)
#Add the Data Feed to Cerebro
cerebro.adddata(data)
cerebro.broker.setcash(100000.0)
# Add a FixedSize sizer according to the stake
#cerebro.addsizer(bt.sizers.FixedSize, stake=10)
cerebro.addsizer(bt.sizers.FixedSize)
# Set the commission
cerebro.broker.setcommission(commission=0.0)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Run over everything
cerebro.run()
#print(df(data))
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.plot()
I tried so hard to order buy when sma5>sma14 and sell at sma5<sma14 but it doesn't work
I use backtrader as backtesting library and use btalib for indicator o generate signal where "btalib.sma(df, period)"
cerebro function is what backtesting module
sometimes it's buy and sell everyday, buy today sell tomorrow
Probably you have to invert the order of your df, this was my problem when computing the RSI with btalib.
Example: df = df.iloc[::-1]

tk.Entry validate command doesn't restore previous value when False returned

I have carefully reviewed answers to Interactively validating Entry widget content in tkinter, but my script fails to restore previous value if the validate command returns False. I captured %P and %s and print them out...They both show the same value.
import tkinter as tk
class Controller :
def __init__(self) :
i=10
j=20
# list comprehension
self.entry_widgets = [[None for col in range(j)] for row in range(i)]
#print(self.entry_widgets)
self.values = [["string"+str(row) + str(col) for col in range(10)] for row in range(20)]
#print(self.values)
class EnterBox(tk.Entry):
def __init__(self,*args,**kwargs):
#print (args)
self._modified = False
self._save = 0
self._raise = 1
self._lower = 2
frame, i,j, *newargs = args
self._content = tk.StringVar()
# tk.Entry.__init__(self,frame,*newargs,
# validate = 'focusout',
# validatecommand = vcmd,
# **kwargs)
tk.Entry.__init__(self,frame,*newargs,**kwargs)
vcmd = (self.register(self._revert), '%P', '%s')
ct.entry_widgets[i][j] = self
self.config(textvariable=self._content)
self.config(validate = "focusout")
self.config(validatecommand = vcmd )
x=(ct.values[i][j])
self.insert(0,x)
#self._content.set(x)
self.bind("<Return>",lambda event, x=self._save : self._action(event,x) )
self.bind("<Button-2>",lambda event, x=self._save : self._action(event,x) )
self.bind("<FocusIn>", lambda event, x=self._raise : self._action(event,x))
self.bind("<FocusOut>", lambda event, x=self._lower : self._action(event,x))
self.bind('<Button-3>', lambda event, x=self._lower : self._action(event,x))
self.grid(column=i+1,row=j+2)
def _revert(self,P,s):
print ("Hi There")
print(P)
print(s)
return False
def _action(self,event,action):
print(str(action)+' ' + str(event))
if action == self._save :
ct.values[i][j] = self._content.get()
self.config(bg='lightskyblue2')
self._modified = True
elif action == self._raise :
self.config(bg = 'light pink')
elif action == self._lower :
self.config(bg = 'gray80')
self._modified = False
else :
print('action value is bad action =>' + str(action))
if "__main__" == __name__ :
root = tk.Tk()
frame = tk.Frame()
i=j=0
ct = Controller()
root.grid()
frame.grid()
check = EnterBox(frame,i,j,width = 24)
check2 = EnterBox(frame,i+1,j,width = 24)
root.mainloop()
I have tried removing all other bindings, to no avail.
Interestingly, but a separate issue, If I use StringVar. set instead of self.insert, (see commented out line) the validate command runs once, and never again despite several focus changes. Using Python 3.8
The validation isn't designed to restore anything if the validation happens on focusout. The validation can only prevent characters from being added at the time they are added. You will have to add code to restore the previous value.

Best program for keeping track of Time (motor racing)

Short Version:
Program to:
control racing (cars) laptimes (it must not reset)
be able to use as a chronometer
b able to use as a reverse chronometer (start in X min:secs end in 00:00)
Long Version:
I need a program to control time, I need the time to go forth and back (for me to choose)
and I insert the starting time.
I also need a program to control lap times.
If anyone know any program for these stuff (racing stuff), I would apreciate it, even if there only are paid solution, I still would like to take a look at them (I staring to make a program in python and it could be good for inspiration)
After some search, I could only find this:
It's a simple clock in python TKinter..... if anyone has anything more advanced... (easier to change :) )
from Tkinter import *
import time
from Tkinter import *
import time
class StopWatch(Frame):
""" Implements a stop watch frame widget. """
def __init__(self, parent=None, **kw):
Frame.__init__(self, parent, kw)
self._start = 0.0
self._elapsedtime = 0.0
self._running = 0
self.timestr = StringVar()
self.makeWidgets()
def makeWidgets(self):
""" Make the time label. """
l = Label(self, textvariable=self.timestr)
self._setTime(self._elapsedtime)
l.pack(fill=X, expand=NO, pady=2, padx=2)
def _update(self):
""" Update the label with elapsed time. """
self._elapsedtime = time.time() - self._start
self._setTime(self._elapsedtime)
self._timer = self.after(50, self._update)
def _setTime(self, elap):
""" Set the time string to Minutes:Seconds:Hundreths """
minutes = int(elap/60)
seconds = int(elap - minutes*60.0)
hseconds = int((elap - minutes*60.0 - seconds)*100)
self.timestr.set('%02d:%02d:%02d' % (minutes, seconds, hseconds))
def Start(self):
""" Start the stopwatch, ignore if running. """
if not self._running:
self._start = time.time() - self._elapsedtime
self._update()
self._running = 1
def Stop(self):
""" Stop the stopwatch, ignore if stopped. """
if self._running:
self.after_cancel(self._timer)
self._elapsedtime = time.time() - self._start
self._setTime(self._elapsedtime)
self._running = 0
def Reset(self):
""" Reset the stopwatch. """
self._start = time.time()
self._elapsedtime = 0.0
self._setTime(self._elapsedtime)
def main():
root = Tk()
sw = StopWatch(root)
sw.pack(side=TOP)
Button(root, text='Start', command=sw.Start).pack(side=LEFT)
Button(root, text='Stop', command=sw.Stop).pack(side=LEFT)
Button(root, text='Reset', command=sw.Reset).pack(side=LEFT)
Button(root, text='Quit', command=root.quit).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()
If you want to go with a packaged solution, you should try some of the apps:
for your android phone: http://www.bestandroidappsreview.com/2010/05/top-android-app-ultimate-stopwatch.html
for your iphone: http://www.apple.com/webapps/utilities/stopwatch_benku.html which is free, but if you want a more powerful stopwatch you should try LAPZERO app (see demo http://www.lapzero.com/v4/)
for your windows mobile phone: http://www.ageye.de/index.php?s=grace/about
or find one for your desktop computer platform/system on google
So what you want is a milliseconds accurate stop watch and lap timer.
Not that I have tried it but heres one I found on google http://www.xnotestopwatch.com/
I wish I could vote, cause that import tardis crack was a good one. :P

Resources