Custom slider value passing

I am trying to write a custom control using “Drawable”. Now it is the last step. The variable “_Initializing_value” in the class cannot be updated in the main window in real time, even though I used “ParentWindow.Invalidate(True)”.
“m_label.Text” will never refresh with “_Initializing_value”
I tested it by printing “x_point_OnMouseUp” in the “OnMouseUp” event, but I didn’t see any change to “m_label.Text”

#! python 3
import Eto.Forms as ef
import Eto.Drawing as ed
import rhinoscriptsyntax as rs

class Slider_tom(ef.Drawable):
    def __init__(self , Initializing_value , Minimum_value , Maximum_value):
        super().__init__()
        self.Width = Maximum_value
        self.Height = 25
        self._Initializing_value = Initializing_value
        self._Initializing_value_point = ed.PointF(Initializing_value , self.Height*0.5)
        self._Minimum_value = Minimum_value
        self._Maximum_value = Maximum_value
        self._Starting_point = ed.PointF(self._Minimum_value ,self.Height*0.5)
        self._end_point = ed.PointF(self._Maximum_value , self.Height*0.5)
        self._lin_a = ed.Pen(ed.Colors.CornflowerBlue, 1)
        self._Starting_point_rct = ed.SizeF(10,10)
        self._Colors_Starting_point_rct = ed.Colors.PaleVioletRed
        self._Initializing_value_point_mouse = ed.PointF(Initializing_value , self.Height*0.5)
        self._Initializing_value_point_mouse_OnMouseUp = ed.PointF(Initializing_value , self.Height*0.5)
        self._valve_value = 1
    def OnPaint(self,e):
        e.Graphics.DrawLine(self._lin_a, self._Starting_point ,self._end_point)

        if self._valve_value == 1:
            Starting_point_rct = ed.RectangleF.FromCenter(self._Initializing_value_point, self._Starting_point_rct)
        elif self._valve_value == 0:
            Starting_point_rct = ed.RectangleF.FromCenter(self._Initializing_value_point_mouse, self._Starting_point_rct)
        elif self._valve_value == 2:
            Starting_point_rct = ed.RectangleF.FromCenter(self._Initializing_value_point_mouse_OnMouseUp, self._Starting_point_rct)
        else:
            pass
        e.Graphics.FillEllipse(self._Colors_Starting_point_rct, Starting_point_rct)
        pass
    def OnMouseEnter(self, e):
        pass
    def OnMouseLeave(self, e):
        pass
    def OnMouseMove(self, e):
        x_point = e.Location.X
        self._Initializing_value_point_mouse = ed.PointF(x_point , self.Height * 0.5)
        self.Invalidate(True)
        pass
    def OnMouseDown(self, e):
        self._valve_value = 0
        self.Invalidate(True)
        pass
    def OnMouseUp(self, e):
        self.x_point_OnMouseUp = e.Location.X 
        self._Initializing_value = self.x_point_OnMouseUp #This
        self._Initializing_value_point_mouse_OnMouseUp = ed.PointF(self.x_point_OnMouseUp , self.Height * 0.5)
        self._valve_value = 2
        print(self.x_point_OnMouseUp)
        self.Invalidate(False)
        self.ParentWindow.Invalidate(True)
        pass


if __name__ == "__main__":
    form = ef.Form()
    form.Width = 300
    form.Height = 300
    #---------
    Slider = Slider_tom(Initializing_value = 10 , Minimum_value=0 , Maximum_value=100)
    
    m_label = ef.Label()
    m_label.Text = str(Slider._Initializing_value)
    #---------
    Layout_0 = ef.PixelLayout()
    Layout_0.Add(Slider,0,0)
    Layout_0.Add(m_label,120,0)
    form.Content = Layout_0
    form.Show()


I am now in the school dormitory, can not sleep at all, who will help me

The issue is that updating the label (or any UI element) needs to happen inside an event handler. For example, to update the label when the mouse is released, you can do this:

def OnMouseUp(self, e):
    m_label.Text = str(e.Location.X)

However, OnMouseUp might not be the ideal place for this, especially if you want real-time updates while dragging. A more intuitive approach is to track mouse dragging with these event handlers:

def OnMouseDown(self, e):
    self._dragging = True

def OnMouseUp(self, e):
    self._dragging = False

def OnMouseMove(self, e):
    if self._dragging:
        self._value = self._clamp(e.Location.X)
        self._label.Text = str(int(self._value))
        self.Invalidate(True)

Here’s the full simplified version of the working slider:

#! python 3
import Eto.Forms as ef
import Eto.Drawing as ed

class SimpleSlider(ef.Drawable):
    def __init__(self, value, min_val, max_val, label):
        super().__init__()
        self._min = min_val
        self._max = max_val
        self._value = self._clamp(value)
        self._label = label
        self._label.Text = str(int(self._value))

        self.Width = max_val
        self.Height = 25
        self._handle_size = 10
        self._dragging = False

    def _clamp(self, x):
        return max(self._min, min(self._max, x))

    def _handle_position(self):
        return ed.PointF(self._value, self.Height * 0.5)

    def OnPaint(self, e):
        line_start = ed.PointF(self._min, self.Height * 0.5)
        line_end = ed.PointF(self._max, self.Height * 0.5)
        e.Graphics.DrawLine(ed.Pen(ed.Colors.CornflowerBlue, 1), line_start, line_end)

        handle_rect = ed.RectangleF.FromCenter(self._handle_position(), ed.SizeF(self._handle_size, self._handle_size))
        e.Graphics.FillEllipse(ed.Colors.PaleVioletRed, handle_rect)

    def OnMouseDown(self, e):
        self._dragging = True

    def OnMouseUp(self, e):
        self._dragging = False

    def OnMouseMove(self, e):
        if self._dragging:
            self._value = self._clamp(e.Location.X)
            self._label.Text = str(int(self._value))
            self.Invalidate(True)


if __name__ == "__main__":
    form = ef.Form()
    form.Width = 300
    form.Height = 100

    label = ef.Label()

    slider = SimpleSlider(value=10, min_val=0, max_val=100, label=label)

    layout = ef.PixelLayout()
    layout.Add(slider, 10, 10)
    layout.Add(label, 120, 10)
    form.Content = layout
    form.Show()
1 Like

Thank you very much, this is perfect, I learned new knowledge today, I will remember to update changes in the event