I am new to tkinter and I coded a live cps counter that displays your current cps, the cps value is therefore constantly changing. All I want to do Is to display this output in the tkinter GUI or an other GUI instead of my pycharm outpout box.
This is the output I get, note that the cps value is changing constantly
10.4 cps
In my code there is this code line that prints the cps:
print(raw_raw/sec, 'cps', end="")
Is there any way I can make this line 'print' in the tkinter GUI?
There is also this line:
print("\r", end="")
That makes the cps count stay in the same line by replacing the previous line to not print an infinite list of cps values
full code:
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()
Thanks for your help
CodePudding user response:
I made an example displaying Your cpi in cmdline, tkinter and pyqt5.
I simplified Your cpi counter and made it in class. Sorry to change Your code completely, but like that it's more suitable to work with multiple output interfaces. In principle, You can use Your code, but it must not be blocking.
Let's start with file click_counter.py
, it will hold ClickCounter
class, which is our back-end, counting clicks in user defined interval
(default is 1 second).
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()
Then we can define different output interfaces.
Let's start with cps_cmdline.py
, which displays cps
in command line:
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)
To display cps in tkinter, use code in file 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()
And last but not least 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()