Hello I need to know a way of deleting a QPushButton from my interface, i have not found a way that i
s usefull for my program.
for example:
class Button(QtGui.QPushButton):
def __init__(self, title, parent):
super(Button, self).__init__(title, parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, e):
if e.mimeData().hasFormat('text/plain'):
e.accept()
else:
e.ignore()
def dropEvent(self, e):
self.setText(e.mimeData().text())
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
edit = QtGui.QLineEdit('', self)
edit.setDragEnabled(True)
edit.move(30, 65)
button = Button("Button", self)
button.move(190, 65)
self.setWindowTitle('Simple drag & drop')
self.setGeometry(300, 300, 300, 150)
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
app.exec_()
if __name__ == '__main__':
main()
there i created a button that can be dragged and dropped in my main window
now i want a way to delete this button from the mainwindow while im in the program.
thanks
Related
I'm trying to call a function in the main class with the PyQt5 button "dropEvent" event in Python. Although the "print("setText")" command in the function works, the next "self.lbl_1.setText("setText")" command does not work.
Code:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Button(QPushButton):
def __init__(self, title, parent):
super(Button, self).__init__(title, parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('text/plain'):
event.accept()
else:
event.ignore()
def dropEvent(self, event):
self.setText(event.mimeData().text())
MainWindow().lbl_setText()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 200, 150)
self.setWindowTitle("Example")
self.setup()
def setup(self):
self.btn_quit = Button('Quit', self)
self.btn_quit.clicked.connect(QApplication.instance().quit)
self.btn_quit.resize(self.btn_quit.sizeHint())
self.btn_quit.move(90, 100)
self.btn_quit.setAcceptDrops(True)
self.le_drag = QLineEdit('', self)
self.le_drag.setDragEnabled(True)
self.le_drag.move(50, 50)
self.lbl_1= QLabel('Hi', self)
self.lbl_1.move(50, 10)
def closeEvent(self, event: QCloseEvent):
reply = QMessageBox.question(self, 'Message', "r u sure!",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def lbl_setText(self):
print("setText")
self.lbl_1.setText("setText")
def main():
app = QApplication([])
app.setStyle("Fusion")
mainWin = MainWindow()
mainWin.show()
app.exec()
if __name__ == '__main__':
main()
The interaction does not occur between classes but between objects, in your case you are creating a new MainWindow object that is not visible so you have that problem. A simple way to communicate objects in Qt is through signals and slots:
class Button(QPushButton):
dropped = pyqtSignal(str)
# ....
def dropEvent(self, event):
self.setText(event.mimeData().text())
self.dropped.emit(self.text())
class MainWindow(QMainWindow):
# ...
def setup(self):
self.btn_quit = Button('Quit', self)
self.btn_quit.clicked.connect(QApplication.quit)
self.btn_quit.resize(self.btn_quit.sizeHint())
self.btn_quit.move(90, 100)
self.btn_quit.setAcceptDrops(True)
self.le_drag = QLineEdit('', self)
self.le_drag.setDragEnabled(True)
self.le_drag.move(50, 50)
self.lbl_1= QLabel('Hi', self)
self.lbl_1.move(50, 10)
self.btn_quit.dropped.connect(self.lbl_1.setText) # <---
# ...
My Program has:
Two buttons, can move with mouse and link with each other
I use button btn1, btn2
write in a view
My question is:
They call the same function Action1 and Action2. I would like to sendback the button postion which I'm using when I call Action2. How can I do this?
My achievement is "print the button's position with is using Action2"
This is the code I have:
from PyQt5 import QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
class Window(QWidget):
def __init__(self):
QWidget.__init__(self)
self.view = View(self)
self.button = QPushButton('Clear View', self)
self.button.clicked.connect(self.handleClearView)
layout = QVBoxLayout(self)
layout.addWidget(self.view)
layout.addWidget(self.button)
def handleClearView(self):
self.view.scene().clear()
class DragButton(QPushButton):
def __init__(self, title, parent=None):
super().__init__(title, parent)
def mouseMoveEvent(self, e):
if e.buttons() != Qt.RightButton:
return
mimeData = QMimeData()
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.exec_(Qt.MoveAction)
class View(QGraphicsView):
def __init__(self, parent):
QGraphicsView.__init__(self, parent)
self.setScene(QGraphicsScene(self))
self.setAcceptDrops(True)
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
self.btn1=DragButton('Test1', self)
self.btn2=DragButton('Test2', self)
self.btn2.setGeometry(230, 80, 100, 30)
self.menu=QMenu()
self.menu1=QMenu()
self.menu.addAction('use', self.Action1)
self.menu.addAction('sendback', self.Action2)
self.menu.addAction('delete',self.btn1.deleteLater)
self.menu1.addAction('use', self.Action1)
self.menu1.addAction('sendback', self.Action2)
self.menu1.addAction('delete',self.btn2.deleteLater)
self.btn1.setMenu(self.menu)
self.btn2.setMenu(self.menu1)
def Action2(self):
print("sendback position")
def Action1(self):
print("~")
def clearScene(self):
self.scene().clear()
def dragEnterEvent(self, e):
if e.source() in [self.btn1, self.btn2]:
self.clearScene()
e.accept()
def dragMoveEvent(self, e):
e.accept()
def dropEvent(self, e):
btn = e.source()
otherBtn = self.btn2 if btn == self.btn1 else self.btn1
position = e.pos()
btn.move(position)
start = QtCore.QPointF(self.mapToScene(btn.pos()))
end = QtCore.QPointF(self.mapToScene(otherBtn.pos()))
self.scene().addItem(
QGraphicsLineItem(QtCore.QLineF(start, end)))
e.setDropAction(Qt.MoveAction)
e.accept()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
Move the menu and the actions directly in your DragButton class.
class DragButton(QPushButton):
def __init__(self, title, parent=None):
super().__init__(title, parent)
self.menu=QMenu()
self.menu.addAction('use', self.Action1)
self.menu.addAction('sendback', self.Action2)
self.menu.addAction('delete',self.deleteLater)
self.setMenu(self.menu)
def Action2(self):
print("sendback position", self.geometry())
def Action1(self):
print("~")
def mouseMoveEvent(self, e):
if e.buttons() != Qt.RightButton:
return
mimeData = QMimeData()
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.exec_(Qt.MoveAction)
class View(QGraphicsView):
def __init__(self, parent):
QGraphicsView.__init__(self, parent)
self.setScene(QGraphicsScene(self))
self.setAcceptDrops(True)
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
self.btn1=DragButton('Test1', self)
self.btn2=DragButton('Test2', self)
self.btn2.setGeometry(230, 80, 100, 30)
If your buttons have to share info with your view, you can create new signals.
Currently I have the following code that executes a drag and drop function and generates a new button by dragging and dropping another.
But what I would like to know is:
How can I make an image of him when I drag the mouse button?
something like this:
This is the code you used
In this I would like to obtain the same effect as in the gif previously shown but with the Qpushbutton
from PyQt5.QtWidgets import QPushButton, QWidget, QApplication
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
import sys
class Button(QPushButton):
def __init__(self, title, parent):
super().__init__(title, parent)
def mouseMoveEvent(self, e):
if e.buttons() != Qt.RightButton:
return
mimeData = QMimeData()
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.exec_(Qt.MoveAction)
def mousePressEvent(self, e):
super().mousePressEvent(e)
if e.button() == Qt.LeftButton:
print('press')
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setAcceptDrops(True)
self.button = Button('Button', self)
self.button.move(100, 65)
self.setWindowTitle('Click or Move')
self.setGeometry(300, 300, 280, 150)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
position = e.pos()
self.button.move(position)
self.create(position)
e.setDropAction(Qt.MoveAction)
e.accept()
def create(self,position):
print(position)
self.position = position
self.newButton = QPushButton("new",self)
self.newButton.move(self.position)
self.newButton.resize(150,50)
self.newButton.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
ex.show()
app.exec_()
You have to take a widget image using the grab() method then set it to QDrag using the setPixmap() method. Also I have created a method that creates a widget of the same type of the source with the same q-properties (that does not imply that it is a copy of the widget since there are non copyable elements). On the other hand it is advisable to use the right click since the left click will interfere with the clicked signal
from PyQt5 import QtCore, QtGui, QtWidgets
def fake_copy_widget(widget, parent):
t = type(widget)
w = t(parent)
mo = widget.metaObject()
for i in range(mo.propertyCount()):
prop = mo.property(i)
if prop.isWritable() and prop.isReadable():
name = prop.name()
w.setProperty(name, widget.property(name))
return w
class Button(QtWidgets.QPushButton):
def mouseMoveEvent(self, e):
if e.buttons() & QtCore.Qt.RightButton:
pos = self.mapFromGlobal(QtGui.QCursor().pos())
ba = QtCore.QByteArray()
ds = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
ds << pos
mimeData = QtCore.QMimeData()
mimeData.setData("application/x-pos", ba)
pixmap = self.grab()
drag = QtGui.QDrag(self)
drag.setHotSpot(pos)
drag.setPixmap(pixmap)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.exec_(QtCore.Qt.MoveAction)
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setAcceptDrops(True)
button = Button('Button', self)
button.move(100, 65)
self.setWindowTitle('Click or Move')
self.setGeometry(300, 300, 280, 150)
def dragEnterEvent(self, e):
if e.mimeData().hasFormat("application/x-pos"):
e.accept()
def dropEvent(self, e):
position = e.pos()
button = e.source()
mimedata = e.mimeData()
p = QtCore.QPoint()
ba = mimedata.data("application/x-pos")
ds = QtCore.QDataStream(ba)
ds >> p
self.create(QtCore.QRect(position - p, button.size()), button, self)
e.accept()
def create(self, geometry, widget, parent):
button = fake_copy_widget(widget, parent)
button.setGeometry(geometry)
button.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
The title basically says it all. I want to create an image that I can drag around inside a window. My code so far does all that but for some reason, the image appears really small even though, I used the scaled() function to resize it. Also, if I change the values inside the scaled() function, the image disappears.
from PySide.QtGui import *
from PySide.QtCore import *
import sys
class Label(QLabel):
def __init__(self, title, parent):
super(Label, self).__init__(title, parent)
self.setup()
def setup(self):
folder_pic = QPixmap("path")
folder_size = folder_pic.scaled(64, 64)
self.label = QLabel(self)
self.label.setPixmap(folder_size)
def mouseMoveEvent(self, e):
if e.buttons() != Qt.LeftButton:
return
mimeData = QMimeData(self)
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.start(Qt.MoveAction)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setAcceptDrops(True)
self.button = Label("", self)
self.button.move(100, 65)
self.setWindowTitle('Click or Move')
self.setGeometry(300, 300, 280, 150)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
position = e.pos()
self.button.move(position)
e.setDropAction(Qt.MoveAction)
e.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
mywin = Example()
mywin.show()
sys.exit(app.exec_())
My code is based on this tutorial http://zetcode.com/gui/pysidetutorial/dragdrop/.
You set a pixmap on the drag object:
drag.setPixmap(self.pixmap())
But for that to work, you will also need this fix:
def setup(self):
folder_pic = QPixmap("path")
folder_size = folder_pic.scaled(64, 64)
self.setPixmap(folder_size)
I've written 3 separate widgets and each one contains a'closeEvent'. However the close events are NOT triggered when the widgets are placed as tabs inside the MainWindow. How can I emit a signal to properly fire the 'closeEvent' for each tab when the MainWindow closes?
I've done my best to simplify the code to focus on the main goal. I'd like to emit the close event for each tab so in the future when I add more tabs it will be more flexible and each tool will still be self contained.
import sys
from PySide import QtGui, QtCore
class TabA(QtGui.QWidget):
def __init__(self, parent=None):
super(TabA, self).__init__(parent)
self.resize(300, 300)
self.setWindowTitle('App A')
self.btn = QtGui.QPushButton("Button A")
grid = QtGui.QGridLayout()
grid.addWidget(self.btn)
self.setLayout(grid)
def closeEvent(self, event):
print "closing Tab A"
event.accept()
class TabB(QtGui.QWidget):
def __init__(self, parent=None):
super(TabB, self).__init__(parent)
self.resize(300, 300)
self.setWindowTitle('App A')
self.btn = QtGui.QPushButton("Button A")
grid = QtGui.QGridLayout()
grid.addWidget(self.btn)
self.setLayout(grid)
def closeEvent(self, event):
print "closing Tab A"
event.accept()
class TabC(QtGui.QWidget):
def __init__(self, parent=None):
super(TabC, self).__init__(parent)
self.resize(300, 300)
self.setWindowTitle('App A')
self.btn = QtGui.QPushButton("Button A")
grid = QtGui.QGridLayout()
grid.addWidget(self.btn)
self.setLayout(grid)
def closeEvent(self, event):
print "closing Tab A"
event.accept()
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.initUI()
def initUI(self):
self.resize(300, 300)
self.setWindowTitle('Tabs')
# Tabs
main_tabWidget = QtGui.QTabWidget()
main_tabWidget.addTab(TabA(), "TabA")
main_tabWidget.addTab(TabB(), "TabB")
main_tabWidget.addTab(TabC(), "TabC")
vbox = QtGui.QVBoxLayout()
vbox.addWidget(main_tabWidget)
vbox.setContentsMargins(0, 0, 0, 0)
main_widget = QtGui.QWidget()
main_widget.setLayout(vbox)
self.setCentralWidget(main_widget)
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The closeEvent method is only called for a top-level window when a close request is received, so it is not suitable for your use-case. However, there are several signals that are emitted while the application is shutting down that you can connect to.
So for instance you could do this:
class TabA(QtGui.QWidget):
def __init__(self, parent=None):
super(TabA, self).__init__(parent)
...
QtGui.qApp.aboutToQuit.connect(self.handleClose)
def handleClose(self):
print "closing Tab A"
This signal is emitted just before the event-loop exits, and there's also a QtGui.qApp.lastWindowClosed signal which is emitted just after the main window closes.
(PS: don't be tempted to use __del__ for this purpose, because the exact behaviour during shutdown is strictly undefined in PyQt, and can change between versions).