Add a click on QLineEdit - python

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)

Related

Manipulating qt Dialog item from a subDialog

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).

How to add a menu only in the QTreeWidgetItem after pressing the right click? [duplicate]

I have the following code to create a QTreeWidget and a contextmenu with 2 actions.
import sys
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.tw = QtWidgets.QTreeWidget()
self.tw.setHeaderLabels(['Name', 'Cost ($)'])
cg = QtWidgets.QTreeWidgetItem(['carrots', '0.99'])
c1 = QtWidgets.QTreeWidgetItem(['carrot', '0.33'])
self.tw.addTopLevelItem(cg)
self.tw.addTopLevelItem(c1)
self.tw.installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tw)
def eventFilter(self, source: QtWidgets.QTreeWidget, event):
if (event.type() == QtCore.QEvent.ContextMenu and
source is self.tw):
menu = QtWidgets.QMenu()
AAction = QtWidgets.QAction("AAAAA")
AAction.triggered.connect(lambda :self.a(source.itemAt(event.pos())))
BAction = QtWidgets.QAction("BBBBBB")
BAction.triggered.connect(lambda :self.b(source, event))
menu.addAction(AAction)
menu.addAction(BAction)
menu.exec_(event.globalPos())
return True
return super(Dialog, self).eventFilter(source, event)
def a(self, item):
if item is None:
return
print("A: {}".format([item.text(i) for i in range(self.tw.columnCount())]))
def b(self, source, event):
item = source.itemAt(event.pos())
if item is None:
return
print("B: {}".format([item.text(i) for i in range(source.columnCount())]))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Dialog()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
When opening the contextmenu in the header and clicking on one of the actions it prints either carrot or carrots, depending on where in the contextmenu I click. But I give the position of right click event to the functions.
So why is this happening and what can I do to stop it?
Your code has 2 errors:
The main error is that the itemAt() method uses the coordinates with respect to the viewport() and not with respect to the view (the QTreeWidget) so you will get incorrect items (the header occupies a space making the positions with respect to the QTreeWidget and the viewport() have an offset).
You should not block the eventloop, for example blocking the eventFilter you may be blocking other events that would cause errors that are difficult to debug, in this case it is better to use a signal.
class Dialog(QtWidgets.QDialog):
rightClicked = QtCore.pyqtSignal(QtCore.QPoint)
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.tw = QtWidgets.QTreeWidget()
self.tw.setHeaderLabels(["Name", "Cost ($)"])
cg = QtWidgets.QTreeWidgetItem(["carrots", "0.99"])
c1 = QtWidgets.QTreeWidgetItem(["carrot", "0.33"])
self.tw.addTopLevelItem(cg)
self.tw.addTopLevelItem(c1)
self.tw.viewport().installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tw)
self.rightClicked.connect(self.handle_rightClicked)
def eventFilter(self, source: QtWidgets.QTreeWidget, event):
if event.type() == QtCore.QEvent.ContextMenu and source is self.tw.viewport():
self.rightClicked.emit(event.pos())
return True
return super(Dialog, self).eventFilter(source, event)
def handle_rightClicked(self, pos):
item = self.tw.itemAt(pos)
if item is None:
return
menu = QtWidgets.QMenu()
print_action = QtWidgets.QAction("Print")
print_action.triggered.connect(lambda checked, item=item: self.print_item(item))
menu.addAction(print_action)
menu.exec_(self.tw.viewport().mapToGlobal(pos))
def print_item(self, item):
if item is None:
return
texts = []
for i in range(item.columnCount()):
text = item.text(i)
texts.append(text)
print("B: {}".format(",".join(texts)))
Although it is unnecessary that you use an eventFilter to handle the contextmenu since a simpler solution is to set the contextMenuPolicy of the QTreeWidget to Qt::CustomContextMenu and use the customContextMenuRequested signal:
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.tw = QtWidgets.QTreeWidget()
self.tw.setHeaderLabels(["Name", "Cost ($)"])
cg = QtWidgets.QTreeWidgetItem(["carrots", "0.99"])
c1 = QtWidgets.QTreeWidgetItem(["carrot", "0.33"])
self.tw.addTopLevelItem(cg)
self.tw.addTopLevelItem(c1)
self.tw.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tw.customContextMenuRequested.connect(self.handle_rightClicked)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tw)
def handle_rightClicked(self, pos):
item = self.tw.itemAt(pos)
if item is None:
return
menu = QtWidgets.QMenu()
print_action = QtWidgets.QAction("Print")
print_action.triggered.connect(lambda checked, item=item: self.print_item(item))
menu.addAction(print_action)
menu.exec_(self.tw.viewport().mapToGlobal(pos))
def print_item(self, item):
if item is None:
return
texts = []
for i in range(item.columnCount()):
text = item.text(i)
texts.append(text)
print("B: {}".format(",".join(texts)))

PyQt5: Notify when attribute's value is changed

First of all, please, look at the code sample, which is given below. How can I access, for example,.setDisabled(...) on QPushButton when the value of attribute self.markup_points inside QGraphicsView is changed? How I can implement this using pyqt signals or... use a singleton?
class ImageView(QtWidgets.QGraphicsView):
def __init__(self, parent):
super(ImageView, self).__init__(parent)
self.markup_points = []
...
...
def set_image(self, pixmap):
foo()
def mousePressEvent(self, event):
foo()
self.markup_points.append(QtCore.QPointF(bar()))
super(ImageView, self).mousePressEvent(event)
...
def keyPressEvent(self, event):
key = event.key()
modifiers = int(event.modifiers())
if (modifiers and modifiers & MOD_MASK == modifiers and
key > 0 and key != QtCore.Qt.Key_Control and key != QtCore.Qt.Key_Meta):
if key == 88:
self.remove_point()
def remove_point(self):
if len(self.markup_points):
self.markup_points.pop()
...
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
...
self.imageView = ImageView()
self.btnLoad.clicked.connect(self._load_combination)
self.btnSkip.clicked.connect(self._skip_combination)
self.btnSave.clicked.connect(self._save_objects)
# qpushbutton that I want to access later
self.btnRemove.clicked.connect(self.imageView.remove_point)
...
def event_if_something_is_changed_in_image_view(self):
self.btnRemove.setDisabled(True)
Why do you think a singleton is the solution? A singleton is an anti-pattern so it should be avoided and only in certain cases is it necessary, besides it has nothing to do with notifying about the changes, so discard it.
The solution is to create a signal that is issued when there is a change, and connect it to a slot that receives notifications:
class ImageView(QtWidgets.QGraphicsView):
markupPointsChanged = QtCore.pyqtSignal(list) # <---
def __init__(self, parent):
super(ImageView, self).__init__(parent)
self.markup_points = []
# ...
def mousePressEvent(self, event):
foo()
self.append_point(QtCore.QPointF(bar()))
super(ImageView, self).mousePressEvent(event)
def keyPressEvent(self, event):
key = event.key()
modifiers = int(event.modifiers())
if (modifiers and modifiers & MOD_MASK == modifiers and
key > 0 and key not in (QtCore.Qt.Key_Control, QtCore.Qt.Key_Meta)):
if key == QtCore.Qt.Key_X:
self.remove_point()
def append_point(self, p):
self.markup_points.append(p)
self.markupPointsChanged.emit(self.markup_points) # <---
def remove_point(self):
if self.markup_points:
self.markup_points.pop()
self.markupPointsChanged.emit(self.markup_points) # <---
# ...
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# ...
self.imageView = ImageView()
self.btnLoad.clicked.connect(self._load_combination)
self.btnSkip.clicked.connect(self._skip_combination)
self.btnSave.clicked.connect(self._save_objects)
self.btnRemove.clicked.connect(self.imageView.remove_point)
self.imageView.markupPointsChanged.connect(self.on_markupPointsChanged) # <---
#QtCore.pyqtSlot(list)
def on_markupPointsChanged(self, points):
print(points)
self.btnRemove.setDisabled(True)

Closing a QDialog and disconnect signals fails

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)

Get drag-n-drop qtreewidget items - Python

Is there a way I can get the items being drag/dropped and their destination parent?
In an ideal scenario what I want to happen is once the dropEvent finishes, it prints the qtreewidgetitems which were moved, as well as the new parent which the items were moved to. The parent would either be the qtreewidget itself or another qtreewidgetitem depending on where the drop happened.
Can someone help me out here please?
Below is the code i have so far.
# Imports
# ------------------------------------------------------------------------------
import sys
from PySide import QtGui, QtCore, QtSvg
class TreeNodeItem( QtGui.QTreeWidgetItem ):
def __init__( self, parent, name="" ):
super( TreeNodeItem, self ).__init__( parent )
self.setText( 0, name )
self.stuff = "Custom Names - " + str(name)
class TreeWidget(QtGui.QTreeWidget):
def __init__(self, parent=None):
QtGui.QTreeWidget.__init__(self, parent)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.setItemsExpandable(True)
self.setAnimated(True)
self.setDragEnabled(True)
self.setDropIndicatorShown(True)
self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
self.setAlternatingRowColors(True)
# def dropEvent(self, event):
# print "finished"
def dropEvent(self, event):
return_val = super( TreeWidget, self ).dropEvent( event )
print ("Drop finished")
d = event.mimeData()
print d, event.source()
return return_val
# Main
# ------------------------------------------------------------------------------
class ExampleWidget(QtGui.QWidget):
def __init__(self,):
super(ExampleWidget, self).__init__()
self.initUI()
def initUI(self):
# formatting
self.resize(250, 400)
self.setWindowTitle("Example")
# widget - passes treewidget
self.itemList = QtGui.QTreeWidget()
self.itemList = TreeWidget()
headers = [ "Items" ]
self.itemList.setColumnCount( len(headers) )
self.itemList.setHeaderLabels( headers )
# layout Grid - row/column/verticalpan/horizontalspan
self.mainLayout = QtGui.QGridLayout(self)
self.mainLayout.setContentsMargins(5,5,5,5)
self.mainLayout.addWidget(self.itemList, 0,0,1,1)
# display
self.show()
# Functions
# --------------------------------------------------------------------------
def closeEvent(self, event):
print "closed"
def showEvent(self, event):
print "open"
for i in xrange(20):
TreeNodeItem( parent=self.itemList , name=str(i) )
# Main
# ------------------------------------------------------------------------------
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
ex = ExampleWidget()
sys.exit(app.exec_())
I would suggest using a View/Model approach.
Decoding the 'application/x-qabstractitemmodeldatalist' will only return the item dragged, and the dropMimeData isn't used in the QTreeWidget.
Look here for an example.
https://wiki.python.org/moin/PyQt/Handling%20Qt's%20internal%20item%20MIME%20type

Categories