2012-06-29 5 views
7

Ho un ListView con ViewStyle = vsReport e due menu a comparsa:Come impostare il menu popup per la barra di intestazione di ListView insieme al menu di scelta rapida degli elementi?

  1. colonna menu a comparsa, che voglio aprire quando l'utente clic destro sulla barra di intestazione
  2. voce di menu a comparsa, deve aprirsi quando l'utente che fa clic con il pulsante destro del mouse su qualsiasi elemento di elenco/sottotitolo o spazio vuoto sotto gli elementi.

Qual è il modo più corretto per mostrare i menu? Quali eventi dovrei gestire?

Il problema si verifica quando imposto la proprietà ListView.PopupMenu, il menu popup visualizzato dopo aver fatto clic con il pulsante destro del mouse su qualsiasi punto nel rettangolo client di ListView.

Quando gestisco l'evento ListView.OnColumnRightClick, se si attiva solo dopo aver fatto clic sull'intestazione della colonna, escluso lo spazio libero della barra dell'intestazione (sulla destra delle colonne).

L'evento LisView.OnMouseUp si attiva solo dopo aver fatto clic con il pulsante destro del mouse sugli spazi sotto gli elementi.

+0

Vuoi il popup del menu 'PopupMenuItems' solo quando hai finito un oggetto o anche quando hai finito il sottotitolo? – TLama

+0

@TLama sì, anche in sottositemi – Andrew

risposta

8

Non è necessario utilizzare la proprietà PopupMenu del ListView, lasciarla impostata e si può allegare un gestore per OnContextPopup eventi e lanciare qualunque menu a comparsa vuoi a seconda della posizione. Esempio:

procedure TForm1.ListViewContextPopup(Sender: TObject; MousePos: TPoint; 
    var Handled: Boolean); 
var 
    HeaderRect: TRect; 
    Pos: TPoint; 
begin 
    GetWindowRect(ListView_GetHeader(ListView.Handle), HeaderRect); 
    Pos := ListView.ClientToScreen(MousePos); 
    if PtInRect(HeaderRect, Pos) then 
    PopupMenuColumns.Popup(Pos.X, Pos.Y) 
    else 
    PopupMenuItems.Popup(Pos.X, Pos.Y); 
end; 
+1

Mi picchia. :-) Stavo copiando il mio codice di test dall'IDE per incollare la mia risposta dicendo la stessa cosa quando è apparso il banner "nuova risposta". +1. –

+0

@Ken - Trovo strano quando ciò accade su alcune ore vecchie domande, mi dispiace .. e grazie. :) –

+0

Peccato per me, hai ragione. OnContextPopup! – Andrew

0

Ecco come ho risolto, ma questa soluzione non mi piace. Se ne hai uno migliore, per favore scrivi, lo accetto come corretto.

uses 
    CommCtrl; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    ListView.PopupMenu := TPopupMenu.Create(Self); 
    ListView.PopupMenu.OnPopup := ListViewPopup; 
end; 

procedure TForm1.ListViewPopup(Sender: TObject); 
var 
    Pos: TPoint; 
    SrcMenu: TPopupMenu; 
    I: Integer; 
    MenuItem: TMenuItem; 
    Header: HWND; 
    HeaderRect: TRect; 
    HeaderHeight: Integer; 
begin 
    // Re-filling ListView's popup menu 
    ListView.PopupMenu.Items.Clear(); 

    // Getting header height 
    Header := ListView_GetHeader(ListView.Handle); 
    GetWindowRect(Header, HeaderRect); 
    HeaderHeight := HeaderRect.Bottom - HeaderRect.Top; 
    Pos := ListView.ScreenToClient(ListView.PopupMenu.PopupPoint); 

    // Clicked on header? 
    if Pos.Y < HeaderHeight then 
    SrcMenu := PopupMenuColumns 
    else 
    SrcMenu := PopupMenuItems; 

    // Copying destired menu to ListView.PopupMenu 
    for I := 0 to SrcMenu.Items.Count - 1 do 
    begin 
    MenuItem := TMenuItem.Create(FListViewPopupMenu); 

    with SrcMenu.Items[I] do 
    begin 
     MenuItem.Action := Action; 
     MenuItem.Caption := Caption; 
     MenuItem.ShortCut := ShortCut; 
     MenuItem.Checked := Checked; 
     MenuItem.Enabled := Enabled; 
     MenuItem.OnClick := OnClick; 
     MenuItem.HelpContext := HelpContext; 
     MenuItem.Name := Name; 
     MenuItem.ImageIndex := ImageIndex; 
    end; 

    ListView.PopupMenu.Items.Add(MenuItem); 
    end; 

    ListView.PopupMenu.Images := SrcMenu.Images; 
end; 
+0

Cosa non ti piace di questa soluzione? – NGLN

+0

@NGLN Sembra un po 'strano, quando è necessario copiare le voci di menu. Ho pensato che è possibile scorrere verso il basso fino a livello WinAPI e fare qualcosa lì. – Andrew

3

È possibile semplificarlo notevolmente. Crea il tuo due menu a comparsa (uno ciascuno per la riga di intestazione e le colonne Assegnare il TListView.PopupMenu il menu a comparsa della colonna nell'IDE

Utilizzare questo per il gestore di eventi per il ListView:..

procedure TForm1.ListView1ContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); 
var 
    HeaderRect: TRect; 
    HeaderHeight: Integer; 
    Header: HWnd; 
begin 
    ListView1.PopupMenu := ColumnMenu; // Default to ColumnMenu 
    Header := ListView_GetHeader(ListView1.Handle); 
    GetWindowRect(Header, HeaderRect); 
    HeaderHeight := HeaderRect.Bottom - HeaderRect.Top; 
    if MousePos.Y < HeaderHeight then 
    ListView1.PopupMenu := HeaderMenu; 
end; 

è leggermente diverso dall'approccio di @ Sertac, nel non chiamare ClientToScreen e PtInRect - poiché sappiamo che il punto è all'interno dei limiti di ListView, un semplice test dell'altezza del clic è sufficiente per sapere se ci troviamo nell'area dell'intestazione o della colonna. Garantisce inoltre che vi sia sempre almeno uno dei menu popup assegnati allo ListView in qualsiasi momento.