Dearpygui status box not updating properly - python

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

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')

Waiting in for loop until QRadioButton get checked everytime?

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()

action callback for libnotify not working

I am trying to develop a desktop notification system with python and Libnotify.
I found this tutorial and tried the example with an action callback, below is my code modification
#initialization of libnotify
Notify.init("Py-Notification")
#creating object
summary = "Wake Up!"
body = "Meeting at 9pm"
notification = Notify.Notification.new(
summary, body
)
# Define a callback function
def my_callback_func():
webbrowser.open('http://google.com')
#adding actions
notification.add_action(
"action_click",
"Reply to Alarm",
my_callback_func,
None # Arguments
)
notification.show()
The callback function is not called whenever I click on the "Reply to Alarm" button
Any help.
You need to integrate with D BUS to receive events from your notifications.
Here is good explanation use Glib for it.

Kivy: How to create a 'blocking' popup/modalview?

I did find a question on this on stackoverflow, here, but I find it just doesn't answer the question, as for me, neither the Popup nor the ModalView actually 'blocks'. What I mean is, execution is moving through a function, like:
def create_file(self):
modal = ModalView(title="Just a moment", size_hint=(0.5, 0.5))
btn_ok = Button(text="Save & continue", on_press=self.save_file)
btn_no = Button(text="Discard changes", on_press=modal.dismiss)
box = BoxLayout()
box.add_widget(btn_ok)
box.add_widget(btn_no)
modal.add_widget(box)
modal.open()
print "back now!"
self.editor_main.text = ""
new = CreateView()
new.open()
And the print statement prints "back now!" and the rest of the function is immediately executed, despite the fact the ModalView just opened. I also tried this using a Popup instead of a ModalView, with the same result. I would like execution in the function to pause while I interact with the Popup/ModalView. Is there a way for this to be done built into kivy? Must I use threads? Or will I need to just find some other workaround?
You can't block like that, as that would stop the event loop and you wouldn't be able to interact with your app anymore. The easiest fix is to split this into two functions, and use on_dismiss to continue:
def create_file(self):
modal = ModalView(title="Just a moment", size_hint=(0.5, 0.5))
btn_ok = Button(text="Save & continue", on_press=self.save_file)
btn_no = Button(text="Discard changes", on_press=modal.dismiss)
box = BoxLayout()
box.add_widget(btn_ok)
box.add_widget(btn_no)
modal.add_widget(box)
modal.open()
modal.bind(on_dismiss=self._continue_create_file)
def _continue_create_file(self, *args):
print "back now!"
self.editor_main.text = ""
new = CreateView()
new.open()
It's also possible to use Twisted to make the function asynchronous, though that's a little more complicated.

How to start a "drawing loop" in PyQt?

Often times when we're drawing a GUI, we want our GUI to update based on the data changing in our program. At the start of the program, let's say I've drawn my GUI based on my initial data. That data will be changing constantly, so how can I redraw my GUI constantly?
The best way that I have found to do this is to run your core program in a QThread and use signals to communicate with your gui. Here is an example where I update a progress dialog as my main program does some stuff.
Here is a code excerpt from a project that I was working on. The basic idea is that I am adding a number of files to a library object and updating the progress as the files are added.
The action is started by the Library class. The tread that does the actual work is in the AddFilesThread.
Let me know if this is helpful. If you need I can try to put together a working example instead of a code excerpt.
If you want to see the full code that I used go here: hystrix_library.py. The diaglog class that I used is in that file. I can't say that this is necessarily the best way to do things, but it works well and is fairly easy to read.
class Library(QtCore.QObject):
"""
This class is used to store information on the libraries.
"""
def __init__(self):
QtCore.QObject.__init__(self)
def importUrls(self, url_list):
# Create a progress dialog
self.ui_progress = AddUrlsProgressDialog()
self.ui_progress.show()
self.ui_progress.raise_()
# Create the add files thread object.
self.add_files_thread = AddFilesThread()
# Connect the thread to the dialog.
self.connect(self.add_files_thread
,QtCore.SIGNAL('updateDialog')
,self.ui_progress.setDialog)
self.connect(self.add_files_thread
,QtCore.SIGNAL('updateValue')
,self.ui_progress.setValue)
self.connect(self.add_files_thread
,QtCore.SIGNAL('finished')
,self.ui_progress.setFinished)
self.connect(self.add_files_thread
,QtCore.SIGNAL('canceled')
,self.ui_progress.closeNow)
# Connect the dialog to the thread
self.connect(self.ui_progress
,QtCore.SIGNAL('cancel')
,self.add_files_thread.cancelRequest)
# Start the thread
self.add_files_thread.start()
class AddFilesThread(QtCore.QThread):
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
self.cancel_request = False
def __del__(self):
self.wait()
def run(self):
try:
self.main()
except:
print 'AddFilesThread broke yo.'
self.cancelNow(force=True)
traceback.print_exc()
def main(self):
num_added = 0
for local_path in self.path_list:
# First Setup the dialog
status_label = 'Finding files to add . . .'
dialog_update = (status_label, (0,0), 0)
self.emit(QtCore.SIGNAL('updateDialog'), dialog_update)
# Do a recursive search.
all_files = hystrix_file.getFiles()
num_files = len(all_files)
if self.cancelNow():
return
status_label = '%d files found.\nExtracting tags . . .' %(num_files)
dialog_update = (status_label, (0,num_files), 0)
self.emit(QtCore.SIGNAL('updateDialog'), dialog_update)
num_added = 0
for index, filename in enumerate(all_files):
try:
metadata = hystrix_tags.getMetadata(filename)
# Here I would add the metadata to my library.
except:
traceback.print_exc()
print('Could not extract Metadata from file.')
continue
# This should be sent to a progress widget
if index % 1 == 0:
self.emit(QtCore.SIGNAL('updateValue'), index)
# Check if a cancel signal has been recieved
if self.cancelNow():
return
status_label = 'Finished. Added %d files.' %(num_added)
dialog_update = ( status_label, (0,num_added), num_added)
self.emit(QtCore.SIGNAL('updateDialog'), dialog_update)
self.emit(QtCore.SIGNAL('finished'))
def cancelRequest(self):
self.cancel_request = True
def cancelNow(self, force=False):
if self.cancel_request or force:
self.emit(QtCore.SIGNAL('canceled'))
return True
else:
return False
You could create a thread to update the GUI constantly, just pass to it references to the graphical widgets that need to be updated

Categories