Set text of textbox on button click - python

I have the code of a cipher and designed a GUI for it in PyQt and am now attempting to integrate the two now but I have become stuck.
I want to be able to push the Generate Key button which will then run the generatekey function I have and display it in the text box to the left of the button. I tried with .setText() but could not get it to work. The object name for the text box is keytext. Not really sure what to do, when I push the button now it just crashes.
from PyQt5 import QtCore, QtGui, QtWidgets
import sys, random
import cipher ## Designed GUI
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
class CipherDesign(QtWidgets.QMainWindow, cipher.Ui_MainWindow):
def __init__(self, parent=None):
super(CipherDesign, self).__init__(parent)
self.setupUi(self)
self.BGenerate.clicked.connect(self.generatekey) # Generate Button
def generatekey():
key = list(LETTERS)
random.shuffle(key)
return ''.join(key)
def main():
app = QtWidgets.QApplication(sys.argv)
form = CipherDesign()
form.show()
app.exec_()
if __name__ == "__main__":
main()

Your problem is that your generateKey method is missing the self argument and then inappropriately returning the key value rather than assigning it with setText.
In normal Python omitting the self parameter would just give a "number of arguments" error when you call self.generateKey(). But here it is being called by PyQT which is (somewhat unexpectedly) causing a crash.
In Python, a call to a method on an object (like self.generateKey()) is translated into a call like this generateKey(self). self here is just an arbitrary name (self is used by convention). This is the mechanism by which the method is associated to the object on which it is called. Then, in the body of the method, the name self is in scope and is bound to the object instance, as you need it to be to use it in Python.
So you should have something like:
def generatekey(self):
key = list(LETTERS)
random.shuffle(key)
self.TextBoxObject.setText(''.join(key))

Related

How do I get the text of an QLineEdit into a method?

I'm still not able to understand how to properly connect Qt_pushButton or Qt_LineEdit to methods. I would be so glad to get a explanation which even I do truly understand...
I've put together a pretty basic UI with Qt Designer. It contains a lineEdit called "lineEditTest" which I can indeed change by typing
self.lineEditTest.setText("changed Text")
However, I'm totally stuck with getting the text which the user entered back into my program. I would like to automatically submit the entered text into my function which sets a var to this value and returns it into my UI class. QLineEdit's signal editingFinished sounds perfect for that I guess? But it won't pass the text which the user entered into my function.
QLineEdit does have a property called "text" right? So it seems logical to me that I just have to pass another arg - apart from self - to my function called text.
My code does look like this but it obviously won't work at all:
from PyQt5 import QtWidgets, uic
import sys
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('test.ui', self)
self.lineEditTest.setText("test")
self.lineEditTest.editingFinished.connect(self.changeText(text))
self.show()
def changeText(self):
currentText = text
print (currentText)
return currentText
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
This will just crash with:
NameError: name 'text' is not defined`
The problem seems to be that the OP doesn't understand the logic of the signals and slots (I recommend you check here). The signals are objects that emit information, and the slots are functions (generally callable) that are connected to the signals to receive that information. And the information transmitted by the signal depends on each case, for example if you check the docs of editingFinished signal:
void QLineEdit::editingFinished() This signal is emitted when the
Return or Enter key is pressed or the line edit loses focus. Note that
if there is a validator() or inputMask() set on the line edit and
enter/return is pressed, the editingFinished() signal will only be
emitted if the input follows the inputMask() and the validator()
returns QValidator::Acceptable.
That signal does not send any information so do not expect to receive any information except knowing that the edition has ended by the user. So how can I get the text? Well, through the text() method of QLineEdit:
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi("test.ui", self)
self.lineEditTest.setText("test")
self.lineEditTest.editingFinished.connect(self.changeText)
self.show()
def changeText(self):
text = self.lineEditTest.text()
print(text)
And how to do if the signal sends information? Then the slot (the function) that this connected will have as arguments to that information, for example if you use the textChanged signal that is emitted every time the text of the QLineEdit is changed, it should be as follows:
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi("test.ui", self)
self.lineEditTest.setText("test")
self.lineEditTest.textChanged.connect(self.changeText)
self.show()
def changeText(self, text):
print(text)
# or
# text = self.lineEditTest.text()
# print(text)
The way you're binding your callback isn't correct. When you bind a callback (and this is true for other frameworks, not just for binding callbacks in PyQt), you want to bind the function which should be triggered when a certain event occurs. That's not what you're doing - you're explicitly invoking the callback self.changeText(text) (note: the parentheses invoke the function). So, you're invoking (calling) the function, evaluating it and placing the return value in ...editingFinished.connect().
Don't explicitly invoke the function. Just pass the function's name. This makes sense if you think about it: we're passing a callable object to connect - this is the function which should be called at a later point in time, when the editingFinished event occurs.
You also don't need to pass lineEditTest's text into the callback, since you can just get whatever text is in the widget via self.lineEditTest.text() from inside the callback.
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
from PyQt5 import uic
super(MainWindow, self).__init__()
uic.loadUi("mainwindow.ui", self)
self.lineEditTest.setPlaceholderText("Type something...")
self.lineEditTest.editingFinished.connect(self.on_line_edit_finished_editing)
#pyqtSlot()
def on_line_edit_finished_editing(self):
text = self.lineEditTest.text()
print(f"You finished editing, and you entered {text}")
def main():
from PyQt5.QtWidgets import QApplication
application = QApplication([])
window = MainWindow()
window.show()
return application.exec()
if __name__ == "__main__":
import sys
sys.exit(main())

Error when instantiating a class for the second time

I'm new to python and PyQt and was developing my first app using it, and I've been stuck in a problem when trying to instantiate a class I made again. I've got the following error:
Traceback (most recent call last):
File "ConfiguradorAnx.py", line 16, in <lambda>
self.ProductInfo.clicked.connect(lambda: self.newWindow(InfoProduct))
TypeError: 'InfoProduct' object is not callable
Aborted
The code goes like this:
from PyQt5 import QtCore, QtGui, QtWidgets, uic
import sys
class StartWindow(QtWidgets.QMainWindow): #This function should inherit the class
#used to make the ui file
def __init__(self):
super(StartWindow,self).__init__() #Calling the QMainWindow constructor
uic.loadUi('Janela_inicial.ui',self)
#defining quit button from generated ui
self.QuitButton = self.findChild(QtWidgets.QPushButton, 'QuitButton')
self.QuitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
#defining product info button
self.ProductInfo = self.findChild(QtWidgets.QPushButton, 'ProductInformation')
self.ProductInfo.clicked.connect(lambda: self.newWindow(InfoProduct))
self.show() #Show the start window
def newWindow(self, _class):
self.newWindow = _class()
del self.newWindow
class InfoProduct(QtWidgets.QMainWindow):
def __init__(self):
super(InfoProduct,self).__init__()
uic.loadUi('informacao_prod.ui',self)
self.QuitButton = self.findChild(QtWidgets.QPushButton, 'pushButton')
self.QuitButton.clicked.connect(lambda: self.destroy())
self.show()
def main():
app = QtWidgets.QApplication(sys.argv) #Creates a instance of Qt application
InitialWindow = StartWindow()
app.exec_() #Start application
if __name__ == '__main__':
main()
The first time I click on self.ProductInfo button it works and the InfoProduct window opens, but when I close the window and click on the same button again, I've got the error. I can't figure out what is it that I'm missing, I hope you guys could help!
Cheers!
You're overwriting the newWindow function in its execution:
def newWindow(self, _class):
self.newWindow = _class()
By doing this, the result is that the next time you click the button, the lambda will try to call self.newWindow(InfoProduct), but at that point self.newWindow is an instance of InfoProduct, which obviously is not callable.
The solution is simple (and very important) use different names for the function and the variable that points to the instance:
self.ProductInfo.clicked.connect(lambda: self.createNewWindow(InfoProduct))
def createNewWindow(self, _class):
self.newWindow = _class()
Two small side notes:
There's no need to use findChild, as loadUi already creates python instance attributes for widgets: you already can access self.QuitButton, etc.
Avoid using capitalized names for variables and attributes. Read more about this and other code styling suggestions on the Style Guide for Python Code (aka, PEP-8).

Store string variables from PyQt4 Text Box

I have created a small uic file with qt Designer in order to build a small gui using PyQt4. One of the elements of that gui is a simple textbox, where I set a string value (textbox is called RiskDate_Box). After setting this value in the GUI, I want to use it as a string variable in the following code (not seen here) . My problem is, that I am not able to store it, in the code seen below I tried it in two different ways ( store it as Riskdate1 and Riskdate2). After compiling the code, bothvariables are empty and not equal to the value I set in the GUI, e.g. '12.08.2012'. However, if I compile the script and after that only compile
Riskdate2=window.RiskDate_Box.toPlainText()
then the Riskdate set in the Gui is correctly assigned to the variable 'Riskdate2' as a string. Would be great if someone could help me with that issue.
from PyQt4 import QtCore, QtGui, uic
import sys
# Gui Code
qtCreatorFile = "untitled.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyWindow(QtGui.QDialog):
def __init__(self):
super(MyWindow, self).__init__()
uic.loadUi("untitled.ui", self)
self.show()
self.RiskDate=self.RiskDate_Box.toPlainText()
if __name__ == '__main__':
app=QtGui.QApplication.instance()
app=0
app = QtGui.QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
window = MyWindow()
#Try 1 to store variable
Riskdate1=window.RiskDate
# Try 2 to store variable
Riskdate2=window.RiskDate_Box.toPlainText()
sys.exit(app.exec_())
you need to send s signal when text in your QPlainTextEdit is changed
void QPlainTextEdit::textChanged()
This signal is emitted whenever the document's content changes; for example, when text is inserted or deleted, or when formatting is applied.
you need to do something like:
self.RiskDate_Box.textChanged.connect(self.get_text)
self.show()
def get_text(self):
self.RiskDate = self.RiskDate_Box.toPlainText())
print (self.RiskDate)

Accessing an object function from a parent widget's function

I'm making a large program in Python and using PyQt for the GUI. The whole program is divided into different modules so that different people can work on it simultaneously without interfering with the other people's work.
I am working on 3 different modules right now. 1 is the main program window that handles the basic UI and assigns widgets so the main window (this is not important, just so you know why the code doesn't look like a full program.)
First is the widget:
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
from CustomButton import HoverButton #just a custom button class
from CustomGif import LblLoadingGif #where things go wrong
class Page1(QtGui.QWidget):
def __init__(self, parent=None):
super(Page1, self).__init__(parent)
self.lbl1GIF = LblLoadingGif(self)
self.lbl1GIF.move(400, 45)
self.btnStart = HoverButton(self)
self.btnStart.setText('Start')
self.btnStart.move(35, 400)
self.btnStart.clicked.connect(self.actStartGif)
#the code below works, but then I can only perform 1 action with each button
#self.btnStart.clicked.connect(self.lbl1GIF.actStart)
def actStartGif(self):
self.lbl1GIF.actStart
The code for the custom GIF looks as follows:
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class LblLoadingGif(QtGui.QLabel):
def __init__(self, parent=None):
QtGui.QLabel.__init__(self, parent)
self.setStyleSheet('background: url();')
self.setScaledContents(True)
self.resize(100, 100)
self.movLoadGif = QtGui.QMovie('Resources_Images/Loading6.gif', QtCore.QByteArray())
self.movLoadGif.setCacheMode(QtGui.QMovie.CacheAll)
self.movLoadGif.setSpeed(100)
self.setMovie(self.movLoadGif)
self.hide()
def actStart(self, event):
#print('test1')
self.show()
self.movLoadGif.start()
def actStop(self, event):
#print('test1')
self.hide()
self.movLoadGif.stop()
So the problem is that I can use the actStart function just fine when I call it from the button click directly, but not when I call it through another function. I have used a lot of different variations of brackets, self, Page1 when calling the actStart of the custom gif from withing the actStartGif function.
Any help will be appreciated.
When you use connect it is necessary to pass the name of the function since internally it is in charge of calling it, in your case you have to call it directly so you will have to pass its parameters, in this case event:
self.lbl1GIF.actStart({your value for event})
I do not understand why you use event for what happens to you None:
def actStartGif(self):
self.lbl1GIF.actStart(None)

PyQt monkey patching QLineEdit.paste?

I am trying to intercept paste() for a specific edit box. After much reading and head scratching I decided to try the big hammer and monkey patch. This didn't work for me either. Anyone know why?
import sys
from PyQt4 import QtGui
def myPaste():
print("paste") # Never gets here
if __name__ == "__main__":
# QtGui.QLineEdit.paste = myPaste # Try #1
app = QtGui.QApplication(sys.argv)
window = QtGui.QMainWindow()
window.setWindowTitle("monkey")
centralWidget = QtGui.QWidget(window)
edit = QtGui.QLineEdit(centralWidget)
# QtGui.QLineEdit.paste = myPaste # Try #2
edit.paste = myPaste # Try #3
window.setCentralWidget(centralWidget)
window.show()
app.exec_()
Based on feedback..i was able to use the event filter suggestion to solve my problem. Updated example code follows...
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = QtGui.QMainWindow()
window.setWindowTitle("monkey")
centralWidget = QtGui.QWidget(window)
edit = QtGui.QLineEdit(centralWidget)
window.setCentralWidget(centralWidget)
def eventFilter(obj, e):
if isinstance(obj, QtGui.QLineEdit):
if (e.type() == QtCore.QEvent.KeyPress):
if (e.matches(QtGui.QKeySequence.Paste)):
obj.paste()
t=str(obj.text()).title() # Special handling here...uppercase each word for example
obj.setText(t)
return True
return False
else:
return QtGui.QMainWindow.eventFilter(obj, e)
window.eventFilter = eventFilter
edit.installEventFilter(window)
window.show()
app.exec_()
The reason you can't "monkey-patch" QLineEdit.paste() is because it's not a virtual function. The important thing about virtual functions is that when they are overridden, the reimplemented function will get called internally by Qt; whereas non-virtual overrides will only get called by Python code. So, since QLinedit.paste() isn't virtual, you will instead have to intercept all the events that would normally result in it being called internally by Qt.
That will mean reimplementing QLineEdit.keyPressEvent, so that you can trap the shortcuts for the default key bindings; and also QLineEdit.contextMenuEvent, so that you can modify the default context menu. And, depending on what you're trying to do, you might also need to override the default drag-and-drop handling. (If you prefer not to use a subclass, an event-filter can be used to monitor all the relevant events).
The QClipboard class provides access to the system clipboard, which will allow you to intercept the text before it is pasted. Every application has a single clipboard object, which can be accessed via QApplication.clipboard() or qApp.clipboard().
In order to do what you want you can subclass QLineEdit and create a method that provides the custom paste functionality that you want (paste method isn't virtual so if it is overriden it won't be called from Qt code). In addition you will need an event filter to intercept the shortcut for CTRL+V. Probably you will have to filter the middle mouse button too which is also used to paste the clipboard content. From the event filter you can call your replacement of paste method.
You can use the following code as starting point:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class myEditor(QLineEdit):
def __init__(self, parent=None):
super(myEditor, self).__init__(parent)
def myPaste(self):
self.insert("custom text pasted! ")
class myWindow(QMainWindow):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.customEditor = myEditor(self)
self.setCentralWidget(self.customEditor)
self.customEditor.installEventFilter(self)
def eventFilter(self, obj, e):
if (obj == self.customEditor):
if (e.type() == QEvent.KeyPress):
if (e.matches(QKeySequence.Paste)):
self.customEditor.myPaste()
return True
return False
else:
return QMainWindow.eventFilter(obj, e)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = myWindow()
window.show()
app.exec_()
The event filter here only takes care of the keyboard shortcut for pasting. As I said you need to consider also other sources of the paste operation.

Categories

Resources