How to let cmd-line continuous print log message? - python-3.x

I wrote a simple app that I want to print logging message every seconds.
I open a terminal and run it, it works well. But when I use mouse to click the terminal, it will not print logging message unless I print Enter in the terminal.
The Code
import logging
from PyQt5.QtCore import *
logging.basicConfig(level=logging.DEBUG)
app = QCoreApplication([])
timer = QTimer()
timer.setInterval(1000)
timer.timeout.connect(lambda: logging.info("abc"))
timer.start()
app.exec()

Seems to be environment issue.
Below example demonstrates that Qt logging works fine even if mouse button is pressed.
cat pyqt_logging_ex.py
#!/usr/bin/python3.9
import logging,os
from PyQt5.QtCore import *
from pynput import mouse,keyboard
def on_click(x, y, button, pressed):
print("Mouse click")
def on_press(key):
print("Key pressed, exiting")
os._exit(0)
listener = keyboard.Listener(on_press=on_press)
listener.start()
listener = mouse.Listener(on_click=on_click)
listener.start()
print("Started listeners")
logging.basicConfig(level=logging.DEBUG)
app = QCoreApplication([])
timer = QTimer()
timer.setInterval(1000)
timer.timeout.connect(lambda: logging.info("abc"))
timer.start()
app.exec()
Run example:
pyqt_logging_ex.py
Started listeners
INFO:root:abc
INFO:root:abc
INFO:root:abc
Mouse click
Mouse click
INFO:root:abc
INFO:root:abc
Mouse click
Mouse click
INFO:root:abc
INFO:root:abc
qKey pressed, exiting
My environment:
uname -or ; lsb_release -d ; python3.9 --version
4.4.0-19041-Microsoft GNU/Linux
Description: Ubuntu 20.04.3 LTS
Python 3.9.5

Related

Same pygame event generated over and over

In my pygame application, I want a web browser to open when the user presses the F1 key:
#!/usr/bin/env python3
import pygame as pg
import webbrowser
pg.init()
screen = pg.display.set_mode((400, 400))
pg.key.set_repeat(200, 100)
while True:
for evt in pg.event.get():
if evt.type == pg.KEYDOWN and evt.key == pg.K_F1:
webbrowser.open('http://some-website.com')
pg.quit()
When pressing F1, the browser opens but my application keeps opening new tabs if I don't kill it. My guess is that the same KEYDOWN event is generated over and over when my application loses the focus due to the use of pg.key.set_repeat: if I comment this call to pg.key.set_repeat then everything works fine.
How can I fix that?
Versions used are: pygame 2.0.1 (SDL 2.0.14, Python 3.9.5).
You should use keyboard module like this:
import keyboard
# [...]
while True:
# [...]
if keyboard.is_pressed("F1"):
webbrowser.open('http://some-website.com')
pg.quit()
Or you can break the loop after you open the spesific website:
# [...]
while True:
for evt in pg.event.get():
if evt.type == pg.KEYDOWN and evt.key == pg.K_F1:
webbrowser.open('http://some-website.com')
break
# [...]
pg.quit()

Pyqt5--Why QApplication.processEvents() failed to update GUI

I am learning to use PyQT5 and QtDesign. The workflow is :Click button->Change a image. But GUI failed to update until QMessege appeared. Here is a code. Firstly, I draw a button named pass_btn, a label named fds_img, by QtDesign.
Then, code as below:
from PyQt5 import QtWidgets, uic, QtGui
import os, sys
from PyQt5.QtWidgets import *
app = QtWidgets.QApplication(sys.argv)
dlg = uic.loadUi('grading_sys.ui')
stepper = 0
img_dir_list = [] #this is a image dir list
dlg.fds_img.setPixmap(QtGui.QPixmap(img_dir_list[stepper]))
def pass_btn():
global stepper
if stepper == len(img_dir_list) - 1:
QtWidgets.QMessageBox.information(None, 'Warning', 'Warning')
return
stepper += 1
dlg.fds_img.setPixmap(QtGui.QPixmap(img_dir_list[stepper]))
print('Try to refresh')
QApplication.processEvents()
dlg.pass_btn.clicked.connect(pass_btn)
dlg.show()
sys.exit(app.exec_())
So why I could not refresh the label? Or how could I refresh image when I click the button?
Finally, I solved this by using QTimer. I know it is a waste of CPU, may not efficient enough, but it finally works. But I still confusing about why it did't work before. I solved this as codes below:
First, put all the update codes in a def, then connected it with QTimer, and ran it every second:
def refresh_ui():
print('Try to refresh UI')
print('Prepare to change image' + str(img_dir_list[stepper]))
dlg.fds_img.setPixmap(QtGui.QPixmap(img_dir_list[stepper]))
timer = QTimer()
timer.timeout.connect(refresh_ui)
timer.start(1000)
My environment: MacOS 10.14.2, PyCharm 2018.3.3 edu edition, Python 3.6, PyQt5, QtDesign (through Anaconda). Dose this happened because of MacOS?

tkinter window not closing properly

My tkinter app windows are not closing properly. I am using python 3.6.6 with tkinter 8.6
My code does basically this:
Open a process, where:
A test function is called via a thread that closes Gui window after 3s
Gui window is created
Wait for thread to complete (join) and guess window was closed
I tried to use:
quit -> window only closes when i hover my mouse over it
destroy -> destroy does not return
I stripped it down to the following code, please copy & execute and/or tell me whats wrong...
from time import sleep, time
import threading
from multiprocessing import Process, set_start_method
from tkinter import *
CtrlApplObj = None
def Start():
global CtrlApplObj
CtrlApplObj = None
CtrlApplObj = ControlApplication()
CtrlApplObj.run()
def End():
print("Quit now...")
#CtrlApplObj.root.destroy()
CtrlApplObj.root.quit()
class ControlApplication():
def __init__(self):
pass
def run(self):
self.root=Tk()
print("Mainloop...")
self.root.mainloop()
def test():
sleep(3)
End()
def execute():
T1 = threading.Thread(target=test)
T1.start()
Start()
T1.join()
if __name__ == "__main__":
set_start_method("spawn")
for i in range(2):
TestProcess = Process(target=execute)
TestProcess.start()
TestProcess.join()
My final solution was not using any tkinter operations in test thread. Then destroy worked.
I had another problem with my test process not closing. This was because a queue was not empty. That porevented process to close.

Incorrect behaviour of print() when executed from within a QTDialog window in Spyder

I am working on a very simple interface to explore/graph csv files. My aim is ultimately to explore, not to build software as I am not a developer, more of a "desperate user" :-)
I am leveraging the code found in this example
These are my first steps both in Python and in GUI, so I tend to put print messages in my calls so that I can more or less track what is happening. And this is where I found a strange behavior if I run the code from within Spyder.
import sys
import os
from PyQt4 import QtGui
import pandas as pd
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
# QtGui.QDialog
class Window(QtGui.QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# a figure instance to plot on
self.figure = plt.figure()
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init__
self.canvas = FigureCanvas(self.figure)
# this is the Navigation widget
# it takes the Canvas widget and a parent
self.toolbar = NavigationToolbar(self.canvas, self)
# Just some extra button to mess around
self.button= QtGui.QPushButton('Push Me')
self.button.clicked.connect(self.do_print)
# set the layout
layout = QtGui.QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
self.setLayout(layout)
def do_print(self):
print('Hello World!!')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
The strange behavior is that if I push the button once, nothing happens on the Ipython console. By the second time I push, then two "Hello World!" printouts appear.
If, on the other hand, I just launch my script from within a Windows Shell:
python my_simple_test.py
Then everything works as expected.
What am I then doing wrong from within Spyder?
Thanks,
Michele
IPython buffers stdout a bit differently from a terminal. When something is printed, it looks at how long it has been since it last flushed the buffer, and if it's longer than some threshold, it flushes it again. So the second time you click the button, it flushes stdout, and you see both outputs.
You can force it to flush immediately like this:
print('Hello World!!')
sys.stdout.flush()

QFileDialog: no signals emitted, wrong starting directory

I'm trying to show a QFileDialog using the following piece of code:
import os, sys
from PyQt4.QtGui import *
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self._button = QPushButton('Test button')
self._button.clicked.connect(self._onButtonClicked)
self._layout = QHBoxLayout()
self._layout.addWidget(self._button)
self.setLayout(self._layout)
def _onButtonClicked(self):
self._dialog = QFileDialog(self, 'Select directory')
self._dialog.setDirectory(os.getenv('HOME'))
self._dialog.setFileMode(QFileDialog.Directory)
self._dialog.directoryEntered.connect(self._onDirEntered)
self._dialog.exec_()
def _onDirEntered(self, directory):
print("Entered directory: %s" % (directory))
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
app.exec_()
Two problems here:
The directoryEntered signal is never emitted, at least I don't get any output from the script (except for some KDE warnings about Samba support, etc.); actually no signal from the QFileDialog class I tried to connect to gets emitted in the example. What am I doing wrong?
In this example I set the starting directory to $HOME, but the dialog will start in /home instead and have my home directory selected in the listing instead of starting directly in my home directory. Can I change this behaviour somehow?
I'm using Python 3.4.0 with PyQt 4.10.4-2.
Both problems do not occur when using a non-native dialog as suggested by #ekhumoro.

Resources