Buchempfehlung
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
"Der" Petzold, das über 1000 Seiten starke Standardwerk zum Win32-API - besonders nützlich u. a. bei der GUI-Programmierung in FreeBASIC! [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Code-Beispiel

Code-Beispiele » GTK, WxWidgets etc.

Drag and Drop

Lizenz:Erster Autor:Letzte Bearbeitung:
k. A.MitgliedTJF 15.05.2012
DnD_example.bas
Vergrößern
DnD_example.bas

Dieses Beispiel betrifft die Funktion Drag and Drop (DnD = ziehen und ablegen). Diese ist z. B. aus Dateimanagern bekannt, wo Dateien aus einem Fenster (= Ordner) in ein anderes verschoben bzw. kopiert werden können, oder wo z. B. eine Quelltextdatei in einen Editor gezogen und damit geöffnet wird.

Die Möglichkeiten von DnD sind sehr vielfältig. Sie können nicht nur Dateien auf der Festplatte, sondern auch Daten im Speicher betreffen. Es können Texte, Bilder in verschiedenen Formaten oder beliebige Daten ausgetauscht werden, innerhalb einer Applikation von einem Widget zu anderen oder auch zwischen unterschiedlichen Applikationen. Die Vielfalt der Möglichkeiten macht die Implementierung von DnD zu einer anspruchsvollen Programmieraufgabe.

Dieses Beispiel zeigt die Grundlagen für einfaches DnD zwischen zwei Widgets innerhalb derselben Applikation und das Senden eines Textes zu einer externen Applikation. Münzen aus dem Button "coins" können in die Senke "well" gezogen werden, oder auch in eine andere Applikation. Dabei werden die Aufrufe der beteiligten Funktionen / Callbacks protokolliert.

Das Beispiel wurde aus Externer Link!diesem C Quelltext übersetzt. Zum Kompilieren sind Externer Link!aktualisierte GTK+ header erforderlich.

' This is file DnD_example.bas, an example for GTK Drag and Drop
'
' Licence: GPLv3
' (C) 2011-2012 Thomas[ dot ]Freiherr[ at ]gmx[ dot ]net
' translated from C source:
'   http://live.gnome.org/GnomeLove/DragNDropTutorial

'/* TestDnD - main.c : Simple tutorial for GTK+ Drag-N-Drop
 '* Copyright (C) 2005 Ryan McDougall.
 '*
 '*  This program is free software; you can redistribute it and/or modify
 '*  it under the terms of the GNU General Public License as published by
 '*  the Free Software Foundation; either version 2 of the License, or
 '*  (at your option) any later version.
 '*
 '*  This program is distributed in the hope that it will be useful,
 '*  but WITHOUT ANY WARRANTY; without even the implied warranty of
 '*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 '*  GNU Library General Public License for more details.
 '*
 '*  You should have received a copy of the GNU General Public License
 '*  along with this program; if not, write to the Free Software
 '*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 '*/

#IFNDEF __FB_UNIX__
#LIBPATH "C:\opt\gtk\lib"
#ENDIF

#INCLUDE ONCE "gtk/gtk.bi"
#INCLUDE ONCE "string.bi"


'/******************************************************************************/
#DEFINE _BYTE   8
#DEFINE _WORD   16
#DEFINE _DWORD  32


'/******************************************************************************/
'/* Define a list of data types called "targets" that a destination widget will
 '* accept. The string type is arbitrary, and negotiated between DnD widgets by
 '* the developer. An enum or GQuark can serve as the integer target id. */
ENUM
  TARGET_INT32
  TARGET_STRING
  TARGET_ROOTWIN
END ENUM

'/* datatype (string), restrictions on DnD (GtkTargetFlags), datatype (int) */
STATIC AS GtkTargetEntry target_list(...) = { _
  TYPE( @"INTEGER",    0, TARGET_INT32 ), _
  TYPE( @"STRING",     0, TARGET_STRING ), _
  TYPE( @"text/plain", 0, TARGET_STRING ), _
  TYPE( @"application/x-rootwindow-drop", 0, TARGET_ROOTWIN ) _
}

'STATIC AS guint n_targets = G_N_ELEMENTS (target_list)
STATIC SHARED AS guint n_targets
n_targets = UBOUND (target_list) + 1


'/******************************************************************************/
'/* Signal receivable by destination */

'/* Emitted when the data has been received from the source. It should check
 '* the GtkSelectionData sent by the source, and do something with it. Finally
 '* it needs to finish the operation by calling gtk_drag_finish, which will emit
 '* the "data-delete" signal if told to. */
SUB drag_data_received_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL x AS gint, _
  BYVAL y AS gint, _
  BYVAL selection_data AS GtkSelectionData PTR, _
  BYVAL target_type AS guint, _
  BYVAL _time_ AS guint, _
  BYVAL data_ AS gpointer)

  DIM AS glong   PTR _idata
  DIM AS gchar   PTR _sdata

  DIM AS gboolean dnd_success = FALSE
  DIM AS gboolean delete_selection_data = FALSE

  DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
  g_print (!"%s: drag_data_received_handl\n", name_)


  '/* Deal with what we are given from source */
  IF((selection_data <> NULL) ANDALSO (selection_data-> length >= 0)) THEN
    IF (context-> action = GDK_ACTION_ASK) THEN
    '/* Ask the user to move or copy, then set the context action. */
    END IF

    IF (context-> action = GDK_ACTION_MOVE) THEN delete_selection_data = TRUE

    '/* Check that we got the format we can use */
    g_print (" Receiving ")
    SELECT CASE AS CONST (target_type)
    CASE TARGET_INT32
      _idata = CAST(glong PTR, selection_data->data)
      g_print ("integer: %ld", *_idata)
      dnd_success = TRUE

    CASE TARGET_STRING:
      _sdata = CAST(gchar PTR, selection_data->data)
      g_print ("string: %s", _sdata)
      dnd_success = TRUE

    CASE ELSE
      g_print ("nothing good")
    END SELECT

    g_print (!".\n")
  END IF

  IF (dnd_success = FALSE) THEN g_print (!"DnD data transfer failed!\n")

  gtk_drag_finish (context, dnd_success, delete_selection_data, _time_)
END SUB

'/* Emitted when a drag is over the destination */
FUNCTION drag_motion_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL x AS gint, _
  BYVAL y AS gint, _
  BYVAL t AS guint, _
  BYVAL user_data AS gpointer) AS gboolean

  '// Fancy stuff here. This signal spams the console something horrible.
  'DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
  'g_print (!"%s: drag_motion_handl\n", name_)
  RETURN  FALSE
END FUNCTION

'/* Emitted when a drag leaves the destination */
SUB drag_leave_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL _time_ AS guint, _
  BYVAL user_data AS gpointer)

  DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
  g_print (!"%s: drag_leave_handl\n", name_)
END SUB

'/* Emitted when the user releases (drops) the selection. It should check that
 '* the drop is over a valid part of the widget (if its a complex widget), and
 '* itself to return true if the operation should continue. Next choose the
 '* target type it wishes to ask the source for. Finally call gtk_drag_get_data
 '* which will emit "drag-data-get" on the source. */
FUNCTION drag_drop_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL x AS gint, _
  BYVAL y AS gint, _
  BYVAL _time_ AS guint, _
  BYVAL user_data AS gpointer) AS gboolean

  DIM AS gboolean        is_valid_drop_site
  DIM AS GdkAtom         target_type

  DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
  g_print (!"%s: drag_drop_handl\n", name_)

  '/* Check to see if (x,y) is a valid drop site within widget */
  is_valid_drop_site = TRUE

  '/* If the source offers a target */
  IF (context-> targets) THEN
    '/* Choose the best target type */
    target_type = GDK_POINTER_TO_ATOM(g_list_nth_data (context-> targets, TARGET_INT32))

    '/* Request the data from the source. */
    gtk_drag_get_data( _
            widget, _        /* will receive 'drag-data-received' signal */
            context, _       /* represents the current state of the DnD */
            target_type, _   /* the target TYPE we want */
            _time_ _         /* TIME stamp */
    )
  '/* No target offered by source => error */
  ELSE
    is_valid_drop_site = FALSE
  END IF

  RETURN  is_valid_drop_site
END FUNCTION


'/******************************************************************************/
'/* Signals receivable by source */

'/* Emitted after "drag-data-received" is handled, and gtk_drag_finish is called
 '* with the "delete" parameter set to TRUE (when DnD is GDK_ACTION_MOVE). */
SUB drag_data_delete_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL user_data AS gpointer)

  '// We aren't moving or deleting anything here
  DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
  g_print (!"%s: drag_data_delete_handl\n", name_)
END SUB

'/* Emitted when the destination requests data from the source via
 '* gtk_drag_get_data. It should attempt to provide its data in the form
 '* requested in the target_type passed to it from the destination. If it cannot,
 '* it should default to a "safe" type such as a string or text, even if only to
 '* print an error. Then use gtk_selection_data_set to put the source data into
 '* the allocated selection_data object, which will then be passed to the
 '* destination. This will cause "drag-data-received" to be emitted on the
 '* destination. GdkSelectionData is based on X's selection mechanism which,
 '* via X properties, is only capable of storing data in blocks of 8, 16, or
 '* 32 bit units. */
SUB drag_data_get_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL selection_data AS GtkSelectionData PTR, _
  BYVAL target_type AS guint, _
  BYVAL _time_ AS guint, _
  BYVAL user_data AS gpointer)

  DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
  DIM AS CONST gchar PTR string_data = @"This is data from the source."
  DIM AS CONST glong integer_data = 42

  g_print (!"%s: drag_data_get_handl\n", name_)
  g_assert (selection_data <> NULL)

  g_print (" Sending ")
  SELECT CASE AS CONST (target_type)
  '/* case TARGET_SOME_OBJECT:
   '* Serialize the object and send as a string of bytes.
   '* Pixbufs, (UTF-8) text, and URIs have their own convenience
   '* setter functions */

  CASE TARGET_INT32
    g_print ("integer: %ld", integer_data)
    gtk_selection_data_set( _
            selection_data, _          /* Allocated GdkSelectionData object */
            selection_data->target, _  /* target TYPE */
            _DWORD, _                  /* number of bits per 'unit' */
            CAST(guchar PTR, @integer_data), _ /* POINTER TO DATA TO be sent */
            SIZEOF (integer_data) _    /* length of DATA in units */
    )

  CASE TARGET_STRING
    g_print ("string: %s", string_data)
    gtk_selection_data_set( _
            selection_data, _
            selection_data->target, _
            _BYTE, _
            CAST(guchar PTR, string_data), _
            strlen (string_data) _
    )

  CASE TARGET_ROOTWIN
    g_print (!"Dropped on the root window!\n")

  CASE ELSE
    '/* Default to some a safe target instead of fail. */
    g_assert_not_reached ()

  END SELECT

  g_print (!".\n")
END SUB

'/* Emitted when DnD begins. This is often used to present custom graphics. */
SUB drag_begin_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL user_data AS gpointer)

  DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
  g_print (!"%s: drag_begin_handl\n", name_)
END SUB

'/* Emitted when DnD ends. This is used to clean up any leftover data. */
SUB drag_end_handl CDECL( _
  BYVAL widget AS GtkWidget PTR, _
  BYVAL context AS GdkDragContext PTR, _
  BYVAL user_data AS gpointer)

    DIM AS CONST gchar PTR name_ = gtk_widget_get_name (widget)
    g_print (!"%s: drag_end_handl\n", name_)
END SUB


'/******************************************************************************/
'main
DIM AS GtkWidget PTR window_
DIM AS GtkWidget PTR hbox
DIM AS GtkWidget PTR coin_source
DIM AS GtkWidget PTR well_dest
DIM AS GtkWidget PTR directions_label
DIM AS guint     win_xsize       = 450
DIM AS guint     win_ysize       = 50
DIM AS guint     spacing         = 5


'/* Always start GTK+ first! */
gtk_init (@__FB_ARGC__, @__FB_ARGV__)


'/* Create the widgets */
window_ = gtk_window_new (GTK_WINDOW_TOPLEVEL)
hbox    = gtk_hbox_new (FALSE, spacing)

coin_source     = gtk_button_new_with_label ("[coins]")
well_dest       = gtk_label_new ("[a well]")

directions_label = gtk_label_new ("drag a coin and drop it in the well")


'/* Pack the widgets */
gtk_container_add (GTK_CONTAINER (window_), hbox)

gtk_container_add (GTK_CONTAINER (hbox), coin_source)
gtk_container_add (GTK_CONTAINER (hbox), directions_label)
gtk_container_add (GTK_CONTAINER (hbox), well_dest)


'/* Make the window big enough for some DnD action */
gtk_window_set_default_size (GTK_WINDOW(window_), win_xsize, win_ysize)


'/* Make the "well label" a DnD destination. */
gtk_drag_dest_set( _
        well_dest, _              /* widget that will accept a drop */
        GTK_DEST_DEFAULT_MOTION _ /* default actions for dest on dnd */
        OR GTK_DEST_DEFAULT_HIGHLight, _
        @target_list(0), _        /* lists of target to support */
        n_targets, _              /* size of list */
        GDK_ACTION_COPY _         /* what to do with data after dropped */
)

'/* Make the "coin button" a DnD source. */
'/* Why doesn't GtkLabel work here?
 '* See Caveat Window above
 '*/
gtk_drag_source_set( _
        coin_source, _           /* widget will be drag-able */
        GDK_BUTTON1_MASK, _      /* modifier that will start a drag */
        @target_list(0), _       /* lists of target to support */
        n_targets, _             /* size of list */
        GDK_ACTION_COPY _        /* what to do with data after dropped */
)


'/* Connect the signals */
g_signal_connect (window_, "destroy", G_CALLBACK (@gtk_main_quit), NULL)

'/* All possible destination signals */
g_signal_connect (well_dest, "drag-data-received", _
        G_CALLBACK(@drag_data_received_handl), NULL)

g_signal_connect (well_dest, "drag-leave", _
        G_CALLBACK (@drag_leave_handl), NULL)

g_signal_connect (well_dest, "drag-motion", _
        G_CALLBACK (@drag_motion_handl), NULL)

g_signal_connect (well_dest, "drag-drop", _
        G_CALLBACK (@drag_drop_handl), NULL)

'/* All possible source signals */
g_signal_connect (coin_source, "drag-data-get", _
        G_CALLBACK (@drag_data_get_handl), NULL)

g_signal_connect (coin_source, "drag-data-delete", _
        G_CALLBACK (@drag_data_delete_handl), NULL)

g_signal_connect (coin_source, "drag-begin", _
        G_CALLBACK (@drag_begin_handl), NULL)

g_signal_connect (coin_source, "drag-end", _
        G_CALLBACK (@drag_end_handl), NULL)


'/* Show the widgets */
gtk_widget_show_all (window_)

'/* Start the even loop */
gtk_main ()

English

See Externer Link!this forum thread.


Zusätzliche Informationen und Funktionen
  • Das Code-Beispiel wurde am 14.05.2012 von MitgliedTJF angelegt.
  • Die aktuellste Version wurde am 15.05.2012 von MitgliedTJF gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen