显示 python(不断变化)'print output' 到 tkinter GUI 文本框(刷新?)

Display python (constantly changing) 'print output' to tkinter GUI textbox (flush?)

我是 tkinter 的新手,我编写了一个实时 cps 计数器来显示您当前的 cps,因此 cps 值不断变化。我想要做的就是 在 tkinter GUI 或其他 GUI 中显示此输出,而不是我的 pycharm 输出框。

这是我得到的输出,请注意 cps 值不断变化

10.4 cps

在我的代码中有这个打印 cps 的代码行:

print(raw_raw/sec, 'cps', end="")

有什么办法可以在 tkinter GUI 中制作这条线 'print' 吗?

还有这一行:

print("\r", end="")

通过替换上一行而不打印无限的 cps 值列表,使 cps 计数保持在同一行

完整代码:

from pynput.mouse import Listener
import time

raw_clicks = 0
sec = 0.6

def on_click(x, y, button, pressed):
    global start
    listener.stop()
    start = time.time()
    print('')

with Listener(on_click=on_click) as listener:
    listener.join()

while True:
    def on_click(x, y, button, pressed):
            global raw_clicks
            global sec
            global start
            raw_clicks = raw_clicks + 1
            if time.time() - start > sec:
                listener.stop()
                raw_raw = (raw_clicks / 2)
                raw_raw = round(raw_raw/sec, 1)
                print("\r", end="")
                print(raw_raw, 'cps', end="")
                raw_clicks = 0
                start = time.time()

    with Listener(on_click=on_click) as listener:
        listener.join()

感谢您的帮助

我做了一个例子,在 cmdline、tkinter 和 pyqt5 中显示你的 cpi。

我简化了您的 cpi 计数器并在 class 中完成了它。很抱歉完全更改您的代码,但这样更适合使用多个输出接口。原则上,你可以使用你的代码,但一定不能阻塞。

让我们从文件 click_counter.py 开始,它将包含 ClickCounter class,这是我们的 back-end,计算用户定义的点击次数 interval(默认是 1 秒)。

from threading import Thread, Event
from typing import Callable

from pynput.mouse import Listener


class ClickCounter(Thread):
    """Click counter, counting clicks / interval"""
    click_count = 0
    stopped = Event()

    def __init__(self, callback: Callable, interval: float = 1.0) -> None:
        super().__init__()
        self.interval = interval
        self.callback = callback
        self.listener = Listener(on_click=self.click_counter)

    def run(self) -> None:
        """Start mouse click listener and timer"""
        self.listener.start()

        while not self.stopped.wait(self.interval):
            # Call callback with click counter value, after interval expires
            self.callback(self.click_count)
            # Reset counter
            self.click_count = 0

    def click_counter(self, x: float, y: float, button: int, pressed: bool) -> None:
        """Count clicks"""
        if pressed:
            # Count when mouse button is pressed
            self.click_count += 1

    def cancel(self) -> None:
        """Cancel counter timer"""
        # Stop timer
        self.stopped.set()
        # Stop listener
        self.listener.stop()

然后我们可以定义不同的输出接口
让我们从 cps_cmdline.py 开始,它在命令行中显示 cps

import signal
from time import sleep

from click_counter import ClickCounter


def print_counter(count):
    print("\r", end="")
    print(count, 'cps', end="")


click_counter = ClickCounter(print_counter)
click_counter.start()

stopped = False

def exit_app(*args):
    """Close counter and app"""
    global stopped, click_counter
    click_counter.cancel()
    stopped = True

# Register kill signals
signal.signal(signal.SIGINT, exit_app)
signal.signal(signal.SIGTERM, exit_app)

while not stopped:
    # Just run until stopped
    sleep(0.1)

要在 tkinter 中显示 cps,请使用文件中的代码 cps_tkinter.py:

import tkinter as tk

from cps.click_counter import ClickCounter


class Window(tk.Frame):

    def __init__(self, master=None):
        """Create label and StringVar holding its text"""
        super().__init__(master)
        self.master = master
        self.pack(fill=tk.BOTH, expand=1)
        self.cps_text = tk.StringVar(value="0 cps")
        self.cps_label = tk.Label(self, textvariable=self.cps_text)
        self.cps_label.place(relx=0.5, rely=0.5, anchor='center')

    def print_counter(self, count):
        """Thread safe variable set"""
        self.after(0, self.cps_text.set, f"{count} cps")

if __name__ == "__main__":
    root = tk.Tk()
    app = Window(root)
    root.wm_title("CPS counter")
    root.geometry("100x100")

    # Create and start counter
    click_counter = ClickCounter(app.print_counter)
    click_counter.start()

    # Start tkinter app
    root.mainloop()
    # tkinter app is over, cancel click_counter
    click_counter.cancel()

最后但同样重要的是 cps_qt5.py:

import sys

from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout

from cps.click_counter import ClickCounter


class Window(QWidget):
    sig_print_counter = pyqtSignal(int)

    def __init__(self, parent=None):
        """Create label and StringVar holding its text"""
        super().__init__(parent)
        self.cps_label = QLabel()
        self.cps_label.setText("0 cps")
        self.resize(100, 100)
        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignHCenter)
        layout.addWidget(self.cps_label)
        self.setLayout(layout)
        self.sig_print_counter.connect(self.print_counter)

    @pyqtSlot(int)
    def print_counter(self, count):
        """Thread safe label text set"""
        self.cps_label.setText(f"{count} cps")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()

    # Create and start counter
    click_counter = ClickCounter(window.sig_print_counter.emit)
    click_counter.start()

    app.exec()
    # Qt app is over, cancel click_counter
    click_counter.cancel()