Форум сайта python.su
Посмотрите примеры реализации dragEnterEvent в примерах, там надо проверить наличие в MimeData нужных данных (изображение или что-то другое, в зависимости от того как реализуете) и подтвердить это (event.setAccepted(True)). Иначе, dropEvent не будет вызываться.
Добираться до объекта QDrag не нужно, всё что переносите, храниться в mimeData, так что тут стоит задуматься, как переносить информацию… Можно запихнуть изображение целиком (поток данных), можно просто путь к файлу изображения, сами решайте как вам удобнее…
кстати, правильно ли это?Да, вроде правильно делаете.
Офлайн
Сделал, но коряво до ужаса.
Картинки, которые необходимы для примера (должны лежать рядом с примером): http://stream.ifolder.ru/9445057 (архив 30 Кб).
Код примера (пригоден для запуска):
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 600, 500)
# создание сцены для отображения элементов-рисунков:
self.scene = Scene()
# создание виджета представления для отображения сцены:
view = QtGui.QGraphicsView(self.scene, self)
# параметры качества прорисовки для виджета представления:
view.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform)
view.setBackgroundBrush(QtGui.QColor(0, 128, 64)) # цвет фона представления
self.setCentralWidget(view) # размещение виджета представления в главном окне
# первый элемент:
item = Element(QtGui.QPixmap(u'011.jpg'), None, self.scene)
item.setZValue(1)
# второй элемент (с поворотом)
item2 = Element(QtGui.QPixmap(u'113.jpg'), None, self.scene)
item2.rotate(25) # поворот
item2.setOffset(100, -30) # смещение
item2.setZValue(2)
class Scene(QtGui.QGraphicsScene):
def __init__(self, parent = None):
QtGui.QGraphicsScene.__init__(self, parent)
self.dndElement = None
self.dndPixmap = None
# операция drag and drop входит в область сцены
def dragEnterEvent(self, event):
pass
# операция drag and drop покидает область сцены
def dragLeaveEvent(self, event):
pass
# в процессе выполнения операции drag and drop
def dragMoveEvent(self, event):
pass
# завершение операции drag and drop
def dropEvent(self, event):
# создание копии перенесённого элемента на новом месте:
item = Element(self.dndPixmap, None, self)
item.setOffset(event.scenePos().x() - 80, event.scenePos().y() - 110)
# удаление перенесённого элемента:
self.removeItem(self.dndElement)
self.dndElement = None
self.dndPixmap = None
class Element(QtGui.QGraphicsPixmapItem):
def __init__(self, pixmap, parent = None, scene = None):
QtGui.QGraphicsPixmapItem.__init__(self, pixmap, parent, scene)
self.setTransformationMode(QtCore.Qt.SmoothTransformation) # качество прорисовки
self.setCursor(QtCore.Qt.OpenHandCursor) # вид курсора мыши над элементом
#self.setAcceptDrops(True)
def mousePressEvent(self, event):
if event.button() != QtCore.Qt.LeftButton: # только левая клавиша мыши
event.ignore()
return
drag = QtGui.QDrag(event.widget()) # объект Drag
mime = QtCore.QMimeData()
drag.setMimeData(mime)
self.scene().dndElement = self # запоминаем элемент, который переносится
self.scene().dndPixmap = self.pixmap()
drag.setPixmap(self.pixmap()) # рисунок, отображающийся в процессе переноса
drag.setHotSpot(QtCore.QPoint(80, 110)) # позиция "ухватки"
# x = int(self.mapToScene(event.scenePos()).x())
# y = int(self.mapToScene(event.scenePos()).y())
# drag.setHotSpot(QtCore.QPoint(x, y))
# временный "затемнённый" рисунок перетаскиваемой картинки
tempPixmap = QtGui.QPixmap(self.pixmap())
painter = QtGui.QPainter()
painter.begin(tempPixmap)
painter.fillRect(self.pixmap().rect(), QtGui.QColor(127, 127, 127, 127))
painter.end()
self.setPixmap(tempPixmap)
drag.start() # запуск (начало) перетаскивания
if __name__=="__main__":
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
Офлайн
:-)
Да… Это проблема, что люди, изучающие PyQt забывают, что пишут на питоне. Сам проходил. Слишком уж много Сишности в этом Qt… :-)
def mousePressEvent(self, event):
drag = QtGui.QDrag(event.widget()) # объект Drag
mime = QtCore.QMimeData()
mime.Element = self
drag.setMimeData(mime)
def dropEvent(self, event):
print event.mimeData().Element
Офлайн
Блин, ты мемя совсем запутал! Ну на кой, простите, хрен ты использовал QGraphicsItem::setOffset()? Используй QGraphicsItem::setPos()! Тогда QGraphicsSceneMouseEvent::pos() будет точно возвращать тебе нужные координаты: drag.setHotSpot(event.pos().toPoint()). И никаких матриц…
Дальше, я думаю, справишься.
Офлайн
ZZZ я бы всё же посоветовал не хакать по-питонски (mime.Element = self) и усложнять жизнь разработчику… можно ведь обойтись “правильным” способом переноса данных (mime.setData(mtype, data)) драг&дропом, который уже будет в себе иметь понятный интерфейс (mtype). Такой подход будет универсальным, т.е. можно будет передавать данные не только в пределах одного приложения… Этот человек пишет пример, в том числе и для того чтобы других учить, а твой пример я считаю не хорошим в этом плане:(
Отредактировано (Дек. 9, 2008 04:28:41)
Офлайн
ZZZНе понял. Вопрос в том, что я не пойму, что именно там за виджет сидит, в моём случае. Это не мой элемент-наследник QGraphicsPixmapItem, это не сцена, это не её QGraphicsView, и это не главное окно. Что это тогда? У меня больше никаких объектов-то нет :).
Ещё обрати внимание на QDropEvent::source(), это разрешит второй вопрос и более Qt'шно решит первый.
Офлайн
Да, кстати: ZZZ, огромное спасибо за участие :) poltergeist - тоже :).
Офлайн
ZZZСпасибо, шикарненько :). Никогда не отдавал себе отчёта в этом…
print event.mimeData().Element
class MyClass():
pass
obj = MyClass()
obj.bla_bla = 'Python is debauched!'
print obj.bla_bla
Отредактировано (Дек. 9, 2008 13:44:41)
Офлайн
Кажется, осилил.
Офлайн
Привет. Поздравляю. :)
А вот вариант решения на PyGTK. По-моему проще. Ухваченная картинка ложится всегда сверху ( по идее, так и должно быть). Движение на второй картинке(av3435.gif - движущийся пингвин в моем профиле) сохраняется.
#!/usr/bin/python
# coding: utf-8
import pygtk
from gtk import *
import time
class DNDImageButton:
file1 ="/home/mike/Desktop/lena.jpg"
file2 ="/home/mike/Desktop/av3435.gif"
fromImage=[("",0,0),("",0,0)]
toCanvas=[("",0,0)]
def __init__(self):
################### хэши - для распознавания кнопок ############################
global HASH,HASH1,HASH2
self.window = Window(WINDOW_TOPLEVEL)
self.window.set_default_size(500, 500)
self.window.connect("destroy", lambda w: main_quit())
self.window.show()
layout = self.makeLayout()
self.window.add(layout)
self.myaddImage(100, 100, self.file1)
self.myaddImage(200, 200, self.file2)
################### установки layout-a ###########################
def layout_resize(self, widget, event):
x, y, width, height = widget.get_allocation()
if width > self.lwidth or height > self.lheight:
self.lwidth = max(width, self.lwidth)
self.lheight = max(height, self.lheight)
widget.set_size(self.lwidth, self.lheight)
def makeLayout(self):
self.lwidth = 0
self.lheight = 0
box = VBox()
box.show()
table = Table()
table.show()
box.pack_start(table)
layout = Layout()
self.layout = layout
layout.set_size(self.lwidth, self.lheight)
layout.connect("size-allocate", self.layout_resize)
layout.show()
table.attach(layout, 0, 1, 0, 1, FILL|EXPAND, FILL|EXPAND, 0, 0)
################### испускаем сигналы при перетаскивании ##########################
layout.connect('drag_leave', self.target_drag_leave)
layout.connect('drag_motion', self.target_drag_motion)
layout.connect('drag_drop', self.target_drag_drop)
layout.connect("drag_data_received", self.receiveCallback)
################### установки цели ##########################
layout.drag_dest_set(DEST_DEFAULT_MOTION |
DEST_DEFAULT_HIGHLIGHT |
DEST_DEFAULT_DROP,
self.toCanvas, gdk.ACTION_MOVE )
return box
####################### устаеавл. виджет в коорд. xd, yd ##########################
def myaddImage(self, xd, yd, f):
global HASH,HASH1,HASH2
hadj = self.layout.get_hadjustment()
vadj = self.layout.get_vadjustment()
image = Image()
image.set_from_file(f)
button = Button()
button.add(image)
if f == self.file1:
HASH1 = button.__hash__()
else:
HASH2 = button.__hash__()
####################### соединяем виджет ##########################
button.connect('button_press_event', self.button_press)
button.connect("drag_data_get", self.sendCallback)
button.connect('drag_data_delete', self.delete_cb)
button.connect("drag_data_received", self.receiveCallback)
###################### установки источника ##########################
button.drag_source_set(gdk.BUTTON1_MASK, self.fromImage, gdk.ACTION_MOVE )
button.show_all()
self.layout.put(button, int(xd+hadj.value), int(yd+vadj.value))
print 'create button'
return
####################### функции CALLBACK ##########################
def button_press(self,button,event):
global HASH,HASH1,HASH2
print 'button_press'
HASH = button.__hash__()
def sendCallback(self, widget, context, selection, targetType, eventTime):
print "send_cb "
selection.set(selection.target, 8, "")
def receiveCallback(self, widget, context, x, y, selection, targetType, time):
global HASH,HASH1,HASH2
print "receive_cb "
if HASH == HASH1:
self.myaddImage(x,y,self.file1)
else:
self.myaddImage(x,y,self.file2)
def delete_cb(self, widget, context):
print "delete_cb "
widget.hide_on_delete()
def target_drag_leave(self, widget, context, time):
print 'leave'
def target_drag_motion(self, widget, context, x, y, time):
print 'motion'
print x,y
def target_drag_drop(self, widget, context, x, y, time):
print 'drop'
####################################################################
####################################################################
DNDImageButton()
main()
Офлайн