Re: simple tkinter battery monitor
Thank you very much! fixed with w.after Here is the code, works under Linux for those who have acpi. My output of acpi -V is the following, the code is parsing the first line of the output. Any improvements are appreciated. $ acpi -V Battery 0: Discharging, 12%, 00:10:59 remaining Battery 0: design capacity 2200 mAh, last full capacity 1349 mAh = 61% Adapter 0: off-line Thermal 0: ok, 40.0 degrees C Thermal 0: trip point 0 switches to mode critical at temperature 98.0 degrees C Thermal 0: trip point 1 switches to mode passive at temperature 93.0 degrees C Cooling 0: Processor 0 of 10 Cooling 1: Processor 0 of 10 Cooling 2: Processor 0 of 10 Cooling 3: Processor 0 of 10 Cooling 4: LCD 0 of 9 -- -- -- #!/usr/bin/python3.2 from re import findall, search from threading import Thread from time import sleep from subprocess import Popen, call, PIPE, STDOUT from tkinter import Tk, Label, StringVar def runProcess(exe): p=Popen(exe, stdout=PIPE, stderr=STDOUT) while True: retcode=p.poll() line=p.stdout.readline() yield line if retcode is not None: break class BatteryMonitor: def __init__(self): root = Tk() root.configure(padx=1, pady=1, bg=#555753) root.geometry(-0+0) root.overrideredirect(True) root.wm_attributes(-topmost, True) self.batteryExtendedStringVar = StringVar() self.batteryPercentStringVar = StringVar() self.batteryExtendedLabel = Label(root, textvariable=self.batteryExtendedStringVar, font=(fixed, 9), bg=#3e4446, fg=#d3d7cf, padx=10, pady=-1) self.batteryPercentLabel = Label(root, textvariable=self.batteryPercentStringVar, font=(fixed, 9), width=4, bg=#3e4446, fg=#d3d7cf, padx=-1, pady=-1) self.batteryPercentLabel.grid() t = Thread(target=self.update_battery_level_loop) t.start() root.bind(Button-1, self.display_details) self.root = root root.mainloop() def display_details(self, event): # displays a message about details of battery status # i.e. on-line or charging, 20 min left and so on self.batteryPercentLabel.grid_remove() self.batteryExtendedLabel.grid() self.batteryExtendedLabel.after(1000, self.batteryExtendedLabel.grid_remove) self.batteryPercentLabel.after(1000, self.batteryPercentLabel.grid) def read_battery_level(self): # dummy function used just to test the GUI for line in runProcess([acpi, -V]): if line[11:-1]!=bon-line: self.level = findall(b\d\d?, line[11:])[0] else: self.level = b0 return line[11:-1] def update_battery_level_loop(self): # threaded function, should constantly update the battery level self.read_battery_level() while True: self.batteryPercentStringVar.set(str(self.level)[2:-1]+%) self.batteryExtendedStringVar.set(self.read_battery_level()) if self.level == 2: runProcess([shutdown, -h, now]) return sleep(5) ## # # main BatteryMonitor() -- http://mail.python.org/mailman/listinfo/python-list
simple tkinter battery monitor
I tried to write a simple battery monitor for laptops which shows normally just the battery percentage, and when is clicked some more info. If I click just one time it works, but if I click a second time, the additional info Label seems to be empty (but it holds the dimension of the StringVar content, even if it isn't displayed) Where am I wrong? --- #!/usr/bin/python3.2 from re import findall, search from threading import Thread from time import sleep from subprocess import Popen, call, PIPE, STDOUT from tkinter import * class battery_monitor: def __init__(self): root=Tk() #root.geometry(-0+0) root.overrideredirect(True) root.wm_attributes(-topmost, 1) self.battery_string=StringVar() self.battery_percent=StringVar() self.battery_label=Label(root, extvariable=self.battery_string, font=(fixed, 9)) self.battery_icon=Label(root, textvariable=self.battery_percent, font=(fixed, 9), width=3) self.battery_icon.grid() t=Thread(target=self.update_battery_level_loop) t.start() root.bind(Button-1, self.display_details) self.root=root root.mainloop() # displays a message about details of battery status # i.e. on-line or charging, 20 min left and so on def display_details(self, event): self.battery_icon.grid_remove() self.battery_label.grid() self.root.update_idletasks() sleep(1) self.battery_label.grid_remove() self.battery_icon.grid() self.root.update_idletasks() # dummy function used just to test the GUI def read_battery_level(self): self.level=100 return battery is full # threaded function, should constantly update the battery level def update_battery_level_loop(self): self.read_battery_level() while True: self.battery_percent.set(self.level) self.battery_string.set(self.read_battery_level()) sleep(5) ## # # main battery_monitor() -- http://mail.python.org/mailman/listinfo/python-list
Re: simple tkinter battery monitor
On 01/27/2013 05:59 PM, leonix.po...@gmail.com wrote: I tried to write a simple battery monitor for laptops which shows normally just the battery percentage, and when is clicked some more info. If I click just one time it works, but if I click a second time, the additional info Label seems to be empty (but it holds the dimension of the StringVar content, even if it isn't displayed) Where am I wrong? See inline comment. --- #!/usr/bin/python3.2 from re import findall, search from threading import Thread from time import sleep from subprocess import Popen, call, PIPE, STDOUT from tkinter import * class battery_monitor: def __init__(self): root=Tk() #root.geometry(-0+0) root.overrideredirect(True) root.wm_attributes(-topmost, 1) self.battery_string=StringVar() self.battery_percent=StringVar() self.battery_label=Label(root, extvariable=self.battery_string, font=(fixed, 9)) I don't know tkinter very well, and I don't have 3.2, but the keyword seems to be wrong. Don't you want textvariable= ?? self.battery_icon=Label(root, textvariable=self.battery_percent, font=(fixed, 9), width=3) self.battery_icon.grid() t=Thread(target=self.update_battery_level_loop) t.start() root.bind(Button-1, self.display_details) self.root=root root.mainloop() # displays a message about details of battery status # i.e. on-line or charging, 20 min left and so on def display_details(self, event): self.battery_icon.grid_remove() self.battery_label.grid() self.root.update_idletasks() sleep(1) Never use sleep() inside a gui's main thread. There are other ways to delay the UI without locking it up. self.battery_label.grid_remove() self.battery_icon.grid() self.root.update_idletasks() # dummy function used just to test the GUI def read_battery_level(self): self.level=100 return battery is full # threaded function, should constantly update the battery level def update_battery_level_loop(self): self.read_battery_level() while True: self.battery_percent.set(self.level) self.battery_string.set(self.read_battery_level()) sleep(5) This sleep() is okay. ## # # main battery_monitor() -- DaveA -- http://mail.python.org/mailman/listinfo/python-list
Re: simple tkinter battery monitor
On Sunday, January 27, 2013 4:59:20 PM UTC-6, leonix...@gmail.com wrote: I tried to write a simple battery monitor for laptops which shows normally just the battery percentage, and when is clicked some more info. If I click just one time it works, but if I click a second time, the additional info Label seems to be empty (but it holds the dimension of the StringVar content, even if it isn't displayed) Where am I wrong? Before i discover your code logic error, i want to expose style errors. --- #!/usr/bin/python3.2 from re import findall, search from threading import Thread from time import sleep from subprocess import Popen, call, PIPE, STDOUT from tkinter import * I am wondering why you would selectively import from the re module, which is a quite normal sized module, but then do the global import from tkinter, of which who's namespace is terribly polluted due to lack of packaging. class battery_monitor: Bad naming convention here! ALL class identifiers must (at the very least) /start/ with a capital letter. My strong opinion is to cap EVERY word. So for example: OptionMenu NOT Optionmenu ComboBox NOT Combobox etc... Using lowercase_with_underscores should be reserved for interface methods and global functions. def __init__(self): root=Tk() #root.geometry(-0+0) root.overrideredirect(True) root.wm_attributes(-topmost, 1) I just hate when people use 1 and 0 for True and False. I know Python allows such non-sense, but i just hate it because it can cause subtle bugs -- and most logical people agree with me. self.battery_string=StringVar() self.battery_percent=StringVar() Two issues here. First you use a function/interface style to define a variable. Then you go and add insult to injury by using an ambiguous name. You should have used something like: batteryStringVar and batteryPercentVar. self.battery_label=Label(root, extvariable=self.battery_string, font=(fixed, 9)) self.battery_icon=Label(root, textvariable=self.battery_percent, font=(fixed, 9), width=3) self.battery_icon.grid() t=Thread(target=self.update_battery_level_loop) Don't assign variables without leaving buffer spaces around the equals sign. Only omit the spaces when passing arguments to a class, method, or function. t.start() root.bind(Button-1, self.display_details) self.root=root root.mainloop() # displays a message about details of battery status # i.e. on-line or charging, 20 min left and so on Oh gawd this is a major pet peeve of mine Always place a comment at the same indention level of the function or class that it references. AND NEVER, EVER, place a comment OUTSIDE of a function, method, or class like you have done here. def display_details(self, event): self.battery_icon.grid_remove() self.battery_label.grid() self.root.update_idletasks() sleep(1) You may want to look into the Universal Tkinter widget method: w.after(ms, func). self.battery_label.grid_remove() self.battery_icon.grid() self.root.update_idletasks() # dummy function used just to test the GUI def read_battery_level(self): self.level=100 return battery is full # threaded function, should constantly update the battery level def update_battery_level_loop(self): self.read_battery_level() while True: self.battery_percent.set(self.level) self.battery_string.set(self.read_battery_level()) sleep(5) Finally, i don't understand why you are using such a deep indention level. Unknown Source said: Four spaces thou shalt indent, and the number of thou indention shall be four. Only after you clean up these style abominations by submitting a new example of your code will i offer any more help. Thanks. -- http://mail.python.org/mailman/listinfo/python-list