In my plugin there is a main dialog, showing list data, and a button that opens another dialog to edit the data in. When you finish the editing the data is saved to a file to be accessed later but a refresh needs to be triggered in the main dialog.
Main Dialog has a refresh function but how can I trigger it from the another "subDialog"?
Main Class
class MainDialog(QDialog):
def __init__(self, iface, parent=None, flags=Qt.WindowFlags()):
QDialog.__init__(self, parent, flags)
uic.loadUi(UI_PATH, self)
self.AnotherClass_instance = AnotherClass(self.iface)
#code to open another dialog when edit is pressed
self.refreshDatabaseData()
def opne_the_other_dialog(self):
self.AnotherClass_instance.execDialog()
def refreshDatabaseData(self):
#code to read txt file and change list view in UI
class MainClass(object):
def __init__(self, iface):
self.act.triggered.connect(self.execDialog)
def initGui(self, menu=None):
if menu is not None:
menu.addAction(self.act)
else:
self.iface.addToolBarIcon(self.act)
def execDialog(self):
self.dialog = MainDialog(self.iface, self.iface.mainWindow())
self.dialog.show()
def quitDialog(self):
self.dialog = None
self.act.setEnabled(True)
self.cancel = False
def execTool(self):
#Do something related to plugin
self.quitDialog()
The other class:
class AnotherClassDialog(QDialog):
def __init__(self, iface, parent=None, flags=Qt.WindowFlags()):
QDialog.__init__(self, parent, flags)
uic.loadUi(UI_PATH, self)
self.iface = iface
class AnotherClass(object):
def __init__(self, iface):
self.iface = iface
self.dialog = None
self.cancel = False
self.act.triggered.connect(self.execDialog)
#connect here the buttons to functions, e.g. "OK"-button to execTool
def execDialog(self):
self.dialog = AnotherClassDialog(self.iface, self.iface.mainWindow())
self.dialog.show()
def scheduleAbort(self):
self.cancel = True
def refreshMainPlugin(self):
#need to execute this correctly
self.refreshDatabaseData()
Edit:
I tried passing the list view in self.AnotherClass_instance.execDialog(here), It works but then I can't pass it from AnotherClass to AnotherClassDialog (it changes from Class Object to QMainWindow).
Related
If I define a disable_signal = QtCore.pyqtSignal() outside of the custom button class, the behaviour I am looking for (all instance are disabled when clicked upon).
class CustomButton(QtWidgets.QToolButton):
def __init__(self, parent, disable_signal):
super(CustomButton, self).__init__(parent)
self.disable_signal = disable_signal
self.disable_signal.connect(self.disable)
self.pressed.connect(self.buttonPressed)
def buttonPressed(self):
self.disable_signal.emit()
#QtCore.pyqtSlot()
def disable(self):
print("received")
self.setEnabled(False)
However, if I define the signal as a class attribute, each instance behave as if they each had their individual signal (pressing upon one, disable only that one):
class CustomButton(QtWidgets.QToolButton):
disable_signal = QtCore.pyqtSignal()
def __init__(self, parent):
super(CustomButton, self).__init__(parent)
self.disable_signal.connect(self.disable)
self.pressed.connect(self.buttonPressed)
def buttonPressed(self):
self.disable_signal.emit()
#QtCore.pyqtSlot()
def disable(self):
print("received")
self.setEnabled(False)
I don't understand why the signal is not shared? I tried to use instead of self.disable_signal.connect(self.disable), CustomButton.disable_signal.connect(self.disable) but I get the error: 'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'.
This is dialog code using PyQt5 QDialog.
class QDialogUI(QDialog):
def __init__(self):
super().__init__()
self.okButton = QPushButton("Ok", self)
self.okButton.clicked.connect(self.acceptCommand)
self.okButton.clicked.connect(lambda:self.closeCommand(1))
self.cancelButton = QPushButton("Cancel", self)
self.cancelButton.clicked.connect(lambda:self.closeCommand(0))
def acceptCommand(self):
...
return date, asset, sort, money, text
def closeCommand(self, status):
return status
And this is main code.
def openDialog(self):
self.dlg = QDialogUI()
self.dlg.exec_()
if self.dlg.closeCommand() == 1:
iD = list(self.dlg.acceptCommand())
self.params.emit(iD[0],iD[1],iD[2],iD[3],iD[4])
If I clicked okButton or cancelButton, Both of them don't react. And I close QDialogUI, it shows error like:
TypeError: closeCommand()missing 1 required positional argument: 'status'
How can I get 'return of acceptCommand' when 'okButton.clicked'?
Or is there more better code that distinguish ok and cancel command?
The solution is to create an attribute of the class that saves that information when it is pressed and that can be used later:
class QDialogUI(QDialog):
def __init__(self):
super().__init__()
self.status = None
self.okButton = QPushButton("Ok", self)
self.okButton.clicked.connect(self.acceptCommand)
self.okButton.clicked.connect(lambda:self.closeCommand(1))
self.cancelButton = QPushButton("Cancel", self)
self.okButton.clicked.connect(lambda:self.closeCommand(0))
def acceptCommand(self):
...
self.status = date, asset, sort, money, text
def closeCommand(self, status):
return self.status
I have a 'nested', a 2-tiered qmenus in which I have created a context menu for renaming and deleting.
I created a subclass for the QMenus in hopes of making my code cleaner as I am unable to use eventFilter in my current code as it messes some functionalities..
For the renaming part, while it renames the first tiered, as soon as I tried to do the same for the second-tiered item, the prompt actually renames the first-tiered item.
The following is a code portion of the QMenu subclass that I did and if you do the following:
Right click and add in a new object called main
In main, create another object called sub
(This is an extra right-click) If you perform another right-mouse click on main and select rename options, and have it changed to 'newMain', this works
Perform the same action as detailed in point #3, but this time, rename on sub to newSub
If you open up the overall menu, noticed that newMain was changed to newSub, while sub remains unchanged.
Could someone kindly shed some light towards my QMenu subclass on where I have done it wrong?
import functools
import sys
from PyQt4 import QtGui, QtCore
class QAddAction(QtGui.QAction):
def __init__(self, icon=None, text="Add Item", parent=None):
if icon:
super(QAddAction, self).__init__(icon, text, parent)
else:
super(QAddAction, self).__init__(text, parent)
class QRenameAction(QtGui.QAction):
def __init__(self, icon=None, text="Rename Item", parent=None):
if icon:
super(QRenameAction, self).__init__(icon, text, parent)
else:
super(QRenameAction, self).__init__(text, parent)
class QDeleteAction(QtGui.QAction):
def __init__(self, icon=None, text="Delete Item", parent=None):
if icon:
super(QDeleteAction, self).__init__(icon, text, parent)
else:
super(QDeleteAction, self).__init__(text, parent)
class QCustomMenu(QtGui.QMenu):
"""Customized QMenu."""
def __init__(self, title, parent=None):
super(QCustomMenu, self).__init__(title=str(title), parent=parent)
self.setup_menu()
def setup_menu(self):
self.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
def contextMenuEvent(self, event):
no_right_click = [QAddAction, QRenameAction, QDeleteAction]
if any([isinstance(self.actionAt(event.pos()), instance) for instance in no_right_click]):
return
self.show_adv_qmenu()
def show_adv_qmenu(self):
qmenu = QCustomMenu(self)
rename_menu_action = QRenameAction(text= "Rename Item", parent=self)
rename_slot = functools.partial(self.rename_menu_item)
rename_menu_action.triggered.connect(rename_slot)
qmenu.addAction(rename_menu_action)
delete_menu_action = QDeleteAction(text="Delete Item", parent=self)
delete_slot = functools.partial(self.delete_menu_item, delete_menu_action)
delete_menu_action.triggered.connect(delete_slot)
qmenu.addAction(delete_menu_action)
qmenu.exec_(QtGui.QCursor().pos())
def addAction(self, action):
super(QCustomMenu, self).addAction(action)
def rename_menu_item(self):
new_name, ok = QtGui.QInputDialog.getText(
self,
"Rename Menu Item ({0})".format(self.title()),
"New name:"
)
if ok:
self.setTitle(new_name)
def delete_menu_item(self, action):
reply = QtGui.QMessageBox.question(self, 'Message',
"Really Delete this item?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
parent = action.parent()
print parent
self.remove_menu_item(self)
else:
event.ignore()
def err_popup(self):
"""Prompts a notification popup."""
msg = QtGui.QMessageBox()
msg.setIcon(QtGui.QMessageBox.Critical)
msg.setText("Input name already exists. Please check.")
msg.setWindowTitle('Unable to add item')
msg.setStandardButtons(QtGui.QMessageBox.Ok)
msg.exec_()
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Example, self).__init__(parent)
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Context menu')
self.qmenu = QCustomMenu(title='', parent=self)
add_item_action = QtGui.QAction('Add new item', self,
triggered=self.add_new_item)
self.qmenu.addAction(add_item_action)
def contextMenuEvent(self, event):
action = self.qmenu.exec_(self.mapToGlobal(event.pos()))
def add_new_item(self):
main_menu_name, ok = QtGui.QInputDialog.getText(
self,
'Main Menu',
'Name of new Menu Item:'
)
if ok:
self._addMenuItemTest(main_menu_name)
def _addMenuItemTest(self, main_menu_name):
base_qmenu = QCustomMenu(title=main_menu_name, parent=self)
base_qmenu.setTearOffEnabled(True)
add_item_action = QAddAction(None, 'Add Item', base_qmenu)
slot = functools.partial(self.add_sub_item, base_qmenu)
add_item_action.triggered.connect(slot)
base_qmenu.addAction(add_item_action)
self.qmenu.addMenu(base_qmenu)
def add_sub_item(self, base_menu):
sub_menu_name, ok = QtGui.QInputDialog.getText(
self,
'Sub Menu',
'Name of new Sub Item:'
)
if ok:
action = QtGui.QAction(sub_menu_name, self)
slot = functools.partial(
self._callActionItem,
str(base_menu.title()),
str(sub_menu_name)
)
action.setCheckable(True)
action.setChecked(True)
action.toggled.connect(slot)
base_menu.addAction(action)
def _callActionItem(self):
pass
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Example()
window.show()
sys.exit(app.exec_())
I need to open a QDialog in a different class of the QMainWindow, and after closing the QDialog, all the signals must be disconnected.
I can open the QDialog by pressing a combination of keys and then, when it is open instantly is connected to the button_pressedmethod which itself is connected to self.spanSelector_press and self.spanSelector_
This is the code so far:
class Window(QMainWindow): #This is a matplotlib figure
def __init__(self):
QMainWindow.__init__(self)
#A lot of stuff for the matplotlib figure
def button_pressed(self):
self.select_data = SelectData(self)
self.select_data.show()
self.cid_press = self.figure_canvas.mpl_connect('button_press_event',
self.spanSelector_press)
self.cid_release = self.figure_canvas.mpl_connect('button_release_event',
self.spanSelector_release)
def spanSelector_press(self, event):
if event.button ==1:
self.limite = "minimum"
self.clearMarker() #This is another method to erase the previous line drawn
self.marker = self.axes.axvline(Window.minimumCoords, linestyle='dashed',
linewidth = 2, color = "green")
self.figure_canvas.draw_idle()
Window.initial_marker = self.marker
self.xmin = event.xdata
def spanSelector_release(self, event):
pass
class SelectData(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent, Qt.WindowStaysOnTopHint)
def closeEvent(self, event):
#I need to disconnect all the signals when i close the QDialog
view = self.parent()
view.figure_canvas.mpl_disconnect(view.cid_press)
view.figure_canvas.mpl_disconnect(view.cid_release)
view.deselect()
event.accept()
How can i disconnect all the signals in the button_pressed method after closing the QDialog? Hope you can help me.
According to the matplotlib docs you can disconnect using the connection id, which you'll need to save by doing something like this in Window:
def button_pressed(self):
self.select_data = SelectData(self)
self.select_data.show()
self.cid_press = self.figure_canvas.mpl_connect('button_press_event', self.spanSelector_press)
self.cid_release = self.figure_canvas.mpl_connect('button_release_event', self.spanSelector_release)
Your SelectData class has a reference to its parent class (Window) that can be had by calling parent(), so you can use that to do the disconnection.
def closeEvent(self, event):
window = self.parent()
window.figure_canvas.mpl_disconnect(window.cid_press)
window.figure_canvas.mpl_disconnect(window.cid_release)
event.accept()
I haven't tested that, but it should be pretty close.
Edit: be sure to pass parent to QDialog constructor as such:
class SelectData(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent, Qt.WindowStaysOnTopHint)
I am working on set a click() event to QLineEdit, I already successfully did it. But I want to go back to Mainwindow when the QLine Edit is clicked because I need the data in Mainwindow to further process the data. But I failed to let it go back, neither nor to cite the Mainwindow as parent, I hope someone can point it out. Thank you so much.
MainWindow
{
...
self.tc = MyLineEdit(self.field[con.ConfigFields.VALUE])#self.tc = wx.TextCtrl(self.parent, -1, str(field[con.ConfigFields.VALUE]), pos=(x+220, y-3), size=(200, -1))
...
}
class MyLineEdit(QtGui.QLineEdit):
def __init__(self, parent=MainWindow):
super(MyLineEdit, self).__init__(parent)
#super(CustomQLineEidt, self).__init__()
def mousePressEvent(self, e):
self.mouseseleted()
def mouseseleted(self):
print "here"
MainWindow.mousePressEvent
I use the following to connect any method as the callback for a click event:
class ClickableLineEdit(QLineEdit):
clicked = pyqtSignal() # signal when the text entry is left clicked
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton: self.clicked.emit()
else: super().mousePressEvent(event)
To use:
textbox = ClickableLineEdit('Default text')
textbox.clicked.connect(someMethod)
Specifically for the op:
self.tc = ClickableLineEdit(self.field[con.ConfigFields.VALUE])
self.tc.clicked.connect(self.mouseseleted)
Just simply call the MainWindow mousePressEvent and give it the event variable the line edit received
class MyLineEdit(QtGui.QLineEdit):
def __init__(self, parent):
super(MyLineEdit, self).__init__(parent)
self.parentWindow = parent
def mousePressEvent(self, event):
print 'forwarding to the main window'
self.parentWindow.mousePressEvent(event)
Or you can connect a signal from the line edit
class MyLineEdit(QtGui.QLineEdit):
mousePressed = QtCore.pyqtProperty(QtGui.QMouseEvent)
def __init__(self, value):
super(MyLineEdit, self).__init__(value)
def mousePressEvent(self, event):
print 'forwarding to the main window'
self.mousePressed.emit(event)
Then just connect the signal in your main window where you created it
self.tc = MyLineEdit(self.field[con.ConfigFields.VALUE])#self.tc = wx.TextCtrl(self.parent, -1, str(field[con.ConfigFields.VALUE]), pos=(x+220, y-3), size=(200, -1))
self.tc.mousePressed[QtGui.QMouseEvent].connect(self.mousePressEvent)
This is what I used to do onClick for QLineEdits
class MyLineEdit(QtGui.QLineEdit):
def focusInEvent(self, e):
try:
self.CallBack(*self.CallBackArgs)
except AttributeError:
pass
super().focusInEvent(e)
def SetCallBack(self, callBack):
self.CallBack = callBack
self.IsCallBack = True
self.CallBackArgs = []
def SetCallBackArgs(self, args):
self.CallBackArgs = args
and in my MainGUI:
class MainGUI(..):
def __init__(...):
....
self.input = MyLineEdit()
self.input.SetCallBack(self.Test)
self.input.SetCallBackArgs(['value', 'test'])
...
def Test(self, value, test):
print('in Test', value, test)