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