I have developed a QGIS plugin using Pyqt. I now have a need within this plugin to have a QDialog popup have its fields populated with data from our database.
My problem is how to pass a variable (in this case it might be a table and row reference) into a class and have it used by the static method.
If I print a passed in variable from within the class it will return the variable in addition to None?? If I take the same variable and try and populate a qplaintextedit it won't work because its complaining of being type 'None'.
Here is some test code I'm trying out just to get the concept down...
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import pdb
class mydi(QDialog):
def __init__(self, pass_var, parent=None):
super(mydi, self).__init__(parent)
layout = QVBoxLayout(self)
self.pass_var = pass_var
print pass_var
self.txt_comments = QPlainTextEdit(self)
self.txt_comments.appendPlainText(pass_var)
layout.addWidget(self.txt_comments)
self.buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
Qt.Horizontal, self)
layout.addWidget(self.buttons)
self.buttons.accepted.connect(self.accept)
self.buttons.rejected.connect(self.reject)
def something(self):
return self.somevar
def comments(self):
return self.txt_comments.toPlainText()
#staticmethod
def getData(parent=None):
dialog = mydi(None)
dialog.exec_()
return (dialog.comments())
def main():
app = QApplication([])
pass_in_var = "test"
dia = mydi(pass_in_var)
data = dia.getData()
print data
Related
I am a beginner with PyQt5 and I am having trouble to use QtCore.signal
I'd like to send a signal when I press my buttons and switch the current widget displayed.
I don't have any errors when I run my code but when I press the buttons nothing happen and I guess it is because I am doing something wrong with the QtCore.Signal
Here is my code :
from PySide2 import QtCore, QtWidgets
from ui_Page_accueil import Ui_MainWindow
from ui_NouvelleVerif import Ui_Dialog as Ui_NouvelleVerif
from ui_NouvelleVerifEssieux import Ui_Dialog as Ui_NouvelleVerifEssieux
import sys
class MainWindowUi(Ui_MainWindow):
to_NouvelleVerif = QtCore.Signal()
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setupUi(self)
#self.pushButton.clicked.connect(self.pushbutton_handler1)
self.pushButton_2.clicked.connect(self.pushbutton_handler2)
#def pushbutton_handler1(self):
# self.to_MainWindow.emit()
def pushbutton_handler2(self):
self.to_NouvelleVerif.emit()
class NouvelleVerifUi(QtWidgets.QWidget, Ui_NouvelleVerif):
to_MainWindow = QtCore.Signal()
to_NouvelleVerifEssieux = QtCore.Signal()
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.setupUi(self)
self.pushButton.clicked.connect(self.pushbutton_handler1)
#self.pushButton_2.clicked.connect(self.pushbutton_handler2)
self.pushButton_3.clicked.connect(self.pushbutton_handler3)
def pushbutton_handler1(self):
self.to_MainWindow.emit()
#def pushbutton_handler2(self):
# self.switch_window.emit()
def pushbutton_handler3(self):
self.to_NouvelleVerifEssieux.emit()
class NouvelleVerifEssieuxUi(QtWidgets.QWidget, Ui_NouvelleVerifEssieux):
to_NouvelleVerif = QtCore.Signal()
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.setupUi(self)
self.pushButton.clicked.connect(self.pushbutton_handler1)
def pushbutton_handler1(self):
self.to_NouvelleVerif.emit()
class Controller :
app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QStackedWidget()
MainWindow = MainWindowUi()
NouvelleVerif = NouvelleVerifUi()
NouvelleVerifEssieux = NouvelleVerifEssieuxUi()
def __init__(self):
self.widget.addWidget(self.MainWindow) # create an instance of the first page class and add it to stackedwidget
self.widget.addWidget(self.NouvelleVerif) # adding second page
self.widget.addWidget(self.NouvelleVerifEssieux)
self.widget.setCurrentWidget(self.MainWindow) # setting the page that you want to load when application starts up. you can also use setCurrentIndex(int)
def show_MainWindow(self):
self.NouvelleVerif = NouvelleVerifUi()
self.NouvelleVerif.to_MainWindow.connect(self.show_MainWindow)
self.widget.setCurrentWidget(self.MainWindow)
def show_NouvelleVerif(self):
self.MainWindow = MainWindowUi()
self.NouvelleVerifEssieux = NouvelleVerifEssieuxUi()
self.MainWindow.to_NouvelleVerif.connect(self.show_NouvelleVerif)
self.NouvelleVerifEssieux.to_NouvelleVerif.connect(self.show_NouvelleVerif)
self.widget.setCurrentWidget(self.NouvelleVerif)
def show_NouvelleVerifEssieux(self):
self.NouvelleVerif = NouvelleVerifUi()
self.NouvelleVerif.to_NouvelleVerifEssieux.connect(self.show_NouvelleVerifEssieux)
self.widget.setCurrentWidget(self.NouvelleVerifEssieux)
def main():
controller = Controller()
controller.widget.show()
sys.exit(controller.app.exec_())
if __name__ == '__main__':
main()
#musicamante I don't know why I though the QtCore.Signal could be call even if he was in a function which has not been called. I did what you said and I realise I made another mistake with the widgets.
In the controller class they are create and add to the QStackedWidget in the __init__, but I was creating new ones and trying to set them as CurrentWidget without adding them to the QStackedWidget.
#alexpdev I wanted to navigate through my three differents with pushButton UI this way :
Start with MainWindowUI
MainWindowUI pushButton_2.clicked --> set the current widget display to NouvelleVerifUI
NouvelleVerifUI pushButton_1.clicked --> set the current widget display back to MainWindowUI
NouvelleVerifUI pushButton_3.clicked --> set the current widget display to NouvelleVerifEssieuxUI
NouvelleVerifEssieuxUI pushButton_1.clicked --> set the current widget display back to NouvelleVerifUI
Now everything work I did what you said #musicamante and I also use the UI created at first.
class Controller :
app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QStackedWidget()
MainWindow = MainWindowUi()
NouvelleVerif = NouvelleVerifUi()
NouvelleVerifEssieux = NouvelleVerifEssieuxUi()
def __init__(self):
self.widget.addWidget(self.MainWindow) # create an instance of the first page class and add it to stackedwidget
self.widget.addWidget(self.NouvelleVerif) # adding second page
self.widget.addWidget(self.NouvelleVerifEssieux)
self.widget.setCurrentWidget(self.MainWindow) # setting the page that you want to load when application starts up. you can also use setCurrentIndex(int)
self.NouvelleVerif.to_MainWindow.connect(self.show_MainWindow)
self.MainWindow.to_NouvelleVerif.connect(self.show_NouvelleVerif)
self.NouvelleVerifEssieux.to_NouvelleVerif.connect(self.show_NouvelleVerif)
self.NouvelleVerif.to_NouvelleVerifEssieux.connect(self.show_NouvelleVerifEssieux)
def show_MainWindow(self):
self.widget.setCurrentWidget(self.MainWindow)
def show_NouvelleVerif(self):
self.widget.setCurrentWidget(self.NouvelleVerif)
def show_NouvelleVerifEssieux(self):
self.widget.setCurrentWidget(self.NouvelleVerifEssieux)
Thank you all for your time
My main window has a variable self.x setup in the INIT. Then I need to access this value from the popup password box that is created. This is just a test script to get my point accross. I'm assuming it's something with the inheritance stuff, all that is still a little foreign to me.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtWidgets
# Created by MyWindow
class LoginDlg(QtWidgets.QDialog):
def __init__(self):
super(LoginDlg, self).__init__()
self.password = QtWidgets.QLineEdit()
# THIS IS THE LINE I NEED IT TO PULL X FROM PARENT
self.password.setText(self.x)
self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout = QtWidgets.QFormLayout()
layout.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow)
layout.addRow('Password', self.password)
layout.addWidget(self.button_box)
self.setLayout(layout)
self.setWindowTitle("Login")
self.setMinimumWidth(350)
# Main parent window
class MyWindow(QtWidgets.QWidget):
def __init__(self):
super(MyWindow, self).__init__()
self.edit = QtWidgets.QLineEdit()
button = QtWidgets.QPushButton("Get input from dialog")
button.clicked.connect(self.get_login)
layout = QtWidgets.QHBoxLayout()
layout.addWidget(self.edit)
layout.addWidget(button)
self.setLayout(layout)
self.x = "PASS THIS STRING"
def get_login(self):
login = LoginDlg()
if login.exec_():
self.edit.setText(login.password.text())
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Normally I would just pass this data through the constructor, but let's say I have a lot of data that I don't want to pass back and forth, is there a way to access parent attributes another way?
Don't get too complicated and just pass the value of that variable through the constructor:
class LoginDlg(QtWidgets.QDialog):
def __init__(self, x):
super(LoginDlg, self).__init__()
self.password = QtWidgets.QLineEdit()
self.password.setText(x)
# ...
class MyWindow(QtWidgets.QWidget):
# ...
def get_login(self):
login = LoginDlg(self.x)
if login.exec_():
self.edit.setText(login.password.text())
Another similar option is to access "password" in get_login:
class LoginDlg(QtWidgets.QDialog):
def __init__(self):
super(LoginDlg, self).__init__()
self.password = QtWidgets.QLineEdit()
# self.password.setText(self.x)
self.button_box = QtWidgets.QDialogButtonBox(
QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel
)
# ...
class MyWindow(QtWidgets.QWidget):
# ...
def get_login(self):
login = LoginDlg()
login.password.setText(self.x)
if login.exec_():
self.edit.setText(login.password.text())
Note: my answer does not try to implement what the OP asks is to "access a class from another" (there is no relationship so using parent-child is incorrect) since that complicates the modularization because if a object could affect the other, in general. I think the OP has an XY problem as it asks how to implement a possible solution instead of the underlying problem which is "how to share information between classes"
Sorry. I will modify the contents. I would like to load a widget inside def test by pressing Qbutton. Can not you use QStackedWidget to load the widget's configured functions? I've compiled the class and called it, but only a = QLineEdit ('Qline', self). I wonder what should be done to switch widgets.
You can also create a table like html using pyqt5.
import sys
from PyQt5.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.stacked = QStackedWidget(self)
self.FirstpUI()
def FirstpUI(self):
self.btn1 = QPushButton('test1', self)
self.btn1.move(50,50)
self.btn1.clicked.connect(self.btn1_click)
def test(self):
a = QLineEdit('Qline', self)
b = QLineEdit('Qline2', self)
c = QPushButton('button', self)
a.move(0, 0)
b.move(100, 0)
c.move(50,50)
c.clicked.connect(self.btn2_click)
def btn1_click(self):
self.btn1.deleteLater()
self.stacked.addWidget(self.test())
self.stacked.setCurrentIndex(self.stacked.currentIndex()+1)
def btn2_click(self):
QMessageBox.about(self,'hello','hello2')
if __name__ == "__main__":
app = QApplication(sys.argv)
fream = MainWindow()
fream.show()
app.exec_()
May be I don't know what you real want,because I know that little, I think You can use QtDesigner,it's very useful
I've built an User Interface using QtDesigner and then converted the .ui to .py. The User Interface has different comboBox and textBox from which I want to read the values once the Run button is clicked. Run a function and then populate other text boxes of the user interface once the calculations are completed. However when I change the value of the comboBox and click the button the script still reads the initial value.
I did a simple GUI with a comboBox with two items and a textBox. I'm trying to read the the comboBox text and based on the selected item set the text of the textBox.
Here is the code I'm using to run the GUI and read the value:
from PyQt4 import QtGui
from pyQt4 import QtCore
import sys
import GUI
class MyThread(QtCore.QThread):
updated = QtCore.pyqtSignal(str)
def run(self):
self.gui = Window()
name = self.gui.gui_Name.currentText()
print (name)
if name == 'Cristina':
country = 'Italy'
else:
country = 'Other'
self.updated.emit(str(1))
class Window(QtGui.QMainWindow, GUI.Home):
def __init__(self,parent = None):
super(Window,self).__init__(parent)
self.setupUi(self)
self._thread = MyThread(self)
self._thread.updated.connect(self.updateText)
self.update()
self.
self.pushButton.clicked.connect(self._thread.start)
def updateText(self,text):
self.Country.setText(str(country))
Any thoughts?
Thanks
If the code that you implement in the run is the one that I think you are abusing the threads since with the currentTextChanged signal it would be enough as I show below:
class Window(QtGui.QMainWindow, GUI.Home):
def __init__(self,parent = None):
super(Window,self).__init__(parent)
self.setupUi(self)
self.gui_Name.currentTextChanged.connect(self.onCurrentTextChanged)
def onCurrentTextChanged(self, text):
if if name == 'Cristina':
country = 'Italy'
else:
country = 'Other'
self.Country.setText(str(country))
On the other hand if the real code is a time-consuming task then the use of the threads is adequate. If the task takes as reference the value of the QComboBox at the moment of pressing the button then it establishes that value as property of the thread, in your case you are creating a new GUI in another thread instead of using the existing GUI:
class MyThread(QtCore.QThread):
updated = QtCore.pyqtSignal(str)
def run(self):
name = self.currentText
print(name)
if name == 'Cristina':
country = 'Italy'
else:
country = 'Other'
self.updated.emit(country)
class Window(QtGui.QMainWindow, GUI.Home):
def __init__(self,parent = None):
super(Window,self).__init__(parent)
self.setupUi(self)
self._thread = MyThread(self)
self._thread.updated.connect(self.Country.setText)
self.pushButton.clicked.connect(self.start_thread)
def start_thread(self):
self._thread.currentText = self.gui_Name.currentText()
self._thread.start()
I am sending a signal from another class to update a PySide QTableWidget but nothing is coming though. I have made this very simple for this demonstration:
This is in the controller module called Records.py
class Records(QDialog, randomDialog.Ui_watchingDialog):
signal = 1
atSig = Signal(int)
def add_button_clicked(self):
# Do some stuff
self.signal = 1
self.atSig.emit(self.signal)
# Do some other Stuff
This sits out side the controller called main.py
from controller import Records
class main(QMainWindow, pyMainWindow.Ui_mainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
signal_records = Records.Records()
signal_records.atSig.connect(self.showNewData)
def showNewData(self, signal):
if signal == 1:
print "It worked!"
else:
print "Problem"
How come this signal is not coming through? No error messages are being thrown and neither of the print statements aren't being called. How can I fix this?
signal_records falls out of scope as soon as main.__init__() returns and is garbage collected. You need to make it a member of main so that it persists for the lifetime of the class.
self.signal_records = Records.Records()
self.signal_records.atSig.connect(self.showNewData)
Alternatively, you could assign main as the parent of signal_records
signal_records = Records.Records(self)
Both methods ensure a reference to signal_records sticks around.
If It's possibly, please define this before caller to receive;
.
.
#Slot (int)
def showNewData(self, signal):
.
.
Or it not, Please check your caller def add_button_clicked(self). I work in pyqt4 (same pySide) and (I cut some part out and put some path for test in your) code, It's work.
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class QRecordsDialog (QtGui.QDialog):
addButtonClickedSignal = QtCore.pyqtSignal(int)
def __init__ (self, parent = None):
super(QRecordsDialog, self).__init__(parent)
self.myQPushButton = QtGui.QPushButton('Test Signal', self)
self.myQHBoxLayout = QtGui.QHBoxLayout()
self.myQHBoxLayout.addWidget(self.myQPushButton)
self.setLayout(self.myQHBoxLayout)
self.myQPushButton.clicked.connect(self.addButtonClicked)
def addButtonClicked (self):
self.addButtonClickedSignal.emit(1)
class QMainWindow (QtGui.QMainWindow):
def __init__ (self, parent = None):
super(QMainWindow, self).__init__(parent)
myQRecordsDialog = QRecordsDialog(self)
myQRecordsDialog.addButtonClickedSignal.connect(self.showNewData)
myQRecordsDialog.show()
#QtCore.pyqtSlot(int)
def showNewData (self, signal):
if signal == 1:
print "It worked !"
else:
print "Problem ?"
myQApplication = QtGui.QApplication(sys.argv)
myQMainWindow = QMainWindow()
myQMainWindow.show()
sys.exit(myQApplication.exec_())
If you want to modify your PyQt code to use the PySide naming scheme, that can be done using a simple definition:
QtCore.Signal = QtCore.pyqtSignal
QtCore.Slot = QtCore.pyqtSlot
Reference this
Regards,