Skip to content

[Solved]增加鼠标滚轮滚动位置操作记录 #10

@FoxonFires

Description

@FoxonFires

参照services\move_tracker.py和click_tracker.py,照猫画虎新增了一个鼠标滚轮操作记录,翻文档或代码时也能证明没摸鱼……

还是直接贴在这里了:
services\scroll_tracker.py

import time
import tkinter as tk

from service.image_cache import ImageCache
from service.types import Color
import threading
from collections import deque

class ScrollTracker(tk.BooleanVar):
    def __init__(self, cache: ImageCache):
        """A tracker that maintains a state of whether it should track or not"""
        super(ScrollTracker, self).__init__(value=True)
        self.cache = cache
        # 滚动事件缓存
        self.point_cache = dict()
        
        self.render_timer = threading.Thread(target=self.render)
        self.render_timer.setDaemon(True)
        self.render_timer.start()

    def __del__(self):
        # 关闭定时器线程
        self.render_timer.join()        # 但是这一句不管用
        pass

    def render(self):
        # 渲染,清空缓存,将线段缓存绘制到图像上
        # 线程一旦开启就不再退出,等待主线程关闭
        while True:
            # 一旦队列中有元素,则渲染,直到队列只有一个点,表示鼠标不动
            # 每次仅移除一个点
            while len(self.point_cache) > 1:
                key, value = self.point_cache.popitem()
                (x, y) = key
                (dx, dy)  = value

                R = int(255*(dx + 1) / 2)   # 没有能测试横向滚的设备,Shift+滚轮还是(0, +-1)
                G = int(255*(dy + 1) / 2)   # 上下滚动时(dx, dy) = (0, +-1)
                B = 255
                colour = (R, G, B, 255)     # 借一下法线贴图的颜色映射

                # print(f"scroll at ({x}, {y}), dir({dx}, {dy}), UV({R}, {G}, {B})")
                self.cache.ellipse(x, y, color = colour)
            time.sleep(0.01)    # 增加睡眠减少线程占用

    def track(self, x: int, y: int, dx: int, dy: int):
        if self.get():
            # 此处将在每次鼠标移动时调用,非常频繁,因此需要优化
            # 使用字典,同一时间在一个位置上的操作只绘制一次
            self.point_cache.update({(x, y): (dx, dy)})




顺便更新了一些其他文件,调用上面的:
services\trackers.py

from typing import Dict

from pynput import mouse

from service.click_tracker import ClickTracker
from service.move_tracker import MoveTracker
from service.scroll_tracker import ScrollTracker


class Trackers(mouse.Listener):
    def __init__(self,
                 click_trackers: Dict[mouse.Button, ClickTracker],
                 move_tracker: MoveTracker,
                 scroll_tracker: ScrollTracker
                 ):
        """
        Implemented by pynput.mouse
        The `mouse.Listener` will create a thread.
        """
        self.click_trackers = click_trackers
        self.move_tracker = move_tracker
        self.scroll_tracker = scroll_tracker

    def reset(self):
        """Reset the mouse listener"""
        super(Trackers, self).__init__(
            on_move=self.move_tracker.on_move,
            on_click=self.on_click,
            on_scroll=self.on_scroll
        )

    def on_click(self, x, y, button, pressed):
        """Pick the right tracker and track"""
        if pressed:
            self.click_trackers[button].track(x, y)

    def on_scroll(self, x, y, dx, dy):
        self.scroll_tracker.track(x, y, dx, dy)

以及main.py初始化的应用构造函数:

class App(tk.Tk):
    def __init__(self):
        super(App, self).__init__()

        # 配置ui信息
        self.title("Mouse Tracker")
        self.geometry("400x400")
        icon_path = './assert/a952d-5afjj.icns'
        if sys.platform.startswith("darwin"):
            icon_image = ImageTk.PhotoImage(Image.open(icon_path))
            self.iconphoto(True, icon_image)
        else:
            self.wm_iconbitmap('./assert/favicon.ico')
        self.config(
            background='#2e3e26',
        )

        # 绑定数据信息
        self.imageCache = ImageCache(
            get_main_screen_size()
        )

        self.line_opacity_value = tk.IntVar(value=50)
        self.line_opacity = InputRange(
            '线条不透明度(实时)',
            variable=self.line_opacity_value,
            from_=1,
            to=100,
        )

        self.line_width_value = tk.IntVar(value=2)
        self.line_width = InputRange(
            '线条宽度(实时)',
            variable=self.line_width_value,
            from_=1,
            to=25,
        )

        self.trackers = Trackers(
            click_trackers={
                mouse.Button.left: ClickTracker(cache=self.imageCache, color=Colors.Left),
                mouse.Button.right: ClickTracker(cache=self.imageCache, color=Colors.Right),
                mouse.Button.middle: ClickTracker(
                    cache=self.imageCache, color=Colors.Middle
                ),
            },
            move_tracker=MoveTracker(self.imageCache, self.line_opacity_value, self.line_width_value),
            scroll_tracker=ScrollTracker(cache=self.imageCache),
        )
        # 挂载组件
        self.radio_list = [     #勾选checklist
            Radio(self, text=text, variable=tracker)
            for text, tracker in zip(
                ["记录左键点击位置", "记录右键点击位置", "记录中键点击位置", "记录鼠标移动轨迹", "记录滚轮滚动位置"],
                [*self.trackers.click_trackers.values(), self.trackers.move_tracker, self.trackers.scroll_tracker],
            )
        ]
        self.switch_button = SwitchButton(
            [self.start_tracking, self.stop_tracking],
            ['开始记录', '结束记录'],
        )
        self.open_out_files = SwitchButton(
            [open_out_folder], ['打开out文件夹']
        )
    def mainloop(self, n: int = 0) -> None:
        time.sleep(0.01)        #增加睡眠减少线程占用
        return super().mainloop(n)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions