Waiting in for loop until QRadioButton get checked everytime? - python

I have a situation where i need to get Pass/Fail from tester for every test step in PySide GUI. Now the data of testsuite i am running in for loop and trying to get current checked/unchecked state of QRadioButton in for loop based on which i will do further code processing.
My code is :-
for i in range(self.ui.hlfDataset_sa_lst.count()):
self.ui.pass_radio.setChecked(False)
self.ui.fail_radio.setChecked(False)
print "command ", str(self.ui.hlfDataset_sa_lst.item(i).text())
print "Run ", str(i)+" is here"
##
self.telnetThread = TelnetThread.SocketTunnel("localhost",2000)
returnCommand = self.telnetThread.communicateSock(str(self.ui.hlfDataset_sa_lst.item(i).text()))
print "returnCommand ",returnCommand
##XML Data structure
result = ET.SubElement(results,"result")
testcasestepno = ET.SubElement(result,"testcasestepno")
testerComment = ET.SubElement(result,"testerComment")
testresult = ET.SubElement(result,"testresult")
mguImage = ET.SubElement(result,"mguImage")
if self.ui.pass_radio.isChecked():
print "TC passed "
testcasestepno.text = str(i+1)
testresult.text = "PASS"
mguImage.text = "NA"
testerComment.text=str(self.ui.testercomment_txt.text())
elif self.ui.fail_radio.isChecked():
if not str(self.ui.testercomment_txt.text()):
QtGui.QMessageBox.critical(self, 'Tester Comment ', 'Tester Comment is desired ', QtGui.QMessageBox.Ok)
self.ui.pass_radio.setChecked(False)
self.ui.fail_radio.setChecked(False)
else:
print "TC failed "
testcasestepno.text = str(i+1)
testresult.text = "FAIL"
testerComment.text = str(self.ui.testercomment_txt.text())
#Save Live Image when failed
I want for loop to wait until tester has provided the input and i don't want to put sleep or in anyway to use thread unless convenient way is shown.
This code runs complete loop without waiting for input.

If I understood you correctly, you want to wait until one of buttons (fail_radio or pass_radio) is checked before if self.ui.pass_radio.isChecked(): line.
In Qt, you can achieve this using QEventLoop like here:
waiting for a signal, where signal you want to wait for is clicked. You need to connect both buttons' signals to quit slot before executing it. For signal/slot connecting in PyQt you can look here:
http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html
So you need to write something like:
loop = QtCore.QEventLoop()
self.ui.fail_radio.clicked.connect(loop.quit)
self.ui.pass_radio.clicked.connect(loop.quit)
loop._exec()

Related

How Can I Print the Contents of my Tkinter Window to a Printer

I made an App to process and display some data in a Tkinter window. I now want to send the contents of the window to a printer for printing on actual paper. However I don't really see any libraries in tkinter or Python to do this. I have to confess I am very new to tkinter and Python.....
Can anyone point me in the right direction?
Thanks.
tkinter is for a graphics user interface and so is all about display. To print data in a tkinter widget you'd have to retrieve that data depending on what the widget is and put it on the clipboard (can do this in tkinter) or file it (in a separate function) and use a separate printing app to print.
(edited as per comment)
This code does much the same as the subprocess module in a minimalist fashion since you have a specific task on Windows. To test it needs a pdf filepath inserted so I've put in an example that brings up notepad just so it can run as it is.
This has an alternative to checking for print status by use of a manual pause. Then Adobe (or any executable that has the appropriate print facility) can be closed automatically. I'd expect the manual pause to be replaced by an automatic timer set for an estimate time for a document to print. Probably need to consider only the time needed to transfer the document into the printing buffer - but that is up to how you want to operate with your system.
"""Process to start external executable.
. default is to let process run until parent pause is complete then process is terminated in parent,
.. this allows time for a process started im the child like printing to finish.
. option to wait until process has finished before returning to parent.
(proc.py)
"""
import _winapi as win
from os import waitpid
from sys import exc_info as ei
def startproc(exe,cmd, wait=False):
try:
ph, th, pid, tid = win.CreateProcess(exe,cmd,None,None,1,0,None,None,None)
win.CloseHandle(th)
except:
print(ei()[1])
ph = 0
return (ph,'error')
if ph > 0:
if not wait:
return (ph,'process still going')
else:
pid, exitstatus = waitpid(ph,0)
return (0,'process done')
#exe = "C:\\Program Files\\Adobe\\Acrobat DC\\Acrobat\\Acrobat.exe"
#cmd = "open <pdf filepath>"
exe = "C:\Windows\System32\\notepad.exe"
cmd = None
print(__doc__)
proc,msg = startproc(exe,cmd)
print(msg)
if 'done' not in msg: # manual pause for printing
input('\n-- carry on --\n') # could be automatic timer
if msg != 'error' and proc != 0:
if win.GetExitCodeProcess(proc) == win.STILL_ACTIVE:
win.TerminateProcess(proc,0)
if 'done' not in msg: print('process closed')
#can delete pdf here
input('\n--- finish ---\n')

Dearpygui status box not updating properly

I am using dearpygui as an interface for a webscraping tool. I have a "status box" which I want to use to communicate messages to the user. It is setup as a read-only, multi-line input text box and is designed to update with the old value and append the new message. If I run the program, it will work but the updates to the status box do not show up until the webscraping(download_reports function) is finished. The gui is not updating each time the update_status function is called. What is the best way to get this to update and display when called and not when the entire process has finished?
def window_month_end_reports(sender, data):
with window('Month End'):
for building in buildings:
add_checkbox(building)
add_spacing()
add_button("Done", callback=run_month_end_reports)
add_spacing()
add_separator()
add_text("Select reports")
for report in reports_list:
add_checkbox(report)
def run_month_end_reports(sender, data):
item_list = []
building_list = []
delete_item('Month End')
for item in reports_list: # LIST OF REPORTS SELECTED
if get_value(item):
item_list.append(item)
for building in buildings:
if get_value(building):
building_list.append(building)
update_status('Running month end reports')
download_reports(building_list, item_list)
def update_status(message):
set_value('##status box', get_value('##status box') + str(message) + '\n')
with window("Main Window"):
add_button("Month End Reports", callback=window_month_end_reports)
add_text("Status Box:")
add_input_text("##status box", readonly=True, multiline=True, height=500)
start_dearpygui(primary_window="Main Window")
Probably, the best way to solve this is to use an async task to complete the download reports function. You could use run_async_function to launch the download. You can find an example of the long task management in the documentation: async functions

Multiple stdout w/ flush going on in Python threading

I have a small piece of code that I made to test out and hopefully debug the problem without having to modify the code in my main applet in Python. This has let me to build this code:
#!/usr/bin/env python
import sys, threading, time
def loop1():
count = 0
while True:
sys.stdout.write('\r thread 1: ' + str(count))
sys.stdout.flush()
count = count + 1
time.sleep(.3)
pass
pass
def loop2():
count = 0
print ""
while True:
sys.stdout.write('\r thread 2: ' + str(count))
sys.stdout.flush()
count = count + 2
time.sleep(.3)
pass
if __name__ == '__main__':
try:
th = threading.Thread(target=loop1)
th.start()
th1 = threading.Thread(target=loop2)
th1.start()
pass
except KeyboardInterrupt:
print ""
pass
pass
My goal with this code is to be able to have both of these threads displaying output in stdout format (with flushing) at the same time and have then side by side or something. problem is that I assume since it is flushing each one, it flushes the other string by default. I don't quite know how to get this to work if it is even possible.
If you just run one of the threads, it works fine. However I want to be able to run both threads with their own string running at the same time in the terminal output. Here is a picture displaying what I'm getting:
terminal screenshot
let me know if you need more info. thanks in advance.
Instead of allowing each thread to output to stdout, a better solution is to have one thread control stdout exclusively. Then provide a threadsafe channel for the other threads to dispatch data to be output.
One good method to achieve this is to share a Queue between all threads. Ensure that only the output thread is accessing data after it has been added to the queue.
The output thread can store the last message from each other thread and use that data to format stdout nicely. This can include clearing output to display something like this, and update it as each thread generates new data.
Threads
#1: 0
#2: 0
Example
Some decisions were made to simplify this example:
There are gotchas to be wary of when giving arguments to threads.
Daemon threads terminate themselves when the main thread exits. They are used to avoid adding complexity to this answer. Using them on long-running or large applications can pose problems. Other
questions discuss how to exit a multithreaded application without leaking memory or locking system resources. You will need to think about how your program needs to signal an exit. Consider using asyncio to save yourself these considerations.
No newlines are used because \r carriage returns cannot clear the whole console. They only allow the current line to be rewritten.
import queue, threading
import time, sys
q = queue.Queue()
keepRunning = True
def loop_output():
thread_outputs = dict()
while keepRunning:
try:
thread_id, data = q.get_nowait()
thread_outputs[thread_id] = data
except queue.Empty:
# because the queue is used to update, there's no need to wait or block.
pass
pretty_output = ""
for thread_id, data in thread_outputs.items():
pretty_output += '({}:{}) '.format(thread_id, str(data))
sys.stdout.write('\r' + pretty_output)
sys.stdout.flush()
time.sleep(1)
def loop_count(thread_id, increment):
count = 0
while keepRunning:
msg = (thread_id, count)
try:
q.put_nowait(msg)
except queue.Full:
pass
count = count + increment
time.sleep(.3)
pass
pass
if __name__ == '__main__':
try:
th_out = threading.Thread(target=loop_output)
th_out.start()
# make sure to use args, not pass arguments directly
th0 = threading.Thread(target=loop_count, args=("Thread0", 1))
th0.daemon = True
th0.start()
th1 = threading.Thread(target=loop_count, args=("Thread1", 3))
th1.daemon = True
th1.start()
# Keep the main thread alive to wait for KeyboardInterrupt
while True:
time.sleep(.1)
except KeyboardInterrupt:
print("Ended by keyboard stroke")
keepRunning = False
for th in [th0, th1]:
th.join()
Example Output:
(Thread0:110) (Thread1:330)

Python GPIO raspberry pi

So bassicaly the user will press the picture_pin buton first, then this calls the picture_taking() function which then it should stop and wait for either (Accept_Pin or Decline_Pin) buttons to be pressed, it should not let the user to continue unless a selection is made. so when the user makes his/her selection then it go back and wait for the picture_pin button. at this stage the Accept_Pin and Decline_Pin should have no affect at all.
I have a python program that waits for a button press from the user then it runs a function to do its thing. what I would like to accomplish is, in that function I would like to also wait for another button press.
(Main.py)
----etc
## PICTURE FUNCTION ##
def picture_taking():
.....etc
returnvalue = subprocess.check_output("sudo ./" + config.layout + ".sh", shell=True)
GPIO.wait_for_edge(Accept_pin, GPIO.FALLING)
GPIO.wait_for_edge(Decline_Pin, GPIO.FALLING)
pad1alreadyPressed = False
pad4alreadyPressed = False
while True:
pad1pressed = not GPIO.input(Accept_pin)
pad4pressed = not GPIO.input(Decline_Pin)
if pad1pressed and not pad1alreadyPressed:
print "Accepted photo:" + str(returnvalue)
pad1alreadyPressed = pad1pressed
if pad4pressed and not pad4alreadyPressed:
print "Declined photo:" + str(returnvalue)
pad4alreadyPressed = pad4pressed
(This here is my Main Program)
#Main section
while True:
time.sleep(0.2)
#camera.hflip = false
camera.shutter_speed = 2000000000
camera.exposure_mode = 'off'
#camera.iso = 1000
camera.preview_fullscreen = True
camera.preview_alpha = 150
camera.start_preview()
GPIO.wait_for_edge(picture_pin, GPIO.FALLING)
picture_taking()
So in the picture_taking() function I would like to ask the user if they accept this picture or not
if they press button (GPIO 19) then they accept or (GPIO 6) as Decline
after they do there selection the program should go back and wait for the main button to select below. and these two buttons should only be selectable inside the function.
I tried this in the Picture_taking() function
when I make the selection it only accepts the "Decline_pin" button, but after I press the "Decline button" then it reads "Accept button".
The other issue is that it does not go back and wait for the Main button "picture_pin" to be pressed. it seems to be stuck here and not exiting.
I am not sure if this is something to do with Indent stuff in Python.
Thank you.
(This should be a comment, not an answer but I don't have reputation 50 yet).
Is this your actual code? I can't understand how it ever returns from the while True: clause in picture_taking(). I'd think you'd need to have something like
while (!(pad1alreadyPressed or pad4alreadyPressed)):

Ping every second and Tkinter Button

I would like to ping every second in my network a certain hostname and change in return the name of the corresponding button.
For now I have this :
import tkinter as tk
import time
# variables
hostname = ("ASUS-PC")
mot= "inactif"
class test(tk.Tk):
# make buttons on grid
def __init__(self):
tk.Tk.__init__(self)
self.button = list()
for i in range(10):
i=i+1
RN = ('RN '+str(i))
self.button.append(tk.Button(text=RN))
self.button[-1].grid(row=0,column=i)
# ping hostname every second
def ping(self):
import subprocess
import os
result=subprocess.Popen(["ping", "-n", "1", "-w", "200", hostname],shell=True).wait()
if result == 0:
print (hostname, "active")
else:
B = self.button[0]
B ['text'] = mot
time.sleep(1)
while True:
ping()
app = test ()
app.mainloop()
It doesn't work and I don't know why. At beginning it was a "self" problem but now it seems to be related to how I ping every second (I took it from there What is the best way to repeatedly execute a function every x seconds in Python?) If someone know the answer...
Thanks for your help
The reason your code "doesn't work" is that you have an infinite loop that calls sleep. This prevents the event loop from processing any events, including events that tell Tkinter to refresh the display. Your program is actually working, you just can't see any results.
The solution is to use after to call your function once a second. Between those calls, tkinter will have time to update the display without you having to do any extra work.
All you need to do is remove the call to sleep, and add a call to after. Once you do that, remove your while loop, and call this function once. Tkinter will then call this function once every second (approximately)
It looks something like this:
def ping(self):
<all your other code>
self.after(1000, self.ping)
It looks a bit like recursion, but it's not. You're simply adding an event on the queue of events managed by Tkinter. When the time comes, it pulls the item off of the queue and executes it.
Thanks a lot everyone ! Now it works :
...
# ping hostname every second
def ping(self):
import subprocess
import os
result=subprocess.Popen(["ping", "-n", "1", "-w", "200", hostname],shell=True).wait()
if result == 0:
print (hostname, "active")
else:
print (hostname, "inactive")
B = self.button[0]
B ['text'] = mot
self.after(1000, self.ping)
app = test ()
app.ping()
app.mainloop()

Categories