How to reopen a dialog box in PyQt5 - python

I'm trying to use a dialog box in order to report an error to the user. It seems to be working if there is one error although when there are multiple it doesn't reopen when closed with the next error and instead crashes.
def errordialog(self, errormessage):
self.errordialog = QMessageBox()
self.errordialog.addButton("OK", 0)
self.errordialog.setText(errormessage)
self.errordialog.exec()
And this is the main program
def validate_data(data, regex):
if re.match(regex, data, re.VERBOSE):
error = False
else:
errormessage = "ERROR"
print("0")
self.errordialog(errormessage)
print("1")
self.errordialog.accept() # I added this in while trying to solve the issue
print("2")
error = True
return error
data = supplierid
regex = "[A-Z]$"
error = validate_data(data, regex)
print("3")
data = suppliername
regex = ".(1,50)$"
error = validate_data(data, regex)
print("4")
It prints 0,1,2,3,0 and then crashes
the error message is object QMessageBox is not callable

After calling this line of code self.errordialog(errormessage), you go into the errordialog function. However, inside the errordialog function, you have redefined self.errordialog so that it is of class QMessageBox instead of class function, so when it goes through the validation the second time, you attempt to call the QMessageBox, which does not work.
Simply changing the function or variable names will solve this problem.

Related

gradio refresh interface when selecting File

I'm trying to create a gradio User Interface which does the following
on the left panel I have a File control, that allows the selection of a local file (eg. a .csv)
when a file is selected a "Process" button should be made visible
when the "Process" button is pressed, a function is called, reading the contents of the file, and processing it in some ways, resulting in a string
the resulting string is shown in a TextArea in the right column
I'm stuck implementing point 2. I can select the file, but can't make the Process button become visible.
This is my code so far (not yet implementing points 3. a:
import gradio as gr
def file_selected(file_input):
print("yes, file_selected is invoked")
print(process_button)
process_button.visible=True
demo.render()
return process_button
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Data")
file_input = gr.File(label="Select File")
process_button = gr.Button("Process", visible=False)
with gr.Column(scale=2, min_width=600):
gr.Markdown("### Output")
result_display = gr.TextArea(default="", label="Result", lines=10, visible=False)
file_input.change(fn=file_selected, inputs=file_input, outputs=process_button)
if __name__ == "__main__":
demo.launch()
I see that at file selection the message is printed (and print(process_button) prints "button" so I'm sure this variable is not None), but the button doesn't appear on the page.
edited: fixed some errors not directly related to the problem.
There were many problems with the code (I fixed those not related with the main issue in the original post), but in the end what solved my problem (making the button visible) was that instead to rerender,
def file_selected():
...
process_button.visible=True
demo.render()
I just had to return the process_button.update
def file_selected(file_input):
...
return gr.update(visible=True)
(Actually this was documented in gradio's online docs; sorry, I didn't notice it before)
This is the complete working code:
import gradio as gr
def file_selected(file_input):
print("yes, file_selected is invoked")
print(process_button)
return gr.update(visible=True)
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Data")
file_input = gr.File(label="Select File")
process_button = gr.Button("Process", visible=False)
with gr.Column(scale=2, min_width=600):
gr.Markdown("### Output")
result_display = gr.TextArea(default="", label="Result", lines=10, visible=False)
file_input.change(fn=file_selected, inputs=file_input, outputs=process_button)
if __name__ == "__main__":
demo.launch()

PyQt5 - stuck in a loop while trying to close ui using macOS

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.

QListWidget item text is not returning with If statement

I have a QListWidget. I am running this function on itemClicked, and this function is also called from different part of my program. So this function has optional argument cutrrentItemText. for some reason my code is not working. Check below example.
def loadSomething(self,currentItemText=None):
if not currentItemText:
item = self.listWidget.currentItem()
currentItemText = item.text()
print currentItemText
#result from above code
<PySide2.QtWidgets.QListWidgetItem object at 0x7f910b112e60>
instead of item text it assigns item object. Here is code without if statement which is working like charm.
def loadSomething(self,currentItemText=None):
#if not currentItemText:
item = self.listWidget.currentItem()
currentItemText = item.text()
print currentItemText
#result of this give currentItems text
I am wondering where I am making mistake. Can any one tell me whats wrong in this code??
Note: I am trying this in Foundry nuke. Trying a custom python panel.
Update:
In my main widget init i have this to connect itemClicked event
self.listWidget.itemClicked.connect( self.loadSomething )
Resolved:
I just realized, itemClicked event sends current item object while call back. so first argument should be item,
def loadSomething(self,item,currentItemText=None)
above change worked
Try this code (I tested it in NukeX 12.0v3 on Catalina):
from PySide2 import QtWidgets, QtGui
import nuke
def loadSomething(currentItemText=None):
if not currentItemText:
item = QListWidget.currentItem()
currentItemText = item.text()
print currentItemText
loadSomething(currentItemText="Some")

python: class instance can't see self attribute

In my project i use module from known bt_manager to decode sbc audio stream. This module is python wrap for C-functions from rtpsbc library.
class SBCCodec:
def __init__(self, config):
import sys
try:
self.codec = ffi.verify(b'#include "rtpsbc.h"',
libraries=[b'rtpsbc'],
ext_package=b'rtpsbc')
except:
print 'Exception:', sys.exc_info()[0]
self.config = ffi.new('sbc_t *')
self.ts = ffi.new('unsigned int *', 0)
self.seq_num = ffi.new('unsigned int *', 0)
self._init_sbc_config(config)
self.codec.sbc_init(self.config, 0)
When i try to create SBCCodec class instance it gives me:
AttributeError: SBCCodec instance has no attribute 'codec'
You can see this attribute in the piece of code i posted above. It works with ffi-methods (ffi.verify, ffi.new). When i input those commands in ipython everything works correct without errors.
What have i missed?
As #Torxed has already mentioned the only way this would happen is if ffi.verify inside your try block throws an exception. If that happens self.codec will not be initialised. If that happens your code does not rethrow the exception and continues as normal after simply printing (which is not clean behaviour). The final statement then tries to call self.codec.config.sbc_init, that is it assumes that self.codec is already intialised, which is incorrect in this particular case and that is why you get the AttibuteError.
If you want to create the instance anyway regardless of the failure for ffi.verify at the start of init define self.codec = None and in your final statement insert a check such as:
if (self.codec != None ):
self.codec.sbc_init(self.config, 0)
Hope that helps.

Handling delete event in pygtk/glade

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!

Categories