Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 5, 2008 21:26:27

gmorgunov
От:
Зарегистрирован: 2008-10-15
Сообщения: 137
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

Привет всем.
Пробовал рисовать картинки на PyGtk и столкнулся с тем, что в примерах по drap_and_drop картинки размножаются :). Смотрел здесь:http://www.pygtk.org/pygtk2tutorial/sec-DNDMethods.html.
И в примерах, поставляемых с PyGtk - только схематичная реализация drag_and_drop.(./usr/lib/pygtk/2.0/demos/dnd.py)Поискал на форуме, в интернете и ответа не нашел. Пришлось разбираться самому.Вот что получилось. На первый взгляд программа кажется сложной, но если приглядеться, то многое становится интуитивно понятно. В инете встречал вопросы по drag_and_drop, так что думаю кому-нибудь это пригодится.Картинка упакована в gtk.Button. В дальнейшем попробую реализовать для gtk.DrawingArea.

dndimage.py

#!/usr/bin/python
# coding: utf-8

import pygtk
import gtk
import string, time
import gtkxpm

class DNDImageButton:
TARGET_TYPE_TEXT = 80
TARGET_TYPE_PIXMAP = 81
fromImage = [ ( "text/plain", 0, TARGET_TYPE_TEXT ),
( "", 0, TARGET_TYPE_PIXMAP ) ]
toButton = [ ( "text/plain", 0, TARGET_TYPE_TEXT ) ]
toCanvas = [ ( "", 0, TARGET_TYPE_PIXMAP ) ]
################### установки 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 = gtk.VBox(False,0)
box.show()
table = gtk.Table(2, 2, False)
table.show()
box.pack_start(table, True, True, 0)
layout = gtk.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, gtk.FILL|gtk.EXPAND,
gtk.FILL|gtk.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(gtk.DEST_DEFAULT_MOTION |
gtk.DEST_DEFAULT_HIGHLIGHT |
gtk.DEST_DEFAULT_DROP,
self.toCanvas, gtk.gdk.ACTION_MOVE )
self.addImage(gtkxpm.gtk_xpm, 0, 0)

return box

####################### устанавл. виджет в коорд. xd, yd ##########################
def addImage(self, xpm, xd, yd):
hadj = self.layout.get_hadjustment()
vadj = self.layout.get_vadjustment()
style = self.window.get_style()
pixmap, mask = gtk.gdk.pixmap_create_from_xpm(
self.window.window, style.bg[gtk.STATE_NORMAL], "/home/mike/Desktop/lena.jpg") #<-----------
image = gtk.Image()
image.set_from_pixmap(pixmap, mask)
button = gtk.Button()
button.add(image)
####################### соединяем виджет ##########################
button.connect("drag_data_get", self.sendCallback)
button.connect('drag_data_delete', self.delete_cb)
###################### установки источника ##########################
button.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
gtk.gdk.ACTION_MOVE )
button.show_all()

self.layout.put(button, int(xd+hadj.value), int(yd+vadj.value))
return

####################### функции CALLBACK ##########################
def sendCallback(self, widget, context, selection, targetType, eventTime):
print "send_cb "
if targetType == self.TARGET_TYPE_PIXMAP:
selection.set(selection.target, 8,
string.join(gtkxpm.gtk_xpm, '\n'))

def receiveCallback(self, widget, context, x, y, selection, targetType,
time):
print "receive_cb "
if targetType == self.TARGET_TYPE_PIXMAP:
self.addImage(gtkxpm.gtk_xpm, x, y)


###################### функция удаления прежнего виджета ##########################
def delete_cb(self, widget, context):
print "delete_cb "
widget.destroy()

def target_drag_leave(self, widget, context, time):
print 'leave'

def target_drag_motion(self, widget, context, x, y, time):
print 'motion'

def target_drag_drop(self, widget, context, x, y, time):
print 'drop'

########################################################################################
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_default_size(400, 400)
self.window.connect("destroy", lambda w: gtk.main_quit())
self.window.show()
layout = self.makeLayout()
self.window.add(layout)
########################################################################################
DNDImageButton()
gtk.main()
В консоли печатаются вызовы всех callback-ов.По-моему очень простой и интересный механизм.
Попутный вопрос: кто-нибудь реализовывал метод rotate() для PyGtk ?
Если есть решение, отпишите пожалуйста, буду признателен.
The Gray Cardinal
По-моему качество изображения ничуть не хуже, чем в PyQt. Правда не знаю, как поведут себя картинки
при повороте. Если удастся решить вашу задачу на PyGtk, обязательно отпишу. :)

P.S. Для правильной работы примера см. посты ниже



Отредактировано (Дек. 6, 2008 05:26:41)

Офлайн

#2 Дек. 5, 2008 23:14:50

The gray Cardinal
От:
Зарегистрирован: 2007-03-07
Сообщения: 422
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

Я не пойму, где взять модуль gtkxpm.



Офлайн

#3 Дек. 5, 2008 23:54:50

gmorgunov
От:
Зарегистрирован: 2008-10-15
Сообщения: 137
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

The gray Cardinal
Я не пойму, где взять модуль gtkxpm.
Забыл прикрепить этот модуль. Он взят из примера по ссылке http://www.pygtk.org/pygtk2tutorial/sec-DNDMethods.html . Вот он(должен лежать рядом с dndimage.py:

gtkxpm.py
# example gtkxpm.py

gtk_xpm = [
"32 39 5 1",
". c none",
"+ c black",
"@ c #3070E0",
"# c #F05050",
"$ c #35E035",
"................+...............",
"..............+++++.............",
"............+++++@@++...........",
"..........+++++@@@@@@++.........",
"........++++@@@@@@@@@@++........",
"......++++@@++++++++@@@++.......",
".....+++@@@+++++++++++@@@++.....",
"...+++@@@@+++@@@@@@++++@@@@+....",
"..+++@@@@+++@@@@@@@@+++@@@@@++..",
".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
".+##++@@@@+++@@@+++++@@@@@@@@$@.",
".+###++@@@@+++@@@+++@@@@@++$$$@.",
".+####+++@@@+++++++@@@@@+@$$$$@.",
".+#####+++@@@@+++@@@@++@$$$$$$+.",
".+######++++@@@@@@@++@$$$$$$$$+.",
".+#######+##+@@@@+++$$$$$$@@$$+.",
".+###+++##+##+@@++@$$$$$$++$$$+.",
".+###++++##+##+@@$$$$$$$@+@$$@+.",
".+###++++++#+++@$$@+@$$@++$$$@+.",
".+####+++++++#++$$@+@$$++$$$$+..",
".++####++++++#++$$@+@$++@$$$$+..",
".+#####+++++##++$$++@+++$$$$$+..",
".++####+++##+#++$$+++++@$$$$$+..",
".++####+++####++$$++++++@$$$@+..",
".+#####++#####++$$+++@++++@$@+..",
".+#####++#####++$$++@$$@+++$@@..",
".++####++#####++$$++$$$$$+@$@++.",
".++####++#####++$$++$$$$$$$$+++.",
".+++####+#####++$$++$$$$$$$@+++.",
"..+++#########+@$$+@$$$$$$+++...",
"...+++########+@$$$$$$$$@+++....",
".....+++######+@$$$$$$$+++......",
"......+++#####+@$$$$$@++........",
".......+++####+@$$$$+++.........",
".........++###+$$$@++...........",
"..........++##+$@+++............",
"...........+++++++..............",
".............++++..............."
]
Это образ кубика gtk. Пока не разобрался зачем он нужен, но на нем завязаны начальные установки.



Офлайн

#4 Дек. 6, 2008 11:21:03

The gray Cardinal
От:
Зарегистрирован: 2007-03-07
Сообщения: 422
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

Спасибо, теперь запускается.
Но работает он неправильно. При перетаскивании, за какое бы место картинки я не “взялся”, при отпускании картинка перемещается так, что её верхний левый угол оказывается на месте курсора мыши. Это довольно увечное перетаскивание :). И совершенно непонятна роль gtkxpm.py. По идее, он не должен быть нужен вообще, его присутствие выглядит как-то нелепо.



Отредактировано (Дек. 6, 2008 11:21:51)

Офлайн

#5 Дек. 6, 2008 13:27:03

gmorgunov
От:
Зарегистрирован: 2008-10-15
Сообщения: 137
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

А по-моему неплохо. :) За какое бы место картинки не ухватился, появляется стрелочка и рука. Стрелочка показывает куда приземлить виджет, рука сигнализирует о том, что мы делаем( перетаскиваем).
Этот файл gtkxpm.py отложил до лучших времен( со временем надеюсь пойму, что и как).Это первый шаг. Ближайшая цель - приспособить drag_and_drop к этому:

#!/usr/bin/env python
# coding: utf-8
import pygtk
import gtk

class DrawingAreaExample:
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.connect("destroy", lambda w: gtk.main_quit())
self.area = gtk.DrawingArea()
self.area.set_size_request(400, 300)
self.sw = gtk.ScrolledWindow()
self.sw.add_with_viewport(self.area)
self.table = gtk.Table(2,2)
self.table.attach(self.sw, 1, 2, 1, 2)
window.add(self.table)
self.area.connect("expose-event", self.area_expose_cb)
self.area.show()
self.sw.show()
self.table.show()
window.show()

def area_expose_cb(self, area, event):
self.style = self.area.get_style()
self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
self.mydraw_pixmap(0, 0, "/home/mike/Desktop/lena.jpg")
return True

def mydraw_pixmap(self, x, y, file):
pix, mask = gtk.gdk.pixmap_create_from_xpm(
self.area.window, self.style.bg[gtk.STATE_NORMAL], file)

self.area.window.draw_drawable(self.gc, pix, 0, 0, x, y,
-1, -1)
return


if __name__ == "__main__":
DrawingAreaExample()
gtk.main()
Запустите и сравните с PyQt. :)
P.S. Я занимаюсь GTK недавно, так что у самого полно вопросов. ( Сейчас разбираюсь с иерархией виджетов)



Офлайн

#6 Дек. 6, 2008 14:08:09

The gray Cardinal
От:
Зарегистрирован: 2007-03-07
Сообщения: 422
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

gmorgunov
За какое бы место картинки не ухватился, появляется стрелочка и рука. Стрелочка показывает куда приземлить виджет, рука сигнализирует о том, что мы делаем( перетаскиваем).
Не, не согласен :). Вот, например, на рабочем столе можно перетаскивать окна при нажатом Alt. Представь, что это работало бы так же :). При отпускании перетаскиваемый объект делает конвульсивный прыжок. Я сначала даже не понял, что вообще происходит :). Это слишком неожиданно для пользователя, противоречит общепринятому.
gmorgunov
Запустите и сравните с PyQt.
Да, по первому впечатлению, качество картинки даже выше, чем у PyQt4 :).
Но на данном этапе я хочу всё же поковырять именно PyQt4, она вроде в целом мощнее.
Где бы нам взять 10 жизней, чтобы оценить все технологии? ;)



Офлайн

#7 Дек. 6, 2008 16:17:06

gmorgunov
От:
Зарегистрирован: 2008-10-15
Сообщения: 137
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

У меня почему-то никаких прыжков не происходит. Да, бывало, когда эту прогу “раскачивал”. Но сейчас все нормально, логично. И с Alt - тоже.
Качество картинки в PyGTK действительно выше( спросил жену, она у меня - эксперт). :)
Вы почаще ставьте такие задачки( с картами). В деле и сравним достинства той и другой библиотеки.
А ведь на PyQt мы ее полностью-то не решили. Посмотрим как на GTK. :)



Отредактировано (Дек. 6, 2008 16:17:52)

Офлайн

#8 Дек. 7, 2008 12:57:19

gmorgunov
От:
Зарегистрирован: 2008-10-15
Сообщения: 137
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

Вот окончательный вариант drag_and_drop картинок, размещенных в кнопке.
Просто вставьте свою картинку(file=/home/mike/Desktop/lena.jpg) и запустите программу.
В консоли будут печататся ваши действия при drag_and_drop.

#!/usr/bin/python
# coding: utf-8

import pygtk
from gtk import *
import time

class DNDImageButton:
file = "/home/mike/Desktop/lena.jpg"
fromImage=[("",0,0),("",0,0)]
toCanvas=[("",0,0)]
################### установки 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 )
self.myaddImage(0, 0)
return box
####################### устаеавл. виджет в коорд. xd, yd ##########################
def myaddImage(self, xd, yd):
hadj = self.layout.get_hadjustment()
vadj = self.layout.get_vadjustment()
image = Image()
image.set_from_file(self.file)
button = Button()
button.add(image)
####################### соединяем виджет ##########################
button.connect("drag_data_get", self.sendCallback)
button.connect('drag_data_delete', self.delete_cb)
###################### установки источника ##########################
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))
return

####################### функции CALLBACK ##########################
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):
print "receive_cb "
self.myaddImage(x, y)

def delete_cb(self, widget, context):
print "delete_cb "
widget.destroy()
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'

def target_drag_drop(self, widget, context, x, y, time):
print 'drop'

########################################################################################
def __init__(self):
self.window = Window(WINDOW_TOPLEVEL)
self.window.set_default_size(400, 400)
self.window.connect("destroy", lambda w: main_quit())
self.window.show()
layout = self.makeLayout()
self.window.add(layout)
########################################################################################
DNDImageButton()
main()



Офлайн

#9 Дек. 7, 2008 13:38:00

The gray Cardinal
От:
Зарегистрирован: 2007-03-07
Сообщения: 422
Репутация: +  0  -
Профиль   Отправить e-mail  

PyGtk. Drag_and_drop картинок.

Спасибо, хороший пример.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version