显示 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()
我是 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()