Announcement

Collapse
No announcement yet.

TMenuItem.OnClick() wird ignoriert

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • TMenuItem.OnClick() wird ignoriert

    Hallo Forum,

    bin am verzweifeln.

    Ein Popupmenü wird zur Laufzeit mit Menüeinträgen wie folgt bestückt:

    Menu.Items.Clear;

    For i:=0 to Liste_mit_Objekten.Counz-1 do
    Begin

    .......

    AMenuItem := TMenuItem.Create(Menu);
    AMenuItem.Tag := i;
    AMenuItem.Caption := irgend_ein_Caption;
    AMenuItem.Bitmap := irgend_ein_BMP;
    AMenuItem.OnClick := MenuItem_OnClick;

    Menu.Items.Add(AMenuItem);
    .........

    End;


    "Menu" ist ein aufs Formular gezogenes Popupmenü.
    Weil ich faul bin, hab ich einen Dummy-Menüeintrag eingefügt und das entsprechende OnClick-Methoden-Gerüst erzeugen lassen.


    Wenn das Popupmenü via Menu.PopUp(x,y) zur Anzeige gebracht wird, ist jedes Item an seinem Platz.

    Jedoch wird bei einer entsprechenden Auswahl, das OnClick-Ereignis ignoriert.

    Wird jedoch in ein Untermenü verzweigt, wird die "MenuItem_OnClick" - Methode aufgerufen.

    Ich arbeite seit 10 Jahren mit Delphi aber hier bin ich mit meinem Latein am Ende und bin für jede Art von Hilfe dankbar

    thomas

  • #2
    Hallo Thomas,

    mit Deinem obigen Beispiel werden aber doch keine Untermenus erzeugt?

    In Deinem Code kann ich jetzt keinen Fehler entdecken. Wir machen das so:

    Code:
      
    var
      mi : TMenuItem;
      hstrl : TStringList;
      i : Integer;
    begin
      pmPrinted.Items.Clear;
    
      hstrl := TStringList.Create;
    
      hstrl Füllen
    
      for i := 0 to hstrl.Count-1 do
      begin
        mi := NewItem(hstrl[i],TextToShortCut(''),false,true,OnShowPrinted,0,'');
        mi.ImageIndex := 0;
        mi.Tag := i;
        ...
        pmPrinted.Items.Add(mi);
      end;
      hstrl.Free;
    im OnShowPrinted prüfen wir dann auf den Tag des Senders

    Comment


    • #3
      Hallo Sven,

      Vielen Dank für Deine Antwort.
      Der gesamte Code ist natürlich etwas komplexer.
      Die "Popupmenübestückungsfunktion" ist rekursiv und holt sich zuvor alle notwendigen Informationen vom SQL-Server ab.
      Dadurch egeben sich dann Untermenüs.

      Die vollständige Procedure (Methode) sieht so aus:

      Procedure IrgendEineKlasse.LoadMenuItems(MenuName:String; ASubMenu:TMenuItem);
      Var
      L : TStringList;
      AMenuItem : TMenuItem;

      AItem : TK_StartmenuItem;
      Das ist eine Art "DatenContainer", der im Popupmenü durch einen entsprechenen Eintrag repräsentiert sein soll.
      Die Verbindung zwischen dem TMenuItem und dem TK_StartMenuItem wird
      auch hier über ein TAG realissiert (Index der globalen Liste LMenuItems ).

      i : Integer;
      Begin
      // Liste aller Menüeinträge ermitteln
      L := FetchColumn('Select ID From StartmenuItem Where MenuName='''+MenuName+''' Order By SortOrder');

      For i:=0 to L.Count-1 do
      Begin

      // Infos aus Datenbank abholen ...
      AItem := TK_StartMenuItem.Create;
      AItem.Load(L[i]);

      // Infos parallel in Liste speichern
      LMenuItems.Add(AItem);


      // MenuItem in PopUpMenü generieren
      AMenuItem := TMenuItem.Create(PopUpMenu);
      AMenuItem.Caption := AItem.Caption;
      AMenuItem.Bitmap := AItem.BMP2;
      AMenuItem.Tag := LMenuItems.Count-1;
      AMenuItem.OnDrawItem := MenuItem_OnDrawItem;
      AMenuItem.OnMeasureItem := MenuItem_OnMeasureItem;
      AMenuItem.OnClick := MenuItem_OnClick;

      If Trim(UpperCase(AItem.WM_CODE)) = 'SUBMENU' Then
      Begin
      // Rekursion bei Submenü
      LoadMenuItems(AItem.NAME, AMenuItem);
      End;


      If ASubMenu <> NIL Then ASubMenu.Add(AMenuItem)
      Else PopUpMenu.Items.Add(AMenuItem);

      End;

      L.Free;

      End;


      Beim OnClick-Ereignis wird via (Sender as TMenuItem).Tag der Listeneintrag
      in LStartMenuItems ermittelt und das entsprechene (Container)Objekt gefunden.
      Dort befinden sich dann noch eine Reihe weiterer Informationen, die das Programm für seine Arbeit benötigt.

      (Die "hauseigenen" OwnerDrawItem und MeasureItem sorgen nur dafür, dass das ganze wie das Windows Startmenü aussieht und sollten die OnClick-Logik nicht beeinflussen)

      Ich wollte mich am Anfang nur auf den wesentlichen Teil fokussieren.

      Jetzt hoffe ich, Euch nicht mit zu viel Text zugemüllt zu haben und bin nach wie vor dankbar für jeden Hinweis.

      Comment


      • #4
        Nichts erkennbar auf den ersten Blick.

        Ich würde allerdings, wenn das MenuItem ein Submenu ist, diesem keinen Tag und kein OnClick zuweisen, da ein Submenuitem nocht auf Klicks reagiert (reagieren sollte).

        In diesem Fall sollte natürlich auch kein TK_StartmenuItem erzeugt werden.

        Sven

        Comment


        • #5
          Hallo Sven,

          der Hinweis ist berechtigt - vielen Dank.

          Um das "Geschwür" zu isolieren hab ich mal noch folgendes probiert:

          Man erzeuge ein leeres Formular
          betätigt ALT + F12
          und fügt in die Textansicht folgendes ein:

          object Form1: TForm1
          Left = 605
          Top = 268
          Width = 194
          Height = 131
          Caption = 'Form1'
          Color = clBtnFace
          Font.Charset = DEFAULT_CHARSET
          Font.Color = clWindowText
          Font.Height = -11
          Font.Name = 'MS Sans Serif'
          Font.Style = []
          OldCreateOrder = False
          OnCreate = FormCreate
          PixelsPerInch = 96
          TextHeight = 13
          object Button1: TButton
          Left = 56
          Top = 40
          Width = 75
          Height = 25
          Caption = 'Button1'
          TabOrder = 0
          OnClick = Button1Click
          end
          end

          nach erneutem ALT + F12 sollte dann ein Formular mit Button zu sehen sein

          folgenden Code muss dann noch in die zugehörige Unit kopiert werden
          und schon sollte es kompiliert werden können....

          unit Unit1;

          interface

          uses
          Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
          Dialogs, StdCtrls,Menus;

          type
          TForm1 = class(TForm)
          Button1: TButton;
          procedure Button1Click(Sender: TObject);
          procedure FormCreate(Sender: TObject);
          private
          { Private-Deklarationen }
          StrList : TStringList;
          ItemIndex : Integer;

          Procedure MenuItem_OnClick(Sender:TObject);

          public
          { Public-Deklarationen }
          end;

          var
          Form1: TForm1;

          implementation

          {$R *.dfm}

          procedure TForm1.FormCreate(Sender: TObject);
          begin
          StrList := TStringList.Create;
          StrList.Add('Option1');
          StrList.Add('Option2');
          StrList.Add('Option3');

          ItemIndex := -1;

          end;

          Procedure TForm1.MenuItem_OnClick(Sender:TObject);
          Begin
          //ShowMessage('OnClick');
          if (Sender is TMenuItem) Then ItemIndex := (Sender as TMenuItem).Tag;
          End;



          procedure TForm1.Button1Click(Sender: TObject);
          Var
          PopUpMenu :TPopUpMenu;
          MenuItem,
          SubMenu :TMenuItem;
          i :Integer;
          P :TPoint;

          begin

          PopUpMenu := TPopUpMenu.Create(Self);

          For i:=0 to StrList.Count-1 do
          Begin
          MenuItem := NewItem(StrList[i],TextToShortCut(''),false,true,MenuItem_OnClick,0, '');
          MenuItem.Tag := i;
          PopUpMenu.Items.Add(MenuItem);
          End;

          SubMenu := MenuItem;

          For i:=0 to StrList.Count-1 do
          Begin
          MenuItem := NewItem(StrList[i],TextToShortCut(''),false,true,MenuItem_OnClick,0, '');
          MenuItem.Tag := i;
          SubMenu.Add(MenuItem);
          End;

          P := ClientToScreen(Point(Button1.Left,Button1.Top));

          PopUpMenu.Popup(P.X,P.Y);

          If ItemIndex >= 0 Then ShowMessage(StrList[ItemIndex]);

          PopUpMenu.Free;

          end;



          end.


          Compiliert und staunt ....

          Bei mir wird die OnClick-Methode nicht aktiviert.
          Wenn ich jedoch in das Submenü verzweige, wird dem ItemIndex der Tag der Option3 zugewiesen ....

          Wo liegt mein Denkfehler ?

          Comment


          • #6
            Folgendes funktioniert:

            Code:
            object Form1: TForm1
              Left = 605
              Top = 268
              Width = 194
              Height = 131
              Caption = 'Form1'
              Color = clBtnFace
              Font.Charset = DEFAULT_CHARSET
              Font.Color = clWindowText
              Font.Height = -11
              Font.Name = 'MS Sans Serif'
              Font.Style = []
              OldCreateOrder = False
              OnCreate = FormCreate
              PixelsPerInch = 96
              TextHeight = 13
              object Button1: TButton
                Left = 56
                Top = 40
                Width = 75
                Height = 25
                Caption = 'Button1'
                TabOrder = 0
                OnClick = Button1Click
              end
              object PopupMenu: TPopupMenu
                Left = 16
                Top = 24
              end
            end
            
            
            unit Unit1;
            
            interface
            
            uses
            Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
            Dialogs, StdCtrls,Menus;
            
            type
            TForm1 = class(TForm)
            Button1: TButton;
                PopupMenu: TPopupMenu;
            procedure Button1Click(Sender: TObject);
            procedure FormCreate(Sender: TObject);
            private
            { Private-Deklarationen }
            StrList : TStringList;
            ItemIndex : Integer;
            
            Procedure MenuItem_OnClick(Sender:TObject);
            
            public
            { Public-Deklarationen }
            end;
            
            var
            Form1: TForm1;
            
            implementation
            
            {$R *.dfm}
            
            procedure TForm1.FormCreate(Sender: TObject);
            begin
            StrList := TStringList.Create;
            StrList.Add('Option1');
            StrList.Add('Option2');
            StrList.Add('Option3');
            
            ItemIndex := -1;
            
            end;
            
            Procedure TForm1.MenuItem_OnClick(Sender:TObject);
            Begin
              //ShowMessage('OnClick');
              if (Sender is TMenuItem) Then
              begin
                ItemIndex := (Sender as TMenuItem).Tag;
                ShowMessage(StrList[ItemIndex]);
              end;
            End;
            
            procedure TForm1.Button1Click(Sender: TObject);
            Var
              MenuItem,
              SubMenu :TMenuItem;
              i :Integer;
              P :TPoint;
            begin
              PopUpMenu.Items.Clear;
            
              For i:=0 to StrList.Count-2 do
              Begin
                MenuItem := NewItem(StrList[i],TextToShortCut(''),false,true,MenuItem_OnClick,0, '');
                MenuItem.Tag := i;
                PopUpMenu.Items.Add(MenuItem);
              End;
            
              SubMenu := NewItem(StrList[StrList.Count-1],TextToShortCut(''),false,true,nil,0, '');
              PopUpMenu.Items.Add(SubMenu);
            
              For i:=0 to StrList.Count-1 do
              Begin
                MenuItem := NewItem(StrList[i],TextToShortCut(''),false,true,MenuItem_OnClick,0, '');
                MenuItem.Tag := i;
                SubMenu.Add(MenuItem);
              End;
            
              P := ClientToScreen(Point(Button1.Left,Button1.Top));
            
              PopUpMenu.Popup(P.X,P.Y);
            end;
            
            
            end.
            Sven

            Comment


            • #7
              Hallo Sven,

              zuerst einmal vorab vielen Dank für die Zeit und Mühe, Dich mit meinem Problem auseinanderzusetzen.

              In der Tat es funktioniert wirklich ....

              Das Konstrukt:

              ItemIndex := -1;
              PopUpMenu.Popup(P.X,P.Y);
              ShowMessage(IntToStr(ItemIndex));

              zeigt mir auch, warum die MessageBox in meinem Beispiel ausblieb.
              ItemIndex bleibt nämlich -1 obwohl dieser in der OnClick-Methode via
              ItemIndex := (Sender as TMenuItem).Tag eindeutig gesetzt wird.
              Schließlich gibt ShowMessage() innerhalb der OnClick-Methode die richtige
              Option wieder....

              Verstehen kann ich das nicht, denn PopUpMenu.Popup() kommt doch erst nach erledigter Arbeit zurück.
              Wieso ist in Itemindex nicht der ihm zugewiesene Wert gespeichert.
              - Aber das ist ein ganz anderes Problem...

              Fazit: Prinzipiell funktionierts - Das es in meinem speziellen Fall nicht geht, liegt vermutlich an irgend einer Blödsinnigkeit innerhalb meines drum herum gestrickten Codes.

              Nochmals vielen Dank an Sven für die Beiträge

              Comment


              • #8
                NACHTRAG:

                Das Ganze Problem beruht auf meiner Fehlannahme, dass WÄHREND des PopUpmenu.Popup(x,y) die OnClick-Methode antriggert wird.

                Dem ist nicht so, denn OnClick kommt erst NACH dem PopUp.

                Normalerweise ist der Zeitpunkt völlig unerheblich, nur wenn man jedoch das Popupmenü dynamisch erzeugt und SOFORT nach dem PopUp wieder freigibt,
                hatt die OnClick-Methode niemals im Leben eine faire Chance, aufgerufen zu werden.

                Mit einem schlichten Application.Processmessages unmittelbar nach PopUp(x,y) bekommt OnChange() seinen Auftritt nun doch noch - und es funktioniert...

                Wieder was dazugelernt ;-)

                Comment

                Working...
                X