Python
Python is heavily used in MH Software & Services products. The library is abundant, easy to manage, and does not require compilation, so you can program on your smartphone. The website is also written in Python. The Python version is 3.8.6 as of October 25, 2020.
GUI There are many GUI environments that can be used with Python, but I make heavy use of tkinter, which is installed by default.
test_form.py This is a sample that uses the Form class of MH Software & Services. A 320x160 window will appear at position (100,50). test_form.py (compressed with ZIP)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from form import Form
class Root(Form):
def __init__(self):
super().__init__(
#dialog=True,
border=0,
relief=None,
#icon=icon_file,
#minsize=minimum_size,
name='main',
position=['320', '160', '100', '50'],
title='title')
def main():
root = Root()
root.mainloop()
if __name__ == '__main__':
main()
It's a window like this.
form.py Form class when using tkinter with MH Software & Services. It incorporates common functions such as mouse events and preparation of UDP transmission / reception function. Also put udp.py in the same folder. form.py (compressed with ZIP)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import threading
import tkinter as tk
from tkinter import ttk
if __name__ == '__main__':
from udp import UDP
else:
from .udp import UDP
class Form(tk.Tk):
def __init__(self, *args, **kwargs):
"""
Argument:
dialog=<class 'bool'>
icon=full_path
hasmenu=True or False: Change height.
master=object
minsize=(width, height)
name=<class "str">
position=[width, height, left, top]
title=<class "str">
topmost=False
udp_port=4000
udp_bufsize=4096
"""
if kwargs.get('toplevel', False):
# Use for dialog new window.
tk.Toplevel.__init__(self)
self.resizable(0, 0)
self.grab_set()
# Focus to me.
self.focus_set()
# Not show taskbar.
self.transient(self.master)
else:
super().__init__(
#border=0,
#relief=None,
)
if len(kwargs.get('minsize', ())) == 2:
self.minsize(
kwargs.get('minsize')[0],
kwargs.get('minsize')[1])
self.border_style = {'borderwidth': 0, 'relief': 'solid'}
self._scaling = self._get_dpi(self) / 72
self.tk.call('tk', 'scaling', self.scaling)
#self.tk.call('tk', 'scaling', 0.5)
# 96 is development PC's DPI. This value is default.
self._screen_ratio = 96 / self._get_dpi(self)
self.master = kwargs.get('master', None)
self.title(kwargs.get('title', ''))
self.name = kwargs.get('name', '')
self._hasmenu = kwargs.get('hasmenu', False)
if len(kwargs.get('position', [])) == 4:
width = int(kwargs.get('position')[0])
if self.minsize()[0] > width:
width = self.minsize()[0]
height = int(kwargs.get('position')[1])
if self.minsize()[1] > height:
height = self.minsize()[1]
x = kwargs.get('position')[2]
y = kwargs.get('position')[3]
self.position = [width, height, x, y]
if kwargs.get('icon', '') != '':
self.icon = kwargs.get('icon', '')
if kwargs.get('topmost', False):
self.grab_set()
if kwargs.get('dialog', False):
self.resizable(0,0)
self._attach_events()
if kwargs.get('udp_port', '') != '':
self.udp = UDP(self, *args, **kwargs)
self.udp.receive.trace('w', self.udp_receive_changed)
self.resize_event = True
@property
def host(self):
result = socket.gethostbyname_ex(socket.gethostname())
result = result[2][0]
return result
@property
def icon(self):
return self._icon
@icon.setter
def icon(self, value):
self._icon = value
self.tk.call('wm', 'iconphoto', self._w, tk.PhotoImage(file=self._icon))
@property
def position(self):
return [
self.winfo_width(),
self.winfo_height(),
self.winfo_x(),
self.winfo_y()]
@position.setter
def position(self, value):
"""
geometry=[width, height, left, top]
"""
if self._hasmenu:
value[1] += 20
self.geometry(f'{value[0]}x{value[1]}+{value[2]}+{value[3]}')
@property
def resize_event(self):
return self._resize_event
@resize_event.setter
def resize_event(self, value):
self._resize_event = value
if self._resize_event:
self.bind('<Configure>', self._on_resize)
else:
self.unbind('<Configure>')
@property
def scaling(self):
return self._scaling
@property
def screen_ratio(self):
return self._screen_ratio
def _attach_events(self):
self.protocol('WM_DELETE_WINDOW', self.on_exit)
self.bind('<Configure>', self._on_resize)
self.unbind('<Configure>')
self.bind('<MouseWheel>', self._mouse_wheel)
self.bind('<Motion>', self._mouse_move)
self.bind('<ButtonPress-1>', self._button1_press)
self.bind('<ButtonRelease-1>', self._button1_release)
self.bind('<ButtonPress-2>', self._button2_press)
self.bind('<ButtonRelease-2>', self._button2_release)
self.bind('<B2-Motion>', self._button2_move)
self.bind('<ButtonPress-3>', self._button3_press)
self.bind('<ButtonRelease-3>', self._button3_release)
self.bind('<Expose>', self._expose)
def _button1_press(self, *args):
pass
def _button1_release(self, *args):
pass
def _button2(self, *args):
pass
def _button2_move(self, event):
pass
def _button2_press(self, *args):
pass
def _button2_release(self, *args):
pass
def _button3(self, *args):
pass
def _button3_press(self, *args):
pass
def _button3_release(self, *args):
pass
def _expose(self, *args):
pass
def _get_dpi(self, window):
MM_TO_IN = 1/25.4
pxw = window.winfo_screenwidth()
inw = window.winfo_screenmmwidth() * MM_TO_IN
return int(pxw/inw)
def _mouse_move(self, *args):
pass
def _mouse_wheel(self, event):
sf = 1.0
if event.delta < 0:
sf = 0.9
else:
sf = 1.3
pass
def on_exit(self):
self.destroy()
def _on_resize(self, event):
"""
override from child.
This event is hook <"Configure">
If size is not changed, through the function.
"""
#if (self.geometry != self.geometry()):
# self.geometry = self.geometry()
self.on_resize(event)
def on_resize(self, event):
# override from child.
pass
def udp_receive_changed(self, *args):
"""
When UDP use, then override this function .
"""
pass
def main():
root = Form()
#root.wm_attributes("-transparentcolor", "white")
root.mainloop()
if __name__ == '__main__':
main()
udp.py This is a common class for UDP communication. Monitor communication with thread. udp.py (compressed with ZIP)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os
import socket
import threading
import tkinter as tk
class UDP():
def __call__(self):
return self.receive.get()
def __init__(self, master, *args, **kwargs):
self.binded = False
self.error_message_enable = kwargs.get('error_message_enable', True)
self.error = self.Error(self)
self._port_changing = False
self._port = int(kwargs.get('udp_port', '4000'))
self._bufsize = int(kwargs.get('udp_bufsize', '4096'))
self.receive = tk.StringVar(value='')
self._sock = None
self._start()
def __new__(cls, master, *args, **kwargs):
cls.master = master
if hasattr(cls.master, 'root'):
cls.root = cls.master.root
if hasattr(cls.root, 'ini'):
cls.ini = cls.root.ini
if hasattr(cls.master, "parent"):
cls.parent = cls.master.parent
return super().__new__(cls)
@property
def bufsize(self):
return self._bufsize
@bufsize.setter
def bufsize(self, value):
self._bufsize = value
class Error():
def __init__(self, master):
self.master = master
self.root = self.master.root
self.id = tk.IntVar(value=0)
self.id.trace('w', self._error_changed)
self.message = ''
self.title = ''
def _error_changed(self, *args):
if self.master.error_message_enable:
if self.id.get() > 0:
tk.messagebox.showwarning(self.title, self.message)
def _start(self):
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self._sock.settimeout(0.1)
self._socket_bind()
self.thread = threading.Thread(
name='udp{}{}'.format(self.port, self.binded),
target=self._thread,
)
self.thread.setDaemon(True)
self.thread.start()
def _socket_bind(self):
try:
# host is ''.
self._sock.bind(('', self.port))
except Exception as e:
if e.errno == 10048:
title = (
lambda:
'UDP port error'.format(self.port)
if lang() == 'ja_JP' else
'Failed UDP port'.format(self.port)
)()
msg = (
lambda:
'port{}Is used'.format(self.port)
if lang() == 'ja_JP' else
'Port {} was used.'.format(self.port)
)()
else:
title = (
lambda:
'Other errors'.format(self.port)
if lang() == 'ja_JP' else
'Other error'.format(self.port)
)()
msg = (
lambda:
'port{}Is used'.format(self.port)
if lang() == 'ja_JP' else
'Port {} was used.'.format(self.port)
)()
#tk.messagebox.showwarning(title, msg)
self.error.message = msg
self.error.title = title
self.error.id.set(1)
self.binded = False
else:
self.error.message = ''
self.error.title = ''
self.error.id.set(0)
self.binded = True
def _thread(self):
while True:
data, addr = None, None
while self.binded:
try:
if self._port_changing:
break
data, addr = self._sock.recvfrom(self._bufsize)
data = data.decode()
if (data is not None) & (addr is not None):
self.receive.set('{};{};{}'.format(
data, addr[0], addr[1]))
data, addr = None, None
except Exception as e:
#print(e)
pass
if self._port_changing:
self._sock.close()
del(self._sock)
self._sock = None
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self._sock.settimeout(0.1)
self._socket_bind()
self.thread.name = 'udp{}{}'.format(self.port, self.binded)
self._port_changing = False
def udp_reset(self):
if type(self._sock) == socket.socket:
self._sock.close()
del(self._sock)
self._sock = None
@property
def port(self):
return self._port
@port.setter
def port(self, value):
value = int(value)
if value != self._port:
self._port = value
self._port_changing = True
def lang():
"""
Sometime os don't has os.environ['LANG'].
This function can not be use...
"""
result = ""
if ('LANG' in os.environ):
result = os.environ.get('LANG')
result = result.split('.')
result = result[0]
if result != 'ja_JP':
result = 'other'
else:
result = 'other'
return result
YouTube: Thermal Camera (Thermo AI Device TiD) Python Edition web: Thermo AI Device TiD Python Form (URL is subject to change.)
Recommended Posts