PySide Qt: Drag and drop of an image - python

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)

Related

When two button use same function , how can I know which button is using

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.

How to drag the icon when using drag and drop

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_())

PySide/PyQt Overlay widget

I am trying to achieve something like this in PySide: https://codepen.io/imprakash/pen/GgNMXO
What I want to do is create a child window frameless with a black overlay below.
I didn't succeed to create a child window frameless and the overlay...
This is a base code to replicate the HTML:
from PySide import QtCore, QtGui
import sys
class MainWindow(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.resize(800, 500)
self.button = QtGui.QPushButton("Click Me")
self.setLayout(QtGui.QVBoxLayout())
self.layout().addWidget(self.button)
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
popup = QtGui.QDialog(self)
popup.setWindowFlags(QtCore.Qt.FramelessWindowHint)
popup.setLayout(QtGui.QHBoxLayout())
popup.layout().addWidget(QtGui.QLabel("HI"))
popup.show()
print "clicked"
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
If you comment the line with the FramelessWindowHint, the window comes, else nothing happen...
I really hope that someone could help me. Thank you for the time you spent to read my question.
I'll be using PyQt5 for this explanation. It might have some differences to PySide (which I'm not sure if its still maintained) and PyQt4, but it shouldn't be too hard to convert.
The following example has a parent widget which a few buttons. One of them (the obvious one) calls for the popup. I've prepared the example to deal with the parent resize but have not made any code regarding mouse events of dragging the popup (see mouseMoveEvent and mouseReleaseEvent for that).
So here is the code:
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
class TranslucentWidgetSignals(QtCore.QObject):
# SIGNALS
CLOSE = QtCore.pyqtSignal()
class TranslucentWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(TranslucentWidget, self).__init__(parent)
# make the window frameless
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.fillColor = QtGui.QColor(30, 30, 30, 120)
self.penColor = QtGui.QColor("#333333")
self.popup_fillColor = QtGui.QColor(240, 240, 240, 255)
self.popup_penColor = QtGui.QColor(200, 200, 200, 255)
self.close_btn = QtWidgets.QPushButton(self)
self.close_btn.setText("x")
font = QtGui.QFont()
font.setPixelSize(18)
font.setBold(True)
self.close_btn.setFont(font)
self.close_btn.setStyleSheet("background-color: rgb(0, 0, 0, 0)")
self.close_btn.setFixedSize(30, 30)
self.close_btn.clicked.connect(self._onclose)
self.SIGNALS = TranslucentWidgetSignals()
def resizeEvent(self, event):
s = self.size()
popup_width = 300
popup_height = 120
ow = int(s.width() / 2 - popup_width / 2)
oh = int(s.height() / 2 - popup_height / 2)
self.close_btn.move(ow + 265, oh + 5)
def paintEvent(self, event):
# This method is, in practice, drawing the contents of
# your window.
# get current window size
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
qp.setPen(self.penColor)
qp.setBrush(self.fillColor)
qp.drawRect(0, 0, s.width(), s.height())
# drawpopup
qp.setPen(self.popup_penColor)
qp.setBrush(self.popup_fillColor)
popup_width = 300
popup_height = 120
ow = int(s.width()/2-popup_width/2)
oh = int(s.height()/2-popup_height/2)
qp.drawRoundedRect(ow, oh, popup_width, popup_height, 5, 5)
font = QtGui.QFont()
font.setPixelSize(18)
font.setBold(True)
qp.setFont(font)
qp.setPen(QtGui.QColor(70, 70, 70))
tolw, tolh = 80, -5
qp.drawText(ow + int(popup_width/2) - tolw, oh + int(popup_height/2) - tolh, "Yep, I'm a pop up.")
qp.end()
def _onclose(self):
print("Close")
self.SIGNALS.CLOSE.emit()
class ParentWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ParentWidget, self).__init__(parent)
self._popup = QtWidgets.QPushButton("Gimme Popup!!!")
self._popup.setFixedSize(150, 40)
self._popup.clicked.connect(self._onpopup)
self._other1 = QtWidgets.QPushButton("A button")
self._other2 = QtWidgets.QPushButton("A button")
self._other3 = QtWidgets.QPushButton("A button")
self._other4 = QtWidgets.QPushButton("A button")
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self._popup)
hbox.addWidget(self._other1)
hbox.addWidget(self._other2)
hbox.addWidget(self._other3)
hbox.addWidget(self._other4)
self.setLayout(hbox)
self._popframe = None
self._popflag = False
def resizeEvent(self, event):
if self._popflag:
self._popframe.move(0, 0)
self._popframe.resize(self.width(), self.height())
def _onpopup(self):
self._popframe = TranslucentWidget(self)
self._popframe.move(0, 0)
self._popframe.resize(self.width(), self.height())
self._popframe.SIGNALS.CLOSE.connect(self._closepopup)
self._popflag = True
self._popframe.show()
def _closepopup(self):
self._popframe.close()
self._popflag = False
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = ParentWidget()
main.resize(500, 500)
main.show()
sys.exit(app.exec_())
Which results in the following:
The logic is the following. You create an empty Widget and manually draw the background and popup (paintEvent). You add a button for closing the popup. For this you build a Signal and let the parent widget do the closing. This is important because you need to make the parent widget control some important elements of the popup (such as closing, resizng, etc.). You can add far more complexity but hopefully the example will suffice for starters.
Thanks to armatita, I succeed to get what I wanted. For now, there are some issues but it works and I get the result that I wanted.
I give you the code to the next who will be looking for the same thing.
from PySide import QtCore, QtGui
import sys
class CtmWidget(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.button = QtGui.QPushButton("Close Overlay")
self.setLayout(QtGui.QHBoxLayout())
self.layout().addWidget(self.button)
self.button.clicked.connect(self.hideOverlay)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
path = QtGui.QPainterPath()
path.addRoundedRect(QtCore.QRectF(self.rect()), 10, 10)
mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
pen = QtGui.QPen(QtCore.Qt.white, 1)
painter.setPen(pen)
painter.fillPath(path, QtCore.Qt.white)
painter.drawPath(path)
painter.end()
def hideOverlay(self):
self.parent().hide()
class Overlay(QtGui.QWidget):
def __init__(self, parent, widget):
QtGui.QWidget.__init__(self, parent)
palette = QtGui.QPalette(self.palette())
palette.setColor(palette.Background, QtCore.Qt.transparent)
self.setPalette(palette)
self.widget = widget
self.widget.setParent(self)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.fillRect(event.rect(), QtGui.QBrush(QtGui.QColor(0, 0, 0, 127)))
painter.end()
def resizeEvent(self, event):
position_x = (self.frameGeometry().width()-self.widget.frameGeometry().width())/2
position_y = (self.frameGeometry().height()-self.widget.frameGeometry().height())/2
self.widget.move(position_x, position_y)
event.accept()
class MainWindow(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.resize(800, 500)
self.button = QtGui.QPushButton("Click Me")
self.setLayout(QtGui.QVBoxLayout())
self.layout().addWidget(self.button)
self.popup = Overlay(self, CtmWidget())
self.popup.hide()
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
self.popup.show()
print "clicked"
def resizeEvent(self, event):
self.popup.resize(event.size())
event.accept()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Once again thank you both of you(ymmx and armatita) to spend time on my issue.
did you try replacing popup.show() by popup.exec_()? and remove self as a parameter of the Qdialog? I change QDialog to QmessageBox to be able to quit the subwindow but it still work with the QDialog.
popup = QMessageBox()
popup.setWindowFlags( Qt.FramelessWindowHint)
popup.setLayout( QHBoxLayout())
popup.layout().addWidget( QLabel("HI"))
popup.exec_()
update
class Popup(QDialog ):
def __init__(self):
super().__init__()
self.setWindowFlags( Qt.CustomizeWindowHint)
self.setLayout( QHBoxLayout())
Button_close = QPushButton('close')
self.layout().addWidget( QLabel("HI"))
self.layout().addWidget( Button_close)
Button_close.clicked.connect( self.close )
self.exec_()
print("clicked")
def mousePressEvent(self, event):
self.oldPos = event.globalPos()
def mouseMoveEvent(self, event):
delta = QPoint (event.globalPos() - self.oldPos)
#print(delta)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPos()
class MainWindow( QWidget):
def __init__(self):
QWidget.__init__(self)
self.resize(800, 500)
self.button = QPushButton("Click Me")
self.setLayout( QVBoxLayout())
self.layout().addWidget(self.button)
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
Popup( )
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

What is the best way of deleting a qpushbutton

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

pyQt Hover event with Svg image

I've been working on this for some time now and I can't figure out what I'm doing wrong. I hope someone here can help.
I'm trying to get hover events to work when I mouse over an Svg item that's in a QGraphicsScene. Here's the code that I've been playing with.
#!/usr/bin/python
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtSvg import *
class Main(QWidget):
def __init__(self):
super(Main, self).__init__()
hbox = QHBoxLayout()
self.setLayout(hbox)
self.view = MyView(self)
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
hbox.addWidget(self.view)
class MyView(QGraphicsView):
def __init__(self, parent):
super(MyView, self).__init__(parent)
self.parent = parent
def mousePressEvent(self, event):
super(MyView, self).mousePressEvent(event)
test = MySvg()
self.parent.scene.addItem(test.image)
class MySvg(QGraphicsSvgItem):
def __init__(self):
super(MySvg, self).__init__()
self.image = QGraphicsSvgItem('ubuntu.svg')
self.image.setFlags(QGraphicsItem.ItemIsSelectable|
QGraphicsItem.ItemIsMovable)
self.setAcceptsHoverEvents(True)
def hoverEnterEvent(self, event):
print 'Enter'
def hoverLeaveEvent(self, event):
print 'Leave'
def hoverMoveEvent(self, event):
print 'Moving'
def runMain():
app = QApplication(sys.argv)
ex = Main()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
runMain()
Hope someone can help.
You are monitoring hover events for MySvg but you are adding another QGraphicsSvgItem to the view that is just an instance (MySvg.image) in MySvg. Your MySvg is not even in the view. Try like this:
#!/usr/bin/python
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtSvg import *
class Main(QWidget):
def __init__(self):
super(Main, self).__init__()
hbox = QHBoxLayout()
self.setLayout(hbox)
self.view = MyView(self)
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
hbox.addWidget(self.view)
class MyView(QGraphicsView):
def __init__(self, parent):
super(MyView, self).__init__(parent)
self.parent = parent
def mousePressEvent(self, event):
super(MyView, self).mousePressEvent(event)
test = MySvg()
self.parent.scene.addItem(test)
class MySvg(QGraphicsSvgItem):
def __init__(self):
super(MySvg, self).__init__('ubuntu.svg')
self.setFlags(QGraphicsItem.ItemIsSelectable|
QGraphicsItem.ItemIsMovable)
self.setAcceptsHoverEvents(True)
def hoverEnterEvent(self, event):
print 'Enter'
def hoverLeaveEvent(self, event):
print 'Leave'
def hoverMoveEvent(self, event):
print 'Moving'
def runMain():
app = QApplication(sys.argv)
ex = Main()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
runMain()

Categories

Resources