PyQt4 connect to signal "textValueChanged()" - python

I have a app that uses PyQt4 for GUI. But having some issues with connecting to signals.
I made a button like this
self.button=QtGui.QPushButton("Load File")
QObject.connect( self.button, SIGNAL('clicked ()'), self.clicked )
And it perfectly fires the following function:
def clicked(self):
So in the same manner i made a input element. However the input element signal does not fire when i change the text.
self.filter=QtGui.QInputDialog() #Create the Input Dialog
self.filter.setInputMode (self.filter.InputMode.TextInput ) #Change the input type to text
self.filter.setOption(self.filter.InputDialogOption.NoButtons,True) #I don't need the buttons so i have removed them
self.filter.setLabelText("Filter") #I change the label to "filter"
self.connect( self.filter, QtCore.SIGNAL("textValueChanged()"), self.filterUpdate ) #I connect to the signal textValueChanged() that should be fired when the text is changed and make it fire the filterUpdate() function
The following is never fired:
def filterUpdate(self):
print "Hello"

This works here:
from PyQt4 import QtCore, QtGui
import sys
app = QtGui.QApplication(sys.argv)
def filterUpdate():
print('!')
filter = QtGui.QInputDialog()
filter.setInputMode (filter.TextInput)
filter.setOption(filter.NoButtons, True)
filter.setLabelText("Filter")
filter.textValueChanged.connect(filterUpdate)
filter.show()
sys.exit(app.exec_())

Related

Printing some text in a Label, depending on textbox input - PyQT5

I need help figuring out how to use the value written in a textbox in PyQT5, and use that value to build an IF statement. Any suggestions on how to do it? I have tried to declare the text in the textbox as a variable and use it in the IF statement but I can't seem to figure it out how to do it properly, and every time i run the code, some exit code shows (-1073741819 (0xC0000005) ).
Summing up, can't use pass the value of the textbox to the variable in order to do an IF statement.
I had this code down below:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QTextEdit
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win.setGeometry(200, 200, 400, 400)
win.setWindowTitle("Register Program")
label = QtWidgets.QLabel(win)
label.setText("Random Text")
label.move(169, 15)
label2 = QtWidgets.QLabel(win)
label2.resize(300, 100)
label2.setText("1- Register new person\n2- See all regestries\n3- See last regestry\n\nPress ESC to exit\n")
label2.move(70, 50)
textbox = QtWidgets.QLineEdit(win)
textbox.setText("")
textbox.resize(250, 25)
textbox.move(70, 250)
button1 = QtWidgets.QPushButton(win)
button1.move(150, 300)
button1.setText("Submit")
button1.clicked.connect(clicked)
button2 = QtWidgets.QPushButton(win)
button2.move(150, 335)
button2.setText("Close")
button2.clicked.connect(close)
win.show()
sys.exit(app.exec_())
def clicked():
inpt = int(window().textbox.text)
if inpt == 1:
print("Hello")
def close():
sys.exit()
window()```
If you're just looking to get user input, there's a builtin static method you can call for requesting input of a particular type: https://doc.qt.io/qt-5/qinputdialog.html#getText
If you want to make your own widget however, you need to use the signals and slots to trigger a python method to store the value. This is easiest to do in a class. You can trigger the method whenever the text changes with the textChanged signal and do whatever you need to do with it.
(Note, I haven't run this as I don't have PyQt5 currently installed, but it should work)
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
# type: (QtWidgets.QWidget) -> None
super(Widget, self).__init__(parent)
self.line_edit = QtWidgets.QLineEdit()
main_layout = QtWidgets.QVBoxLayout()
main_layout.addWidget(self.line_edit)
self.setLayout(main_layout)
self.line_edit.textChanged.connect(self.on_text_changed)
def get_text(self):
return self.line_edit.text()
def on_text_changed(self, text):
print("The text was changed to:", text)
if __name__ == '__main__':
app = QtWidgets.QApplication([])
widget = Widget()
widget.show()
app.exec_()
Edit: Also, to clarify why you're getting an error, QApplication is a singleton. This means there can only ever be one created. If you try to create a second, you'll get an error. The best way to access the current QApplication is to call QApplication.instance(). You also only call app.exec_() once, as once the application is running it will continue to run in the background. You should use signal/slots to interact with the UI and trigger the code you want to run.

QMessageBox add custom button and keep open

I want to add a custom button to QMessagebox that opens up a matplotlib window, along with an Ok button for user to click when they want to close it
I currently have it somewhat working, but I want the two buttons to do separate things and not open the window.
I know I can just create a dialog window with the desired results, but I wanted to know how to with a QMessageBox.
import sys
from PyQt5 import QtCore, QtWidgets
def main():
app = QtWidgets.QApplication(sys.argv)
msgbox = QtWidgets.QMessageBox()
msgbox.setWindowTitle("Information")
msgbox.setText('Test')
msgbox.addButton(QtWidgets.QMessageBox.Ok)
msgbox.addButton('View Graphs', QtWidgets.QMessageBox.YesRole)
bttn = msgbox.exec_()
if bttn:
print("Ok")
else:
print("View Graphs")
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Desired result:
Ok button - closes QMessageBox
View Graph button - opens matplotlib window and keeps QMessageBox open until user clicks Ok
A bit hacky IMO, but after you add the View Graphs button you could disconnect its clicked signal and reconnect it to your slot of choice, e.g.
import sys
from PyQt5 import QtCore, QtWidgets
def show_graph():
print('Show Graph')
def main():
app = QtWidgets.QApplication(sys.argv)
msgbox = QtWidgets.QMessageBox()
msgbox.setWindowTitle("Information")
msgbox.setText('Test')
msgbox.addButton(QtWidgets.QMessageBox.Ok)
yes_button = msgbox.addButton('View Graphs', QtWidgets.QMessageBox.YesRole)
yes_button.clicked.disconnect()
yes_button.clicked.connect(show_graph)
bttn = msgbox.exec_()
if bttn:
print("Ok")
sys.exit(app.exec_())
if __name__ == "__main__":
main()
A QMessageBox, as all QDialogs, blocks everything until exec_() is returned, but it also automatically connects all buttons to either accepted/rejected signals, returning the exec_() in any case.
A possible solution for your code is:
app = QtWidgets.QApplication(sys.argv)
msgbox = QtWidgets.QMessageBox()
# the following is if you need to interact with the other window
msgbox.setWindowModality(QtCore.Qt.NonModal)
msgbox.addButton(msgbox.Ok)
viewGraphButton = msgbox.addButton('View Graphs', msgbox.ActionRole)
# disconnect the clicked signal from the slots QMessageBox automatically sets
viewGraphButton.clicked.disconnect()
# this is just an example, replace with your matplotlib widget/window
graphWidget = QtWidgets.QWidget()
viewGraphButton.clicked.connect(graphWidget.show)
msgbox.button(msgbox.Ok).clicked.connect(graphWidget.close)
# do not use msgbox.exec_() or it will reset the window modality
msgbox.show()
sys.exit(app.exec_())
That said, be careful in using QDialog.exec_() outside (as in "before") the sys.exit(app.exec_()) call, as it might result in unexpected behavior if you don't know what you are doing.
Okay well first you do not use anything in QtCore so no need to import that. This should help you understand what you need to do. I tweaked it a smidge and I had to add the 2 sys.exits or when you pressed View Graphs the program just hung due to how you have this currently set up. If you do not choose to adjust this code flow then pull the sys.exit out of the if/else and put it right after the if/else -- no sense having unnecessary redundant code
from sys import exit as sysExit
from PyQt5.QtWidgets import QApplication, QMessageBox
def Main():
msgbox = QMessageBox()
msgbox.setWindowTitle("Information")
msgbox.setText('Test')
msgbox.addButton(QMessageBox.Ok)
msgbox.addButton('View Graphs', QMessageBox.YesRole)
bttn = msgbox.exec_()
if bttn == QMessageBox.Ok:
print("Ok")
sysExit()
else:
print("View Graphs")
sysExit()
if __name__ == "__main__":
MainThred = QApplication([])
MainApp = Main()
sysExit(MainThred.exec_())
Aka your non-redundant if/else would look as follows
if bttn == QMessageBox.Ok:
print("Ok")
else:
print("View Graphs")
sysExit()

Why the editText doesn't show the user input in Python class?

I have a Python class that display a window that includes 2 text filed and 2 buttons.
Where the user enter a string in the first edit text and on click on the (open button) the second edit text will display the user input.
The problem is that on the click on the button there is nothing displayed in the text filed.
Code:
'''
1- import the libraries from the converted file
2- import the converted file
'''
from PyQt5 import QtCore, QtGui, QtWidgets
import pathmsgbox
import os
import pathlib
class path_window(pathmsgbox.Ui_PathMSGbox):
def __init__(self,windowObject ):
self.windowObject = windowObject
self.setupUi(windowObject)
self.windowObject.show()
self.getText()
'''
get the userInput from the EditLine
'''
def getText(self):
inputUser = self.pathEditLine.text()
outPutUser = self.outputPathName.setText(inputUser)
print(outPutUser)
def puchBtn(self):
openButton = self.PathOpenBtn.clicked.connect(self.getText)
'''
function that exit from the system after clicking "cancel"
'''
def exit():
sys.exit()
'''
define the methods to run only if this is the main module deing run
the name take __main__ string only if its the main running script and not imported
nor being a child process
'''
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
PathMSGbox = QtWidgets.QWidget()
pathUi = path_window(PathMSGbox)
pathUi.pathCancelBtn.clicked.connect(exit)
sys.exit(app.exec_())
You're not connecting your clicked button event to the function - the binding is in a function that is never called.
Simply connect your button in the class initialization:
class path_window(pathmsgbox.Ui_PathMSGbox):
def __init__(self,windowObject ):
self.windowObject = windowObject
self.setupUi(windowObject)
self.windowObject.show()
self.PathOpenBtn.clicked.connect(self.getText)
self.getText()

PyQt4: Only the last signal is being processed

I ran into a strange problem when working on my project. I have a GUI and a QTextEdit that serves as a status browser. When a button is clicked, I want the QTextEdit to display a 10 second countdown while another function is happening in a separate thread. Even though I emit a signal every second, the QTextEdit hangs for 9 seconds, then displays the last countdown number.
I thought this might have something to do with stuff happening in a separate thread, so I created a separate example to test this out. In my simple example, there are two things: a QTextEdit and a Button. When the button is clicked, the status browser should display '5' for two seconds, then '4'.
Here is the code:
import sys
from PyQt4 import QtGui, uic
from PyQt4.QtCore import QObject, pyqtSignal
import time
class MainUI(QObject):
status_signal = pyqtSignal(str)
def __init__(self, window):
super(QObject, self).__init__()
self.ui = uic.loadUi(r'L:\internal\684.07\Mass_Project\Software\PythonProjects\measure\testing\status_test.ui', window)
self.ui.statusBrowser.setReadOnly(True)
self.ui.statusBrowser.setFontPointSize(20)
self.status_signal.connect(self.status_slot)
self.ui.button.clicked.connect(self.counter)
window.show()
def status_slot(self, message):
self.ui.statusBrowser.clear()
self.ui.statusBrowser.append(message)
def counter(self):
print 'clicked'
i = 5
self.status_signal.emit(str(i))
time.sleep(2)
self.status_signal.emit(str(i-1))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
app.setStyle("cleanlooks")
main_window = QtGui.QDialog()
main_ui = MainUI(main_window)
sys.exit(app.exec_())
In this example, the same thing happens. The status browser hangs for 2 seconds, then only displays '4'. When I alter the status_slot function so that it doesn't clear the status browser before appending to it, the status browser waits for 2 seconds, then emits both signals at once, displaying '5 \n 4'. Does anyone know why this is happening and what I can do to constantly update the display? Thanks in advance!
time.sleep() blocks the Qt main loop so it can't process window redraw events. Use a QTimer to periodically call a method which emits your signal so that control is returned to the Qt event loop regularly.

Click event is sent immediately after I start application (PySide and Python)

I have an application with a button for which the clicked signal is connected to a slot that opens a QFileDialog. I want to manipulate the state of the button (sender) within the slot depending on the actions taken by the user in the QFileDialog.
However, with the code I have presently, my application do not starts correctly. It starts immediately with QFileDialogOpen and I do not understand why. When I comment the line that connect the button's clicked signal to the slot, the application starts normally though.
How can I correctly pass the button as an argument when I want to connect a clicked signal of a button to a slot? Here is a MCWE of my problem:
from PySide import QtGui
import sys
class MyApplication(QtGui.QWidget):
def __init__(self, parent=None):
super(MyApplication, self).__init__(parent)
self.fileButton = QtGui.QPushButton('Select File')
self.fileButton.clicked.connect(self.select_file(self.fileButton))
layout = QtGui.QGridLayout()
layout.addWidget(self.fileButton)
self.setLayout(layout)
def select_file(self, button):
file_name = QtGui.QFileDialog.getOpenFileName()
if str(file_name[0]) is not "":
button.setEnabled(True)
else:
button.setDisabled(True)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = MyApplication()
w.show()
sys.exit(app.exec_())
You don't bind an actual function call using PySide signals/slots, you bind a function, method, or function-like object using PySide's signals/slots.
You have:
self.fileButton.clicked.connect(self.select_file(self.fileButton))
This tells Qt to bind the click event to something that is returned from the self.select_file function call, which presumably has no __call__ attribute and is called immediately (causing the opening of the QFileDialog)
What you want is the following:
from functools import partial
self.fileButton.clicked.connect(partial(self.select_file, self.fileButton))
This creates a callable, frozen function-like object with arguments for Qt to call.
This is comparable to saying:
self.fileButton.clicked.connect(self.select_file)
Rather than saying:
self.fileButton.clicked.connect(self.select_file())

Categories