2009-05-25 8 views
1

J'ai un tableau de boutons qui appellent tous la même méthode mais avec l'index du bouton comme argument.C#: Obtenir quel bouton a été enfoncé dans un tableau de boutons # gtk?

using System; 
using Gtk; 

public class Input : Gtk.Window { 

    private Gtk.Button[] plus; 

    public Input() : base(Gtk.WindowType.Toplevel) { 

     plus = new Button[10]; 

[...]

 for (uint i = 0; i < 10; i++) { 
      plus[i] = new Button(); 
      plus[i].Name = i.ToString(); 
      plus[i].ButtonPressEvent += AddButtonPressed; 
     } 
    } 

Je l'ai essayé en utilisant cette méthode, mais il semble qu'il se même pas appelé car il n'y a pas de sortie:

protected virtual void AddButtonPressed(object sender, System.EventArgs e) { 
     Console.WriteLine("Button pressed"); 
     for (uint i = 0; i < plus.Length; i++) { 
     if (sender.Equals(plus[i])) { 
      uint index = i; 
      i = (uint)plus.Length; 
      Console.WriteLine(index); 
     } 
    } 

Peut-être que quelqu'un peut me pointer dans la bonne direction? Merci.

Répondre

2

réponse rapide:

[GLib.ConnectBefore] 
protected virtual void AddButtonPressed(object sender, EventArgs e)  { 
    Console.WriteLine("Button pressed"); 
    for (uint i = 0; i < plus.Length; i++) { 
     if (sender.Equals(plus[i])) { 
     uint index = i; 
     i = (uint)plus.Length; 
     Console.WriteLine(index); 
     } 
    } 
} 

explication Rambling:

Ceci est en fait une question intéressante. Il a fallu un peu de recherche à trouver, mais GTK#'s FAQ (mais je suppose que pas souvent liée à) dit,

« Avec la version 0.15, Gtk # a commencé en utilisant le drapeau connect_after lors reliant les gestionnaires d'événements aux signaux. cela signifie que les gestionnaires d'événements sont ne courir qu'après le signal par défaut gestionnaires, ce qui signifie que le widget sera mis à jour lorsque l'événement exécution des gestionnaires. Un effet secondaire de ce changement est que dans le cas où défaut les gestionnaires retournent à pour signaler la propagation du signal, Gtk # eve nts ne sera pas émis. C'est le cas pour l'exemple dans Gtk.Button, où le gestionnaire de signal par défaut de bouton-presse-événement-événement est ignoré pour émettre des événements pressés.

Bien que potentiellement confus, c'est pas vraiment un bug. Lorsque vous utilisez un Gtk.Button, vous obtenez un widget qui émet des événements pressés en réponse à des pressions Button1. Si vous voulez également votre bouton pour changer les couleurs, ou un menu contextuel sur les presses Button3, ce n'est pas un Gtk.Button. La bonne façon de mettre en œuvre un tel widget est sous-classe Gtk.Button et remplacer la méthode virtuelle OnButtonPressEvent à mettre en œuvre les nouveaux comportements que vous souhaitez ."

S'il n'y avait pas, « tollé général »(rarement un signe d'une bonne interface), il n'y aurait aucun moyen d'éviter cela, sauf subclassing qui est parfois gênant en C# en raison du manque de Heureusement, vous n'êtes pas la première personne à avoir ce problème.C'est donc là que l'attribut GLib.ConnectBefore entre en jeu. Il dit en gros, appelez ce gestionnaire d'événements d'abord pour que l'événement ne soit pas dévoré par Gtk +

L'ennui ne s'arrête pas là: à l'origine, je proposais d'appliquer une bonne solution éprouvée pour passer des paramètres "supplémentaires" aux gestionnaires d'événements, ce qui vous permettrait de trouver l'index sans Name chaîne Il essentiellement je mpl quent la création d'un délégué wrapper qui « fait semblant » d'être un ButtonPressEventHandler mais passe en interne un entier à votre méthode de support:

Func<uint, ButtonPressEventHandler> indexWrapper = ((index) => ((s, e) => { AddButtonPressed_wrapped(s, e, index); })); 

    ... 

    plus[i].ButtonPressEvent += indexWrapper(i); 

    ... 

    protected virtual void AddButtonPressed_wrapped(object sender, EventArgs e, uint index) 
    { 
     Console.WriteLine("Button pressed"); 
     Console.WriteLine("Index = {0}", index); 
    } 

Il compile, et fonctionne sans erreur, mais il a le même problème, l'événement ne se déclenche. J'ai réalisé que vous ne pouvez pas mettre un attribut directement sur un délégué/lambda. Donc, même si la méthode de sauvegarde a [GLib.ConnectBefore] le délégué ne fonctionne pas, donc il échoue. Pour finir, vous pouvez utiliser l'événement Clicked comme dans this API example. J'ai vérifié que cela fonctionne comme prévu. On pourrait penser qu'il ne se déclencherait que sur des clics de souris, mais il se déclencherait aussi sur la barre d'espace.

+0

J'ai pris le chemin court hacky pour l'instant ;-) Merci pour cette réponse très détaillée et votre temps investi! Une petite correction d'ailleurs: ça doit être [GLib.ConnectBeforeAttribute] –

+0

En fait, ça marche dans les deux sens. Voir http://www.go-mono.com/docs/index.aspx?link=C%3AGtk.ButtonPressEventArgs. Je viens aussi de trouver http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx, qui dit "Par convention, tous les noms d'attribut se terminent par le mot" Attribute "pour les distinguer des autres Dans le .NET Framework, vous n'avez pas besoin de spécifier le suffixe d'attribut lorsque vous utilisez des attributs dans le code. " –

0

Je suis assez certain que vous devez réellement ajouter les boutons à la hiérarchie de la fenêtre GTK, quelque chose comme:

for (uint i = 0; i < 10; i++) { 
     plus[i] = new Button(); 
     plus[i].Name = i.ToString(); 
     plus[i].ButtonPressEvent += AddButtonPressed; 
     Add(plus[i]); 
    } 

devrait être similaire à celle, jamais réellement utilisé GTK <. <

+0

Ils sont tous ajoutés correctement à un Vbox et montré lors de l'exécution du programme, mais en appuyant sur les boutons ne fonctionne pas. Désolé, je pensais que c'était clair ... –

+0

Eh bien j'ai essayé! – Blindy

+0

merci cependant ;-) –

0

Utilisez la propriété Tag, si le bouton Gtk en a un.

for (uint i = 0; i < 10; i++) { 
    plus[i] = new Button(); 
    plus[i].Name = i.ToString(); 
    plus[i].ButtonPressEvent += AddButtonPressed; 
    plus[i].Tag = i; 
    Add(plus[i]); 
} 

Handler:

protected virtual void AddButtonPressed(object sender, System.EventArgs e) { 
    Console.WriteLine("Button pressed"); 
    Gtk.Button button = sender as Gtk.Button; 
    Console.WriteLine("Index: {0}", button.Tag); 
} 
+0

Bien Gtk.Button n'a pas de propriété "Tag", mais j'ai essayé d'utiliser le Name comme identifiant qui devrait fonctionner de la même manière. En tout cas cela ne m'aide pas avec le problème que la méthode ne sera pas appelée en appuyant sur le bouton, mais merci. –

+0

Vous avez une mauvaise signature de votre gestionnaire d'événements. Ceci provient de la documentation Mono: délégué public void ButtonPressEventHandler (objet o, arguments ButtonPressEventArgs) – mnn

+0

Ceci est faux. Comme vous auriez pu le constater si vous aviez réellement testé, "le groupe de méthodes pour déléguer les conversions est contravariant dans leurs types d'argument" (http://blogs.msdn.com/ericlippert/archive/2007/10/19/covariance-and -contravariance-dans-c-part-trois-membre-groupe-conversion-variance.aspx). Depuis AddButtonPressed accepte/any/EventArgs, il accepte de manière inhérente tout ButtonPressEventArgs, parce que ButtonPressEventArgs sont juste un autre type de EventArgs après tout. –

1
for (uint i = 0; i < 10; i++) 
{ 
    plus[i] = new Button(); 
    plus[i].Data.Add("Index",i); 
    plus[i].ButtonPressEvent += AddButtonPressed; 
    Add(plus[i]); 
} 

Handler:

protected virtual void AddButtonPressed(object sender, System.EventArgs e) { 
    Console.WriteLine("Button pressed"); 
    Gtk.Button button = sender as Gtk.Button; 
    Console.WriteLine("Index: {0}", button.Data["Index"]); 
} 
Questions connexes