Seite 1 von 1

Double-Action/Click Event

Verfasst: Samstag 13. Februar 2016, 23:27
von harryberlin
Grüße

Ich hab mir mal ein script gebastelt, mit dem ich eine Art Double Click für Funktionen realisieren möchte.
Gibt es auch wege das sinnvoller so lösen?

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

from threading import Thread
import time

class Clicker():
    def __init__(self):
        self.click_time = time.time() - 1
        self.single_event = True
        self.__double_click_delay = 0.3

    def click(self):
        t = time.time()
        if t - self.click_time < self.__double_click_delay:
            self.single_event = False
            return 2
        else:
            self.click_time = time.time()
            time.sleep(self.__double_click_delay)
            if self.single_event:
                return 1
            else:
                self.single_event = True
                return 0

def as_thread(function, params=[]):
    thread = Thread(target=function, args=params)
    thread.start()

def click_event(singleevent,doubleevent):
    temp = click1.click()
    if temp == 2:
        doubleevent()
    elif temp == 1:
        singleevent()


def single():
    print 'single'

def double():
    print 'double'

def main():
    as_thread(click_event,[single,double])
    time.sleep(0.250)
    as_thread(click_event,[single,double])


click1 = Clicker()

if __name__ == '__main__':
    main()


Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 01:34
von pillmuncher
Für sowas würde ich evtl. asyncio oder RxPy verwenden, aber selbstgestrickt geht es auch:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Queue
import threading
import time


class Clicker:

    def __init__(self, double_click_interval, single_func, double_func):
        self._queue = Queue.Queue()
        latch = threading.Event()

        def handle_clicks():
            latch.set()
            while True:
                self._queue.get()
                try:
                    self._queue.get(True, double_click_interval)
                except Queue.Empty:
                    single_func()
                else:
                    double_func()

        thread = threading.Thread(target=handle_clicks)
        thread.daemon = True
        thread.start()
        latch.wait()

    def click(self):
        self._queue.put(None)


def single():
    print 'single'


def double():
    print 'double'


def main():
    clicker = Clicker(.3, single, double)
    clicker.click()
    clicker.click()
    clicker.click()
    time.sleep(0.250)
    clicker.click()
    clicker.click()
    time.sleep(0.350)
    clicker.click()


if __name__ == '__main__':
    main()
    time.sleep(1)
Das noch:

1) statt /usr/bin/python direkt in die shebang-Zeile zu schreiben, ist es besser, /usr/bin/env python zu verwenden. Dann wird auch in einem virtuellen Environment das richtige Python verwendet, statt immer das aus dem /usr/bin Verzeichnis.

2) die leeren Klammern hinter dem Klassennamen bei deiner Klassendefinition haben keinerlei Funktion. Lass sie weg.

3) doppelte führende Unterstriche bei einem Attributnamen bedeuten nicht, dass das ein privates Attribut ist. So etwas gibt es in Python überhaupt nicht. Statt dessen gibt es die Konvention, dass der Name eines Attributs, das ein Implementationsdetail ist, mit einem einzelnen führenden Unterstrich begimmt. Zwei führende Unterstriche (ohne zwei abschließende solche) führen zum sog Name Mangling. Mehr dazu hier.

Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 02:12
von BlackJack
Ergänzend zu 2): Bei Python 2 die Klammern nicht weglassen, sondern ``object`` dort hineinschreiben, denn wenn man von nichts erbt, bekommt man eine ”old style”-Klasse bei der nicht alles funktioniert was Python so bietet.

Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 08:03
von harryberlin
echt merkwürdig, e-mail benachrichtigungen bleiben schon eine ganze zeit aus....
danke für die überarbeitung, dass probiere ich gleich mal aus.

zu 2. ja da hab ich nicht ganz aufgepasst, hatte bei in tests davor noch thread drin stehen.

zu 3. das mit den zwei unterstrichen hatte ich aus der doku zu threading. dass unterstriche nix bewirken, im tatsächlichen sinne, weiß ich. aber trotzdem weg lassen, ok. aber pycharm ist so schlau und bietet mir dieses attribut nicht an, wenn ich "click1." eintippe.

Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 11:52
von harryberlin
Kann ich meine funktionen zum ausführen in eine klasse packen und übergeben?
derzeit läufts auf nen fehler.
TypeError: unbound method double() must be called with events instance as first argument (got nothing instead)

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Queue
import threading
import time


class Clicker:

    def __init__(self, double_click_interval, single_func, double_func):
        self._queue = Queue.Queue()
        latch = threading.Event()

        def handle_clicks():
            latch.set()
            while True:
                self._queue.get()
                try:
                    self._queue.get(True, double_click_interval)
                except Queue.Empty:
                    single_func()
                else:
                    double_func()

        thread = threading.Thread(target=handle_clicks)
        thread.daemon = True
        thread.start()
        latch.wait()

    def click(self):
        self._queue.put(None)

class events:

    def single(self):
        print 'single'

    def double(self):
        print 'double'


def main():
    clicker = Clicker(0.3, events.single, events.double)
    print '1st click'
    clicker.click()
    print '2nd click'
    clicker.click()

    time.sleep(0.350)

    print '3rd click'
    clicker.click()

if __name__ == '__main__':
    main()
    time.sleep(1)
  
oder sollte ich einfach nur meine funktionen umbenennen?

Code: Alles auswählen

def event_single(self):
    print 'single'

def event_double(self):
    print 'double'

Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 11:57
von harryberlin
haha, bin grad selbst auf die lösung gekommen.
musste die classe noch in eine instanz setzen.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import Queue
import threading
import time


class Clicker:
    def __init__(self, double_click_interval, single_func, double_func):
        self._queue = Queue.Queue()
        latch = threading.Event()

        def handle_clicks():
            latch.set()
            while True:
                self._queue.get()
                try:
                    self._queue.get(True, double_click_interval)
                except Queue.Empty:
                    single_func()
                else:
                    double_func()

        thread = threading.Thread(target=handle_clicks)
        thread.daemon = True
        thread.start()
        latch.wait()

    def click(self):
        self._queue.put(None)


class events:
    def single(self):
        print 'single'

    def double(self):
        print 'double'

event = events()

def main():
    clicker = Clicker(0.3, event.single, event.double)
    print '1st click'
    clicker.click()
    print '2nd click'
    clicker.click()

    # time.sleep(0.350)

    print '3rd click'
    clicker.click()


if __name__ == '__main__':
    main()
    time.sleep(1)


Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 12:04
von BlackJack
@harryberlin: `events` sollte mit einem grossen `E` anfangen. Das ist aber auch semantisch gar keine Klasse, sondern zwei einzelne Funktionen, dementsprechend sollten die auch nicht syntaktisch in einer Klasse stecken.

Der Fehler, der zu der Ausnahme führt, ist das Du kein Exemplar von `events` erstellt hast, sondern direkt die ungebundenen Methoden angibst, und da fehlt dann beim Aufruf das Exemplar als erstes Argument. Wenn die Methoden nicht von der Klasse sondern von einem Exemplar kommen, dann sind sie ja an dieses Exemplar gebunden, dass heisst es wird automatisch als erstes Argument übergeben. Was, wie im letzten Absatz schon erwähnt, allerdings keinen Sinn macht, weil man das hier überhaupt gar nicht braucht. Wenn man `self` nicht benutzt, sollte man dafür eine nachvollziehbare Erklärung haben, sonst macht man etwas falsch.

Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 12:49
von harryberlin
Stimmt, es war nicht groß geschrieben. Verzeih mir den Fehler.

Als Idee hätte ich jetzt noch ein dictionary. Aber da wäre es mir am liebsten, wenn ich die funktion direkt darin schreiben könnte.
das simple print war nur zum testen.
Hintergrund ist, ich möchte Funktionen, die aus meiner sicht zusammen gehören, irgendwie gebündelt sind.
ein script zum ewig langen scrollen find ich umständlich. in einer art klasse geht es noch, weil man die in pycharm einklappen kann.

Re: Double-Action/Click Event

Verfasst: Sonntag 14. Februar 2016, 14:00
von BlackJack
@harryberlin: Namensräume für Funktionen sind Module/Packages und nicht Klassen. Wobei Du natürlich Klassen verwenden kannst und solltest, wenn dort wirklich zusammengehöriger Zustand *und* Operationen zusammengefasst werden.