OnDropText() is carried out twice when used with image list

Hello!

I am trying to write a program with that I can assign images to
Products.

I have an imagelist that contains some images.
Via Drag and Drop, I transfer the selected image name into a text
field.
After the drag operation I want the image to be deleted from the
imagelist. For that I use the function: deleteFirstItemFromImageList()
After deleting, I refresh the image list. For that I use the function:
assignTextsAndShowImageList()

My Problem:
When I drag the image to the target text field: the OnDropText() is
carried out twice!
This leads to: the first and the second image name is inserted into
the text field. And the first and second image is deleted from the
imagelist!

Note 1:
This problem occurs on Windows.
When I run the program on Linux (ubuntu) the OnDropText() is only
carried out once (as expected).

Note 2:
When I (on Windows) run the function assignTextsAndShowImageList_1()
instead, then the OnDropText() is only carried out once (as
expected).
But this function does not refresh the imagelist correctly :frowning:

Note 3:
I have created a button that does the same thing (call
deleteFirstItemFromImageList() and assignTextsAndShowImageList()).
The button works perfectly on Windows and Ubuntu.

Has anyone got an idea?

Here the complete code. In order to run it, you need a folder named
"bilder" with some images in the same directory...

···

#
--------------------------------------------------------------------------------------
###

#Boa:Frame:Frame1

import wx
import glob

# Define Text Drop Target class
class TextDropTarget(wx.TextDropTarget):

    def __init__(self, obj):
        wx.TextDropTarget.__init__(self)
        self.obj = obj

    def OnDropText(self, x, y, data):
        # When text is dropped, write it into the object specified
        self.obj.WriteText(data + '\n\n')

        # and remove the item from the image list
        deleteFirstItemFromImageList(self.self_frame1)
        assignTextsAndShowImageList(self.self_frame1) # if this
function is called, OnDropText is carried twice!
        #assignTextsAndShowImageList_1(self.self_frame1) # if this
function is called, OnDropText is only carried out once

#
-----------------------------------------------------------------------------------

def create(parent):
    return Frame1(parent)

[wxID_FRAME1, wxID_FRAME1BTN_LOAD, wxID_FRAME1BUTTON1,
wxID_FRAME1LISTCTRL1,
wxID_FRAME1PANEL1, wxID_FRAME1STATICTEXT1, wxID_FRAME1TEXTCTRL1,
] = [wx.NewId() for _init_ctrls in range(7)]

class Frame1(wx.Frame):

    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAME1, name='Frame1',
parent=prnt,
              pos=wx.Point(366, 66), size=wx.Size(618, 466),
              style=wx.DEFAULT_FRAME_STYLE, title='Bildertool')
        self.SetClientSize(wx.Size(610, 439))
        self.Bind(wx.EVT_CLOSE, self.OnFrame1Close)

        self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1',
parent=self,
              pos=wx.Point(0, 0), size=wx.Size(610, 439),
              style=wx.TAB_TRAVERSAL)

        self.listCtrl1 = wx.ListCtrl(id=wxID_FRAME1LISTCTRL1,
name='listCtrl1',
              parent=self.panel1, pos=wx.Point(48, 48),
size=wx.Size(424, 352),
              style=wx.LC_ICON)
        self.listCtrl1.Bind(wx.EVT_LIST_ITEM_SELECTED,
              self.OnListCtrl1ListItemSelected,
id=wxID_FRAME1LISTCTRL1)

        self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
              label='Drop Target:', name='staticText1',
parent=self.panel1,
              pos=wx.Point(47, 14), size=wx.Size(89, 18), style=0)
        self.staticText1.SetToolTipString('')

        self.btn_load = wx.Button(id=wxID_FRAME1BTN_LOAD, label='load
images',
              name='btn_load', parent=self.panel1, pos=wx.Point(496,
84),
              size=wx.Size(100, 23), style=0)
        self.btn_load.Bind(wx.EVT_BUTTON, self.OnBtn_loadButton,
              id=wxID_FRAME1BTN_LOAD)

        self.textCtrl1 = wx.TextCtrl(id=wxID_FRAME1TEXTCTRL1,
name='textCtrl1',
              parent=self.panel1, pos=wx.Point(140, 12),
size=wx.Size(220, 21),
              style=0, value='')

        self.button1 = wx.Button(id=wxID_FRAME1BUTTON1,
              label='delete first item', name='button1',
parent=self.panel1,
              pos=wx.Point(496, 120), size=wx.Size(100, 23), style=0)
        self.button1.Bind(wx.EVT_BUTTON, self.OnButton1Button,
              id=wxID_FRAME1BUTTON1)

    def __init__(self, parent):
        self._init_ctrls(parent)

        # Create a Text Drop Target object
        dt1 = TextDropTarget(self.textCtrl1)
        # Link the Drop Target Object to the Text Control
        self.textCtrl1.SetDropTarget(dt1)

        TextDropTarget.self_frame1 = self # slightly unelegant
way. I want to refer to
                                              # objects in "Frame1"

    def OnBtn_loadButton(self, event):
        # Bilder vom angegebenen Pfad laden

        self.il = wx.ImageList(100, 100, True)
        self.names = []

        wx.InitAllImageHandlers()

        for name in glob.glob("bilder/*"):
            image = wx.Image(name, wx.BITMAP_TYPE_ANY)
            width = image.GetWidth()
            height = image.GetHeight()
            thumbnail_size = 100
            if width < height:
                thumbnail_width = thumbnail_size
                factor = width / thumbnail_size
                thumbnail_height = height / factor
            else:
                thumbnail_height = thumbnail_size
                factor = height / thumbnail_size
                thumbnail_width = width / factor
            image = image.Rescale(thumbnail_width, thumbnail_height)
            bmp = wx.BitmapFromImage(image, depth = -1)
            self.names.append(name)
            self.il_max = self.il.Add(bmp)

        assignTextsAndShowImageList(self)

    def OnListCtrl1ListItemSelected(self, event):
       """ Begin a Drag Operation """

       itemSelected = event.GetItem()
       dragText = itemSelected.GetText()

       tdo = wx.PyTextDataObject(dragText)

       tds = wx.DropSource(self.listCtrl1)
       tds.SetData(tdo)
       tds.DoDragDrop(True)

    def OnButton1Button(self, event):
        deleteFirstItemFromImageList(self)
        assignTextsAndShowImageList(self)

    def OnFrame1Close(self, event):
        self.Destroy()

#
-------------------------------------------------------------------------

def assignTextsAndShowImageList(self):
    self.listCtrl1.ClearAll()

    il_max = self.il.GetImageCount()

    self.listCtrl1.SetImageList(self.il, wx.IMAGE_LIST_NORMAL)

    for x in range(il_max):
        self.listCtrl1.InsertImageStringItem(x, self.names[x], x)

def assignTextsAndShowImageList_1(self):
    # this function only refreshes the images, but the filenames
remain...
    self.listCtrl1.Refresh()

def deleteFirstItemFromImageList(self):
    self.il.Remove(0)
    del self.names[0]

#
-------------------------------------------------------------------------

class BoaApp(wx.App):
    def OnInit(self):
        self.main = create(None)
        self.main.Show()
        self.SetTopWindow(self.main)
        return True

def main():
    application = BoaApp(0)
    application.MainLoop()

if __name__ == '__main__':
    main()

#
--------------------------------------------------------------------------------------
###

My versions:
Python: 2.7.2
WxPython:2.8.12.1

Many thanks,
Leon

Please attach your code to the message so it does not get word-wrapped. You can make attachments if you use email to send the message or you can also do it in the new (beta) version of the Google Groups UI.

···

On 10/5/11 9:27 AM, Leon wrote:

Hello!

I am trying to write a program with that I can assign images to
Products.

I have an imagelist that contains some images.
Via Drag and Drop, I transfer the selected image name into a text
field.
After the drag operation I want the image to be deleted from the
imagelist. For that I use the function: deleteFirstItemFromImageList()
After deleting, I refresh the image list. For that I use the function:
assignTextsAndShowImageList()

My Problem:
When I drag the image to the target text field: the OnDropText() is
carried out twice!
This leads to: the first and the second image name is inserted into
the text field. And the first and second image is deleted from the
imagelist!

Note 1:
This problem occurs on Windows.
When I run the program on Linux (ubuntu) the OnDropText() is only
carried out once (as expected).

Note 2:
When I (on Windows) run the function assignTextsAndShowImageList_1()
instead, then the OnDropText() is only carried out once (as
expected).
But this function does not refresh the imagelist correctly :frowning:

Note 3:
I have created a button that does the same thing (call
deleteFirstItemFromImageList() and assignTextsAndShowImageList()).
The button works perfectly on Windows and Ubuntu.

Has anyone got an idea?

Here the complete code. In order to run it, you need a folder named
"bilder" with some images in the same directory...

My versions:
Python: 2.7.2
WxPython:2.8.12.1

--
Robin Dunn
Software Craftsman

oh sorry. Here it comes…

Frame1.py (5.88 KB)

You are getting more than one drop because you are calling DoDragDrop from a EVT_LIST_ITEM_SELECTED handler and when you manipulate the items in the list then there can be additional selection events. Doing the DoDragDrop from a EVT_LIST_BEGIN_DRAG event handler would be more appropriate, since a DnD is supposed to be a "Drag" after all, not a selection.

···

On 10/5/11 9:27 AM, Leon wrote:

Hello!

I am trying to write a program with that I can assign images to
Products.

I have an imagelist that contains some images.
Via Drag and Drop, I transfer the selected image name into a text
field.
After the drag operation I want the image to be deleted from the
imagelist. For that I use the function: deleteFirstItemFromImageList()
After deleting, I refresh the image list. For that I use the function:
assignTextsAndShowImageList()

My Problem:
When I drag the image to the target text field: the OnDropText() is
carried out twice!
This leads to: the first and the second image name is inserted into
the text field. And the first and second image is deleted from the
imagelist!

Note 1:
This problem occurs on Windows.
When I run the program on Linux (ubuntu) the OnDropText() is only
carried out once (as expected).

Note 2:
When I (on Windows) run the function assignTextsAndShowImageList_1()
instead, then the OnDropText() is only carried out once (as
expected).
But this function does not refresh the imagelist correctly :frowning:

Note 3:
I have created a button that does the same thing (call
deleteFirstItemFromImageList() and assignTextsAndShowImageList()).
The button works perfectly on Windows and Ubuntu.

Has anyone got an idea?

--
Robin Dunn
Software Craftsman

wow! That was it.
Thank you VERY much!
:slight_smile: