Python Forum
[Tkinter] Anyone know what happened to my button?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Anyone know what happened to my button?
#14
I have made it so that there is a variable to set the number of voltage panels NUMBER_OF_VOLTAGE_PANELS it uses this to automatically alter the GUI to have the right amount of widgets to display the data, it defaults to having at least 1 so the code won't break.

In the App update method you will need to alter the following lines to set the actual data from the xbee.
self.data.set_date('30/05/2021')
self.data.set_time('12:00')
self.data.set_voltages((0.12, 3.8, 1.3))
self.data.set_voltages takes a tuple of length to match the NUMBER_OF_VOLTAGE_PANELS
import dataclasses
import functools
import statistics
import tkinter as tk
from concurrent import futures

from digi.xbee.devices import XBeeDevice

PORT = "COM5"
BAUD_RATE = 9600
device = XBeeDevice(PORT, BAUD_RATE)

NUMBER_OF_VOLTAGE_PANELS = 3
DATE = 'Fecha de mediciĆ³n'
TIME = 'Hora de mediciĆ³n'
VOLTAGE = 'Voltage de Panel'
AVERAGE = 'Promedio'
LOWEST = 'Panel con Menor Voltaje'


@dataclasses.dataclass
class FloatData:
    label: str
    value: float


@dataclasses.dataclass
class StringData:
    label: str
    value: str


@dataclasses.dataclass
class Data:
    date: StringData = dataclasses.field(
        default=StringData(DATE, ''), init=False)
    time: StringData = dataclasses.field(
        default=StringData(TIME, ''), init=False)
    voltages: list[FloatData] = dataclasses.field(
        default_factory=list, init=False)
    average: FloatData = dataclasses.field(
        default=FloatData(AVERAGE, 0), init=False)
    lowest: FloatData = dataclasses.field(
        default=FloatData(LOWEST, 0), init=False)

    def __post_init__(self):
        end_range = max(2, NUMBER_OF_VOLTAGE_PANELS+1)
        for number in range(1, end_range):
            self.voltages.append(FloatData(f'{VOLTAGE} {number}', 0))

    def set_date(self, date: str):
        self.date.value = date

    def set_time(self, time: str):
        self.time.value = time

    def set_voltages(self, voltages: tuple[float]):
        for float_data, voltage in zip(self.voltages, voltages):
            float_data.value = voltage
        self.calculations()

    def calculations(self):
        volatages = [float_data.value for float_data in self.voltages]
        self.average.value = round(statistics.mean(volatages), 2)
        self.lowest.value = min(volatages)


thread_pool_executor = futures.ThreadPoolExecutor(max_workers=1)


def tk_after(target):

    @functools.wraps(target)
    def wrapper(self, *args, **kwargs):
        args = (self,) + args
        self.after(0, target, *args, **kwargs)

    return wrapper


def submit_to_pool_executor(executor):
    '''Decorates a method to be sumbited to the passed in executor'''
    def decorator(target):

        @functools.wraps(target)
        def wrapper(*args, **kwargs):
            result = executor.submit(target, *args, **kwargs)
            result.add_done_callback(executor_done_call_back)
            return result

        return wrapper

    return decorator


def executor_done_call_back(future):
    exception = future.exception()
    if exception:
        raise exception


class App(tk.Tk):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.title("Sistema de Monitoreo de Paneles Solares del SESLab")
        self.config(bg="#919F89")
        self.data = Data()

        width_of_window = 600
        height_of_window = 280
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        x_coordinate = (screen_width/2)-(width_of_window/2)
        y_coordinate = (screen_height/2)-(height_of_window/2)
        self.geometry((f'{width_of_window}x{height_of_window}+'
                       f'{x_coordinate:.0f}+{y_coordinate:.0f}'))

        self.form_frame = FormFrame(self.data, self)
        self.form_frame.pack()
        self.btn = tk.Button(
            self, bg="#E2BBAC", text="Iniciar ", command=self.on_btn)
        self.btn.pack()

    @tk_after
    def btn_enable(self, enable: bool = True):
        self.btn.config(state='normal' if enable else 'disabled')

    def on_btn(self):
        self.btn_enable(False)
        self.update()

    @submit_to_pool_executor(thread_pool_executor)
    def update(self):
        device.open()
        DATA_TO_SEND = "Hola XBee!"
        device.send_data_broadcast(DATA_TO_SEND)

        try:
            device.flush_queues()
            while True:
                xbee_message = device.read_data()
                if xbee_message is not None:
                    data = xbee_message.data.decode()
                    self.data.set_date('30/05/2021')
                    self.data.set_time('12:00')
                    self.data.set_voltages((0.12, 3.8, 1.3))
                    self.form_frame.update()

        finally:
            if device is not None and device.is_open():
                device.close()
            self.btn_enable()


class FormFrame(tk.Frame):
    def __init__(self, data: Data, *args, **kwargs):
        self.data = data
        kwargs['width'] = '1200'
        kwargs['height'] = '600'
        super().__init__(*args, **kwargs)
        self.config(bg="#98A7AC")
        self.str_variables = {}

        label1 = tk.Label(
            self, text="Sistema de monitoreo de Paneles del SESLab", font=18)
        label1.grid(row=0, column=0, padx=5, pady=5, columnspan=2)

        self.data_objs = [self.data.date, self.data.time]
        self.data_objs += [obj for obj in self.data.voltages]
        self.data_objs += [self.data.average, self.data.lowest]

        for row_index, data_obj in enumerate(self.data_objs, 1):
            label = tk.Label(self, text=f'{data_obj.label} : ')
            label.grid(row=row_index, column=0, padx=2, pady=5)

            str_variable = tk.StringVar()
            entry = tk.Entry(self, textvariable=str_variable)
            entry.grid(row=row_index, column=1, padx=1, pady=5)
            entry.config(fg="black", justify="center", state='readonly')
            self.str_variables[data_obj.label] = str_variable

    @tk_after
    def update(self):
        for data_obj in self.data_objs:
            self.str_variables[data_obj.label].set(data_obj.value)


if __name__ == '__main__':
    app = App()
    app.mainloop()
IgnacioMora23 likes this post
Reply


Messages In This Thread
RE: Anyone know what happened to my button? - by Yoriz - May-30-2021, 11:37 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  [PySimpleGui] How to alter mouse click button of a standard submit button? skyerosebud 3 5,038 Jul-21-2019, 06:02 PM
Last Post: FullOfHelp

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020