diff --git a/TermTk/TTkCore/signal.py b/TermTk/TTkCore/signal.py index 1dbd934d..ea3a3142 100644 --- a/TermTk/TTkCore/signal.py +++ b/TermTk/TTkCore/signal.py @@ -59,6 +59,7 @@ __all__ = ['pyTTkSlot', 'pyTTkSignal'] from inspect import getfullargspec from types import LambdaType +from threading import Lock def pyTTkSlot(*args, **kwargs): def pyTTkSlot_d(func): @@ -72,7 +73,7 @@ def pyTTkSignal(*args, **kwargs): class _pyTTkSignal_obj(): _signals = [] - __slots__ = ('_types', '_name', '_revision', '_connected_slots') + __slots__ = ('_types', '_name', '_revision', '_connected_slots', '_mutex') def __init__(self, *args, **kwargs): # ref: http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html#PyQt5.QtCore.pyqtSignal @@ -90,6 +91,7 @@ class _pyTTkSignal_obj(): self._name = kwargs.get('name', None) self._revision = kwargs.get('revision', 0) self._connected_slots = {} + self._mutex = Lock() _pyTTkSignal_obj._signals.append(self) def connect(self, slot): @@ -133,11 +135,13 @@ class _pyTTkSignal_obj(): del self._connected_slots[slot] def emit(self, *args, **kwargs): + if not self._mutex.acquire(False): return if len(args) != len(self._types): error = "func"+str(self._types)+" signal has "+str(len(self._types))+" argument(s) but "+str(len(args))+" provided" raise TypeError(error) for slot,sl in self._connected_slots.copy().items(): slot(*args[sl], **kwargs) + self._mutex.release() def clear(self): self._connected_slots = {} diff --git a/TermTk/TTkWidgets/scrollbar.py b/TermTk/TTkWidgets/scrollbar.py index 81ebdb19..2780251b 100644 --- a/TermTk/TTkWidgets/scrollbar.py +++ b/TermTk/TTkWidgets/scrollbar.py @@ -126,12 +126,11 @@ class TTkScrollBar(TTkWidget): def wheelEvent(self, evt): if evt.evt == TTkK.WHEEL_Up: - self._value -= self._pageStep + value = self._value-self._pageStep else: - self._value += self._pageStep - self._value = max(self._minimum,min(self._maximum,self._value)) + value = self._value+self._pageStep + self.setValue(max(self._minimum,min(self._maximum,value))) self.sliderMoved.emit(self._value) - self.update() return True def mousePressEvent(self, evt): @@ -143,21 +142,20 @@ class TTkScrollBar(TTkWidget): mouse = evt.x if mouse == 0: # left/up arrow pressed - self._value = self._value - self._singleStep + self.setValue(self._value - self._singleStep) elif mouse == size-1: # right/down arrow pressed - self._value = self._value + self._singleStep + self.setValue(self._value + self._singleStep) elif self._screenPgDown[0] <= mouse < self._screenPgDown[1]: - self._value = self._value - self._pageStep + self.setValue(self._value - self._pageStep) elif self._screenPgUp[0] <= mouse < self._screenPgUp[1]: - self._value = self._value + self._pageStep + self.setValue(self._value + self._pageStep) elif self._screenScroller[0] <= mouse < self._screenScroller[1]: self._mouseDelta = mouse-self._screenScroller[0] self._draggable = True else: return False - self._value = max(self._minimum,min(self._maximum,self._value)) + self.setValue(max(self._minimum,min(self._maximum,self._value))) self.sliderMoved.emit(self._value) - self.update() # TTkLog.debug(f"m={mouse}, md:{self._mouseDelta}, d:{self._screenPgDown},u:{self._screenPgUp},s:{self._screenScroller}") return True @@ -176,11 +174,9 @@ class TTkScrollBar(TTkWidget): asciiDrawingSize = size2 - asciiStep a = aa * (self._maximum - self._minimum) // asciiDrawingSize - self._value = a + self._minimum - self._value = max(self._minimum,min(self._maximum,self._value)) + self.setValue(max(self._minimum,min(self._maximum,a+self._minimum))) self.sliderMoved.emit(self._value) - self.update() # TTkLog.debug(f"m={mouse}, md:{self._mouseDelta}, aa:{aa}") return True diff --git a/tests/test.ui.006.scroll.py b/tests/test.ui.006.scroll.01.py similarity index 100% rename from tests/test.ui.006.scroll.py rename to tests/test.ui.006.scroll.01.py diff --git a/tests/test.ui.006.scroll.02.tryLoop.py b/tests/test.ui.006.scroll.02.tryLoop.py new file mode 100755 index 00000000..c624849b --- /dev/null +++ b/tests/test.ui.006.scroll.02.tryLoop.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys, os + +sys.path.append(os.path.join(sys.path[0],'..')) +import TermTk as ttk + +root = ttk.TTk() + +sb1 = ttk.TTkScrollBar(parent=root, pos=(10,2), size=(1,10)) +sb2 = ttk.TTkScrollBar(parent=root, pos=(12,2), size=(1,12)) +sb3 = ttk.TTkScrollBar(parent=root, pos=(14,2), size=(1,14)) +sb4 = ttk.TTkScrollBar(parent=root, pos=(16,2), size=(1,16)) +sb5 = ttk.TTkScrollBar(parent=root, pos=( 5,0), size=(30,1), orientation=ttk.TTkK.HORIZONTAL) + +sb1.valueChanged.connect(sb2.setValue) +sb2.valueChanged.connect(sb3.setValue) +sb3.valueChanged.connect(sb4.setValue) +sb4.valueChanged.connect(sb5.setValue) +sb5.valueChanged.connect(sb1.setValue) + + +root.mainloop() \ No newline at end of file diff --git a/tools/check.import.sh b/tools/check.import.sh index 34e268e0..8c7e41fc 100755 --- a/tools/check.import.sh +++ b/tools/check.import.sh @@ -9,6 +9,7 @@ __check(){ -e "from dataclasses" \ -e "signal.py:from inspect import getfullargspec" \ -e "signal.py:from types import LambdaType" \ + -e "signal.py:from threading import Lock" \ -e "colors.py:from .colors_ansi_map" \ -e "log.py:import inspect" \ -e "log.py:import logging" \