Hello I have two function. One Class is a watchdog and the other class is a pyqt gui. I have three QTextBrowser.
If I connect a button to the function in the QT Class and call the function my TextBrowser get updated normally.
If I trigger an event in the watchdog and the watchdog class calls my QT class, my TextBrowser didnt update.
This is how I call the function from another class
class Handler(FileSystemEventHandler):
#staticmethod
def on_any_event(event):
if event.is_directory:
return None
elif event.event_type == 'created':
# Event is created, you can process it now
print("Watchdog received created event - % s." % event.src_path)
window = MyWindow()
window.start_xl()
This is the function, which works when i call it with a button.
def update(self):
terminate('cmd.exe')
terminate('EXCEL.exe')
self.text_Browser = self.ui.textBrowser
self.text_Browser_2 = self.ui.textBrowser_2
self.text_Browser_3 = self.ui.textBrowser_3
self.text_Browser.setTextColor(QtGui.QColor('white'))
self.text_Browser_2.setTextColor(QtGui.QColor('white'))
self.text_Browser_3.setTextColor(QtGui.QColor('white'))
path = "C:/Program Files (x86)/STIHL/Faps/Temp"
# Check if the folder is empty
if os.listdir(path):
# Get a list of all files in the directory
files = os.listdir(path)
# The first file in the directory
first_file = files[0]
self.text_Browser.append("FINISHED")
self.text_Browser_2.append("goal_dir")
self.text_Browser_3.append(first_file)
else:
self.ui.label.setText("Ordner ist Leer")
pass
This is the function which is called by the class Handler. Everything is working besides the updating of the TextBrowser
def start_xl(self):
terminate('cmd.exe')
terminate('EXCEL.exe')
self.text_Browser = self.ui.textBrowser
self.text_Browser_2 = self.ui.textBrowser_2
self.text_Browser.setTextColor(QtGui.QColor('white'))
self.text_Browser_2.setTextColor(QtGui.QColor('white'))
print(self.text_Browser)
print(self.text_Browser_2)
# QtCore.QMetaObject.invokeMethod(self.text_Browser, "append", QtCore.Qt.QueuedConnection,
# QtCore.Q_ARG(str, "FINISHED"))
# QtCore.QMetaObject.invokeMethod(self.text_Browser_2, "append", QtCore.Qt.QueuedConnection,
# QtCore.Q_ARG(str, "goal_dir"))
self.text_Browser.setPlainText("FINISHED")
# self.text_Browser_2.append("goal_dir")
I tried it with invoke and append. The kill process get started, so the function is called.
Is there something I should consider?
Related
I have created a UI with PyQt5. I can use it on Windows and it works perfectly, but when I try to use it on MacOS I get stuck trying to close it (with self.close()). Using the PyCharm debugger I found out that after self.close() it jumps to app.exec_() and the function that was entered to close it is executed again (for example on_later_button_clicked(self)). I have also already tried sys.exit(app.exec_()).
Here is my code:
import os
import sys
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QApplication, QDialog
from PyQt5.uic import loadUi
from Modules.database import addNeverID
from Modules.supportedWebsites import getWebsites
def Start():
m = askForPartnerUrl()
# m.setFixedSize(500,500)
m.show()
return m
class askForPartnerUrl(QDialog):
def __init__(self):
super(askForPartnerUrl, self).__init__()
loadUi('lib/askForPartnerURL.ui', self)
self.setWindowTitle('Upload')
current_id = getFromFile("id.txt")
self.show_id.setText(current_id)
self.show_origin_url.setText(
'' + getFromFile("origin_url.txt") + '')
self.show_origin_url.setOpenExternalLinks(True)
id_beginns = ["1"]
website_eq = ["1"]
website_guess_str = "Nicht verfügbar!"
for i in range(len(id_beginns)):
if id_beginns[i] in current_id:
website_guess_str = '' + website_eq[i] + ''
self.website_guess.setOpenExternalLinks(True)
break
self.website_guess.setText(website_guess_str)
self.save_button.clicked.connect(self.on_save_button_clicked)
self.later_button.clicked.connect(self.on_later_button_clicked)
self.never_button.clicked.connect(self.on_never_button_clicked)
try:
os.remove('temp/currentObject/partner_url.txt')
except:
pass
#pyqtSlot()
def on_never_button_clicked(self):
addNeverID(getFromFile("id.txt"))
saveToFile("Never-ID", "partner_url.txt")
self.close()
def on_later_button_clicked(self):
saveToFile("Later-ID", "partner_url.txt")
self.close()
def on_save_button_clicked(self):
url_is_valid = False
for i in getWebsites():
if i in self.partner_url_input.text():
url_is_valid = True
break
if url_is_valid:
saveToFile(self.partner_url_input.text(), "partner_url.txt")
self.close()
else:
error_dialog = QtWidgets.QErrorMessage(self)
error_dialog.setWindowTitle("Eingabe nicht verwertbar")
error_dialog.showMessage('Die eingegebene URL ist nicht verwendbar! Bitte prüfe deine Eingabe.')
def showGUI():
app = QApplication(sys.argv)
app.setStyle('Fusion')
app.setWindowIcon(QtGui.QIcon('lib/icon.png'))
window = Start()
app.exec_()
def saveToFile(content, filename):
file = open("temp/currentObject/" + filename, "w+")
file.write(content)
file.close()
def getFromFile(filename):
file = open("temp/currentObject/" + filename)
content = file.read()
file.close()
return content
Many thanks in advance
The reason is that since you're using uic, it automatically enables the auto-connection feature, which automatically detects function names based on object/signals names and connects them, even if the functions do not have Qt slots decorators.
The result is that your slot will be actually called thrice:
without any argument (clicked());
with the checked argument (clicked(bool)): the argument is ignored by Qt since the function doesn't take any, but the function will be called anyway because no slot signature has been specified for it;
again with the checked argument, because you manually connected it in your code;
If you want to keep using the auto connection, use a unique slot decorator for that specific function, otherwise manually connect to a function (possibly with a slot, if you need a specific signature) that does not use the auto connection naming, but don't use both.
class askForPartnerUrl(QDialog):
def __init__(self):
super(askForPartnerUrl, self).__init__()
loadUi('askForPartnerURL.ui', self)
# ...
# remove the following lines:
# self.save_button.clicked.connect(self.on_save_button_clicked)
# self.later_button.clicked.connect(self.on_later_button_clicked)
# self.never_button.clicked.connect(self.on_never_button_clicked)
# manual connection
self.later_button.clicked.connect(self.saveLater)
# using the auto connection; the function doesn't need arguments, so
# you can ignore the argument type signature
#pyqtSlot()
def on_never_button_clicked(self):
addNeverID(getFromFile("id.txt"))
# ...
# with a normal function; in this case no slot decorator is required since
# you don't have arguments
def saveLater(self):
url_is_valid = False
# ...
PS: The reason for which it gets "stuck" is probably due to the way Python deals with the end of the program (which by default happens as soon as the last window is closed in Qt) on MacOS: after the first call to close() PyQt tries to quit the QApplication (free up memory, etc...), but while doing so the original click event is still in the process of firing the signals to the remaining second and third slot, hence the "loop" (but it's not an actual loop, and the third slot never gets called because it's the second one that blocks everything).
Note that this is a big oversimplification, I'm not an expert in memory usage and low level programming, but this is fundamentally what's happening.
I am very new to python. I was trying to pass value from one method to another within the class. I searched about the issue but i could not get proper solution. Because in my code, "if" is calling class's method "on_any_event" that in return should call my another method "dropbox_fn", which make use of the value from "on_any_event". Will it work, if the "dropbox_fn" method is outside the class?
I will illustrate with code.
class MyHandler(FileSystemEventHandler):
def on_any_event(self, event):
srcpath=event.src_path
print (srcpath, 'has been ',event.event_type)
print (datetime.datetime.now())
#print srcpath.split(' ', 12 );
filename=srcpath[12:]
return filename # I tried to call the method. showed error like not callable
def dropbox_fn(self)# Or will it work if this methos is outside the class ?
#this method uses "filename"
if __name__ == "__main__":
path = sys.argv[1] if len(sys.argv) > 1 else '.'
print ("entry")
event_handler = MyHandler()
observer = Observer()
observer.schedule(event_handler, path, recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
The main issue in here is.. I cannot call "on_any_event" method without event parameter. So rather than returning value, calling "dropbox_fn" inside "on_any_event" would be a better way. Can someone help with this?
To call the method, you need to qualify function with self.. In addition to that, if you want to pass a filename, add a filename parameter (or other name you want).
class MyHandler(FileSystemEventHandler):
def on_any_event(self, event):
srcpath = event.src_path
print (srcpath, 'has been ',event.event_type)
print (datetime.datetime.now())
filename = srcpath[12:]
self.dropbox_fn(filename) # <----
def dropbox_fn(self, filename): # <-----
print('In dropbox_fn:', filename)
I have a program which will check for several conditions and check whether data is available or not. If there is any missing data then i will popup another window which will collect data in that window. It will have two buttons (Apply and Close). I want to return a value after button is triggered.
Both program.py and dataEntry.py have there own UIs designed in PyQt Disigner.
I want my program to wait for return value from other window. and depending on the input i will continue my other process.
Lets say program file is program.py and another window is dataEntry.py is imported in program.py
My dataEntry.py looks like
#imports necessary modules
class dataEntry(QtGui.QMainWindow,Ui_DataEntry):
def __init__(self):
super(dataEntry,self).__init__()
self.setupUi(self)
self.Btn_Apply.clicked.connect(self.ApplyChanges)
self.Btn_Close.clicked.connect(self.CancelChanges)
def ApplyChanges(self):
#This will trigger when ApplyButonn is clicked
#I want to return True value from here
return True
def CancelChanges(self):
#This will trigger when CancelButonn is clicked
#I want to return False value from here
return False
My program.py looks like
from dataEntry import dataEntry
class MainApp(QtGui.QMainWindow,Ui_MainApp):
def __init__(self):
super(MainApp,self).__init__()
self.setupUi(self)
self.CheckDetails()
def CheckDetails(self):
#Here i will check if required data is present else i will take data from dataEntry class
if checkFails:
input = dataEntry()
input.show()
#Here i want this class to wait until i get the result from dataEntry class
EntryResult = return value from dataEntry
if EntryResult:
#Do some thing when its True
else:
#Do some thing when its False
first of all import dataentry.py in program.py,
after this in your program.py
EntryResult = dataentry.py.Ui_DataEntry() #considering that the UI class in dataentry.py is Ui_DataEntry
This will run the dataentry.py and make your dataentry.py return the required value. This way, the program.py will wait till it gets a value from dataentry.py
In my PyQt4 application, there is a functionality that allows users to save a avi file.
To this aim, a saveMovie method has been implemented in the main window:
def saveMovie(self):
""" Let the user make a movie out of the current experiment. """
filename = QtGui.QFileDialog.getSaveFileName(self, "Export Movie", "",
'AVI Movie File (*.avi)')
if filename != "":
dialog = QtGui.QProgressDialog('',
QtCore.QString(),
0, 100,
self,
QtCore.Qt.Dialog |
QtCore.Qt.WindowTitleHint)
dialog.setWindowModality(QtCore.Qt.WindowModal)
dialog.setWindowTitle('Exporting Movie')
dialog.setLabelText('Resampling...')
dialog.show()
make_movie(self.appStatus, filename, dialog)
dialog.close()
My idea is to use a QProgressDialog to show how the video encoding work is proceeding.
Nevertheless, after the selection of the filename, the QFileDialog won't disappear and the entire application stays unresponsive until the make_movie function has completed.
What should I do to avoid this?
Lesson learned: if you have some long-running operations to do -- for example, reading or writing a big file, move them to another thread or they will freeze the UI.
Therefore, I created a subclass of QThread, MovieMaker, whose run method encapsulates the functionality previosly implemented by make_movie:
class MovieMaker(QThread):
def __init__(self, uAppStatus, uFilename):
QtCore.QThread.__init__(self, parent=None)
self.appStatus = uAppStatus
self.filename = uFilename
def run(self):
## make the movie and save it on file
Let's move back to the saveMovie method. Here, I replaced the original call to make_movie with the following code:
self.mm = MovieMaker(self.appStatus,
filename)
self.connect(self.mm, QtCore.SIGNAL("Progress(int)"),
self.updateProgressDialog)
self.mm.start()
Note how I defined a new signal, Progress(int).
Such a signal is emitted by the MovieMaker thread to update the QProgressDialog used to show the user how the movie encoding work is progressing.
I have a GUI designed in glade, using python/gtk in the background.I want to handle the delete event and display a "Are you sure?"-message dialog.I have been trying to handle the delete and destroy events, but failing to do so.any light?
#!/usr/bin/python
import .... stuff
class App:
def __init__(self):
self.gladefile = 'test.glade'
windowname = 'window'# This must match the window name in glade
self.wTree = gtk.glade.XML(self.gladefile, windowname)# object for acessing widgets
dic={
# Also need to set project2's signal tab
'on_window_delete_event':self.on_erro,
'on_window_destroy_event':self.on_erro,
}
self.wTree.signal_autoconnect (dic)
self.op=self.wTree.get_widget('window')
self.op.show()
def on_erro(self,widget,*args):
print 'hello'
app = App()
gtk.main()
This code opens a simple window .On clicking on close button, it prints hello and exits.(I want the window to remain open)
You have to return True in order to stop propagation of the delete event in the callback on_erro as mentioned in the documentation for "delete-event". In your current code, the callback is not returning any boolean value as required by the function, which I am guessing is returning False (Please check the signature for on_window_delete_event callback functions, the return type is boolean)
Hope this helps!