How to connect PyQt signal to external function - python

How does one connect a pyqt button signal in one file, to a function in another python file? I've tried various things, but nothing seems to work.
This is the first file:
from PyQt4 import QtGui
from PyQt4.QtGui import QMainWindow
from MainUIFile import Ui_Main
from pythonfile import myOutsideFunction
class MainWindow(QMainWindow,Ui_file):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
self.btn.clicked.connect(myOutsideFunction())
The second file that is called by the first:
def myOutsideFunction(self):
# Do some stuff here
How would I go about doing this?

You are currently making a call to myOutsideFunction and passing the result to the connect function, which expects a callable as an argument.
Remove the parenthesis from myOutsideFunction in the connect call
self.btn.clicked.connect(myOutsideFunction)

What is the importance of connecting to a function outside of your code? Could you not just do something like this:
def myOutsideFunction(a,b,c,d):
#process variables/objects a,b,c,d as you wish
return answer
from PyQt4 import QtGui
from PyQt4.QtGui import QMainWindow
from MainUIFile import Ui_Main
from pythonfile import myOutsideFunction
class MainWindow(QMainWindow,Ui_file):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
self.btn.clicked.connect(self.pressed_the_button())
#initialize your variables/objects for your outside function if need be
def pressed_the_button(self):
answer_from_outside_function = myOutsideFunction(self.a,self.b,self.c,self.d)
# run whatever you need to here...

Related

How to do Web Scraping with BeautifulSoup without affecting my PyQt5 application?

I am making an application that involves taking websites and getting the links they have (and also images), but these operations take some time and cause the application to freeze. I've tried using QThread and QRunnable to try and separate the execution of the application from the execution of the functions I use.
I programmed this small example of how it works in my app:
from PyQt5 import QtWidgets,QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow,QLineEdit,QVBoxLayout
from PyQt5.QtCore import QThread
from bs4 import BeautifulSoup
import requests
class mainwindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setFixedSize(600,64)
## Set a QLineEdit
self.Line=QtWidgets.QLineEdit()
self.Line.setPlaceholderText('You should be able to type here while the links are searched')
self.Line.setFixedSize(600,32)
self.layout().addWidget(self.Line)
## Set a QPushButton
self.Button=QtWidgets.QPushButton()
self.Button.setText('Seach links')
self.Button.move(0,32)
self.Button.setFixedSize(600,32)
self.layout().addWidget(self.Button)
## Connect button with function
self.Button.clicked.connect(lambda:self.search_start())
## Function calls QProcess class
def search_start(self):
self.sclass=search_class()
self.sclass.func_seach()
## Class search for links
class search_class(QThread):
def func_seach(self):
url='https://youtu.be/dQw4w9WgXcQ'
links_list=[]
for link in BeautifulSoup(requests.get(url).text, 'html.parser').find_all('a'):
links_list.append(link.get('href'))
print(links_list)
if __name__=='__main__':
Aplication=QtWidgets.QApplication([])
MainWindow=mainwindow()
MainWindow.show()
Aplication.exec_()
How can I prevent the app from freezing while executing that function?
I think you may have already noticed that I'm pretty new to this. I need to know what's wrong, what I'm doing wrong and how to fix it.
Thank you very much in advance.
The solution was to put the entire class below in a function inside the first class and trigger my function through another function that started the other one in a thread:
from PyQt5 import QtWidgets,QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow,QLineEdit,QVBoxLayout
from PyQt5.QtCore import QThread
from bs4 import BeautifulSoup
import requests
class mainwindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setFixedSize(600,64)
self.Line=QtWidgets.QLineEdit()
self.Line.setPlaceholderText('You should be able to type here while the links are searched')
self.Line.setFixedSize(600,32)
self.layout().addWidget(self.Line)
## Set a QPushButton
self.Button=QtWidgets.QPushButton()
self.Button.setText('Seach links')
self.Button.move(0,32)
self.Button.setFixedSize(600,32)
self.layout().addWidget(self.Button)
## Connect button with function
self.Button.clicked.connect(lambda:self.search_start())
## Function calls func_seach function as a thread
def search_start(self):
thread=Thread(target=self.func_seach)
thread.start()
def func_seach(self):
url='https://youtu.be/dQw4w9WgXcQ'
links_list=[]
for link in BeautifulSoup(requests.get(url).text, 'html.parser').find_all('a'):
links_list.append(link.get('href'))
print(links_list)
if __name__=='__main__':
Aplication=QtWidgets.QApplication([])
MainWindow=mainwindow()
MainWindow.show()
Aplication.exec_()

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 4 - global name 'SIGNAL' is not defined

I am trying to connect a push button signal to a callable I created, but for some reason this error keeps on popping up. I've checked to make sure QtCore is imported ... what else am I missing?
Sample code:
from PyQt4 import QtCore
from PyQt4 import QtGui
import sys
class guiFindFiles(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
#Create window
self.setFixedSize(400,180)
self.setWindowTitle("Choose the files to use")
#Create all layouts to be used by window
self.windowLayout = QtGui.QVBoxLayout()
self.fileLayout1 = QtGui.QHBoxLayout()
self.fileLayout2 = QtGui.QHBoxLayout()
self.fileLayout3 = QtGui.QHBoxLayout()
#Create the prompt for user to load in the q script to use
self.qFileTF = QtGui.QLineEdit("Choose the q script file to use")
self.qFileButton = QtGui.QPushButton("Open")
self.qFileButton.setFixedSize(100,27)
self.fileLayout1.addWidget(self.qFileTF)
self.fileLayout1.addWidget(self.qFileButton)
#Connect all the signals and slots
self.connect(self.qFileButton, SIGNAL("pressed()"), self.loadFile)
def loadFile():
fileName = []
selFile = QtGui.QFileDailog.getOpenFileName(self)
print selFile
SIGNAL is inside QtCore, so the line should be:
self.connect(self.qFileButton, QtCore.SIGNAL("pressed()"), self.loadFile)
but you really should use the new style connections:
self.qFileButton.pressed.connect(self.loadFile)
And, unless you meant to differentiate a click from press/release couple, you'd better use clicked signal:
self.qFileButton.clicked.connect(self.loadFile)
SIGNAL is defined inside QtCore, so you must use it within QtCore namespace if you've imported QtCore as a whole. So use:
QtCore.SIGNAL(...)
instead of:
SIGNAL(...)
Or you can import SIGNAL from QtCore explicitly:
from PyQt4.QtCore import SIGNAL

Accesing PyQt Gui elements from another file

I am learning PyQt and coming from webdesign, so excuse this question that must have very obvious answer.So I am building a PyQt application and I would like to spread methods to several files to correspond different parts of GUI. How can I access textbox locating in fileA.py from fileB.py. :
#fileA.py
import sys
from PyQt4 import QtGui, QtCore
from gui1 import Ui_MainWindow
import fileB
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
#This works all fine
def pressed():
window.plainTextEdit.appendPlainText("Hello")
window.pushButton.pressed.connect(pressed)
window.button2.pressed.connect(fileB.func3)
sys.exit(app.exec_())
Now, in this file I would like to use textbox from fileA.py
#fileB.py
import fileA
#How do I access window.plainTextEdit from fileA.py
def func3():
print "hello"
fileA.window.plainTextEdit.appendPlainText("Hello")
What am I doing wrong? What would be best way to spread functionality to multiple files if not this?
Thank you for taking time to read this.
You can take advantage of Python's class inheritance, like so:
fileA.py:
import sys
from PyQt4 import QtGui, QtCore
from gui1 import Ui_MainWindow
import fileB
class MyApp(fileB.MyApp, QtGui.QMainWindow):
def __init__(self):
self.MyMethod()
# Should print 'foo'
fileB.py:
import sys
from PyQt4 import QtGui, QtCore
from gui1 import Ui_MainWindow
class MyApp(QtGui.QMainWindow):
def MyMethod(self):
print 'foo'
Well, first off, the code under if __name__ == "__main__" will never be run when you are importing fileA.py, and so fileA.window does not exist. That's what it should do: run only when __name__ is "__main__", i.e. run as a top-level program. Instead, you should import fileA.py, create the QApplication and window again, then access window.plainTextEdit. However, this creates a very tight coupling between the code, as you are directly accessing a widget in MyApp from fileB. It might be better if instead, you expose a method in MyApp that appends to the text box instead of having fileB.py do it directly. So you may want to think about what you want to do and how to structure your program.
Of course, you don't have to structure your code that way; you could simply do
window = MyApp()
window.plainTextEdit.appendPlainText("Hello")
in fileB if you wanted.

Connect Signal emited from method Class into different Class Slot Custom Signals PySide

I want to connect the signal emitted from closeWidgetUI class method into addTool class method. But this seems only to work with PyQt4 not with PySide. Every time I hit the closeButton created in self.close_btn.clicked.connect(self.closeWidgetUI), the program freeze and close itself. Any sugestion?
import PySide.QtCore as qc
import PySide.QtGui as qg
class InterpolateIt(dc,qg.QDialog):
def __init__(self):
qg.QDialog.__init__(self)
""" MORE THINGS
OVER THIS PART NOT IMPORTANT AT MOMENT"""
add_button.clicked.connect(self.addTool)
def addTool(self):
#NEED TO CONNECT closeWidgetUI EMITED SIGNAL HERE
new_widget = InterpolateWidget()
self.clicked.connect(new_widget, qc.SIGNAL('CLOSE'), self.removeTool)
def removeTool(self,interpWidget):
self.interpolateLayout.removeWidget(interpWidget)
interpWidget.deleteLater()
# ------------------------------------------------------------------------------------------------------#
class InterpolateWidget(qg.QFrame):
def __init__(self):
qg.QFrame.__init__(self)
""" MORE THINGS
OVER THIS PART NOT IMPORTANT AT MOMENT"""
# HERE BUTTON EMIT SIGNAL AT CLICKED
self.close_btn.clicked.connect(self.closeWidgetUI)
# TRIGGER THIS FUNC
def closeWidgetUI(self):
self.emit(qc.SIGNAL('CLOSE'), self)
from functools import partial
def addTool(self):
#NEED TO CONNECT closeWidgetUI EMITED SIGNAL HERE
new_widget = InterpolateWidget()
deleteTool = partial(self.removeTool,new_widget)
new_widget.close_btn.clicked.connect(deleteTool)
i did it in this way! thanks to my brain :) cheers

Categories

Resources