Excel Forum - Porady, Pomoc,  Excel Help, Excel FAQ Strona Główna
 FAQ  RegulaminRegulamin  Szukaj   Użytkownicy   Grupy   Rejestracja   Profil   Twoje wiadomości   Zaloguj 


Poprzedni temat «» Następny temat
ID tematu: 76147 Skopiuj do schowka 2 poziomowe dynamiczne Context Menu
Autor Wiadomość
kloszuu
Stały bywalec Excelforum


Pomógł: 1 raz
Posty: 253
Wysłany: 05-10-2024, 10:54   2 poziomowe dynamiczne Context Menu

Witam,

Chciałbym prosić o pomoc przy zrobieniu dwu pozimowego Context Menu, musi ono być dynamiczne i tworzone na postawie wartości z dwóch kolumn. Przedstawię to na prostym przykładzie asortymentu sklepowego.

W załączonym Pliku mamy trzy poziomy:

Poziom podstawowy (Poziom 0): Jest to ogólny Asortymenty
Poziom 1: Kategorie: Warzywa; Owoce, Nabiał, Pieczywo
Poziom2: Poszczególne artykuły przynależne do tych kategorii.


Po przyciśnięciu prawego przycisku myszy jak widać takie Menu jest tworzone natomiast nie jest ono dynamiczne, a to jest mój główny problem ponieważ zarówno kategorie będę ulegały zmianie jak i artykuły w tych kategoriach. Czy jest możliwe stworzenie takiego menu żeby automatycznie się dostosowywało w zależności od wartości jakie użytkownik wprowadzi w tych poszczególnych kolumnach odpowiadających Pomowi 1 i 2?

Przy tworzeniu Menu musza byc wybierane tylko unikatowe wartosci kategorii. Uzytkownicy beda dodawali nowe artykuly wedlug schematu tabelki przedstawionego w pliku.

Wisienka na torcie by już było gdy jeszcze one były ułożone alfabetycznie.

Pozdrawiam i dziekuje

Piotrek

Przyklad Menu.xlsm
Pobierz Plik ściągnięto 13 raz(y) 21.34 KB

ID posta: 437205 Skopiuj do schowka
 
 
Czeslaw


Pomógł: 279 razy
Posty: 931
Wysłany: 05-10-2024, 12:59   

Power Query
Kod:
let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    #"Grouped Rows" = Table.Group(Source, {"Poziom1"}, {{"Count", each _, type table [Poziom1=text, Poziom2=text]}}),
    #"Added Custom" = Table.AddColumn(#"Grouped Rows", "Custom", each Table.AddIndexColumn([Count],"Index",1,1)),
    #"Expanded Custom" = Table.ExpandTableColumn(#"Added Custom", "Custom", {"Poziom1", "Poziom2", "Index"}, {"Poziom1.1", "Poziom2", "Index"}),
    #"Removed Columns1" = Table.RemoveColumns(#"Expanded Custom",{"Poziom1", "Count"}),
    #"Pivoted Column" = Table.Pivot(#"Removed Columns1", List.Distinct(#"Removed Columns1"[Poziom1.1]), "Poziom1.1", "Poziom2"),
    #"Removed Columns2" = Table.RemoveColumns(#"Pivoted Column",{"Index"})
in
    #"Removed Columns2"


Przyklad Menu(1).xlsm
Pobierz Plik ściągnięto 7 raz(y) 30.46 KB

ID posta: 437206 Skopiuj do schowka
 
 
kloszuu
Stały bywalec Excelforum


Pomógł: 1 raz
Posty: 253
Wysłany: 05-10-2024, 13:16   

Dziekuje za odpowiedz natomiast tego typu rozwiaznie nie moge zaimplementowac do VBA zeby utworzyc Menu dostepne po kliknieciu prawego przycisku myszy tak jak to bylo pokazane w zalaczonym przykladzie.

przyklad.jpg
Plik ściągnięto 16 raz(y) 78.29 KB

ID posta: 437207 Skopiuj do schowka
 
 
Tajan


Pomógł: 5548 razy
Posty: 12042
Wysłany: 05-10-2024, 19:22   

Procedury w Module1 zamień na taki kod:
Kod:
Option Explicit

Dim dane As Object

Sub AddItemContextMenu()
    Dim ContextMenu As CommandBar
    Dim MojeMenu As CommandBarControl
    Dim i As Long, j As Long
   
    InitializeMenuData
   
    Application.CommandBars("Cell").Reset

    Set ContextMenu = Application.CommandBars("cell")

    Set MojeMenu = ContextMenu.Controls.Add(Type:=msoControlPopup, before:=1)

    With MojeMenu
        .Caption = "Asortyment"
        For i = 0 To dane.Count - 1
            With .Controls.Add(Type:=msoControlPopup, before:=1)
                .Tag = "Poziom1"
                .Caption = dane.keys()(i)
                For j = 1 To dane.items()(i).Count
                    With .Controls.Add(Type:=msoControlButton, before:=1)
                        .Tag = "Poziom2"
                        .Caption = dane.items()(i)(j)
                        .OnAction = "'" & ThisWorkbook.Name & "'!" & "module1.dodawanie"
                    End With
                Next
                End With
            Next
           
        End With

    End Sub

Private Sub InitializeMenuData()
    Dim arr, i As Long, j As Long
    Dim kat As String, c As Collection
   
    Set dane = CreateObject("Scripting.Dictionary")
   
    With ThisWorkbook.Sheets(1)
        arr = .Range("C8:E" & .Cells(.Rows.Count, "C").End(xlUp).Row).Value
    End With
   
    For i = 1 To UBound(arr)
        kat = arr(i, 2)
        If Not dane.exists(kat) Then
            Set c = New Collection
            On Error Resume Next
            For j = i To UBound(arr)
                If arr(j, 2) = kat Then c.Add arr(j, 3), arr(j, 3)
            Next
            On Error GoTo 0
            Set dane(kat) = c
        End If
    Next
End Sub

Sub dodawanie()
    Dim nazwa As String
    nazwa = Application.CommandBars.ActionControl.Caption

    MsgBox "Wybrano " & nazwa
End Sub
ID posta: 437210 Skopiuj do schowka
 
 
kloszuu
Stały bywalec Excelforum


Pomógł: 1 raz
Posty: 253
Wysłany: 05-10-2024, 20:04   

Działa super dziękuje za pomoc, szkoda ze jest tylko możliwość dać jeden punkt za pomoc bo to chyba takie proste nie było do zrobienia. Wielki szacunek za wiedze.

Zakładam żeby dodać sortowanie do tego kod to nie będzie takie proste bo musiałbym sortować tablice kilku wymiarowa?

Pozdrawiam

Piotrek
ID posta: 437212 Skopiuj do schowka
 
 
Maciej Gonet 
Excel Expert


Wersja: Win Office 365
Pomógł: 3545 razy
Posty: 10461
Wysłany: 05-10-2024, 21:11   

Nie analizowałem kodu Tajana, bo myślałem nad swoim. Trochę dłużej mi zeszło.
Nie napisałeś nic o wersji Excela, więc nie wiedziałem co zrobić z sortowaniem.
Wybrałem wariant z arkuszem pomocniczym, do którego kopiuję dane i sortuję je metodą klasyczną, a następnie z powrotem do tablicy.
Kod:
Sub AddItemContextMenu()

  ' Czytaj dane i sortuj w arkuszu pomocniczym
   
   Dim Dane
   Dim wk1 As Worksheet, wk2 As Worksheet
   Set wk1 = Worksheets("Przykllad")
   Set wk2 = Worksheets("Pomoc")
   Dane = wk1.Range("C7").CurrentRegion.Value
   wk2.Range("A1").CurrentRegion.Clear
   wk2.Range("A1").Resize(UBound(Dane), UBound(Dane, 2)).Value = Dane
   wk2.Range("A1").CurrentRegion.Sort Key1:=wk2.Range("B1"), Order1:=xlDescending, _
       Key2:=wk2.Range("C1"), Order2:=xlDescending, Header:=xlYes
   Dane = wk2.Range("A1").CurrentRegion.Value
   
   ' utwórz polecenia
   
   Dim ContextMenu As CommandBar
   Dim MojeMenu As CommandBarControl

   Application.CommandBars("Cell").Reset

   Set ContextMenu = Application.CommandBars("cell")
   Set MojeMenu = ContextMenu.Controls.Add(Type:=msoControlPopup, before:=1)
   Dim i As Long, poziom As String
   Dim Grupa As CommandBarPopup
   
   With MojeMenu
       .Caption = Dane(2, 1)  '  "Asortyment"
       For i = 2 To UBound(Dane)
           If poziom <> Dane(i, 2) Then
               Set Grupa = .Controls.Add(Type:=msoControlPopup, before:=1)
               poziom = Dane(i, 2)
           End If
           With Grupa
               .Tag = "Poziom1"
               .Caption = poziom
               
                With .Controls.Add(Type:=msoControlButton, before:=1)
                    .Tag = "Poziom2"
                    .Caption = Dane(i, 3)
                    .OnAction = "dodawanie"   '  "'" & ThisWorkbook.Name & "'!" & "module1.dodawanie"
                End With
           End With
       Next i
   End With
End Sub

Sub dodawanie()
    Dim nazwa As String
    nazwa = Application.CommandBars.ActionControl.Caption

    MsgBox "Wybrano " & nazwa
End Sub


Przyklad Menu.xlsm
Pobierz Plik ściągnięto 8 raz(y) 21.9 KB

ID posta: 437213 Skopiuj do schowka
 
 
kloszuu
Stały bywalec Excelforum


Pomógł: 1 raz
Posty: 253
Wysłany: 05-10-2024, 21:19   

Wersja Excel to będzie najnowsza bo używam Office 365 z najnowszymi uaktualnieniami.

Tez sie zastanawiałem nad ta opcja sortowana danych przed ich załadunkiem, przy moim poziomie programowania nawet osiągalna do wykonania, natomiast obawiam sie o szybkość działania przy użyciu operacji na arkuszu.

Mam pytanie a czy nie można do posortowania tego zakresu w czasie ladowania go do pamięci komputer, użyć wbudowanej formuły aplikacji Excel "Sort"?

Sadze ze tego typu operacje sortowania będzie szybsza w pamięci komputera niż jako operacja na pliku.
ID posta: 437214 Skopiuj do schowka
 
 
ple4
ExcelSpec


Wersja: Win Office 2003
Pomógł: 128 razy
Posty: 518
Wysłany: 05-10-2024, 21:54   

To jeszcze takie "cóś" do kolekcji:
Kod:
Option Explicit

Sub AddItemContextMenu()
    Dim i As Long, j As Long, k As Long
    Dim pn As String
    Dim a, b, c
   
    pn = "'" & ThisWorkbook.Name & "'!" & "Module1.dodawanie"
   
    c = ThisWorkbook.ActiveSheet.Range("C7").CurrentRegion.Value
        With CreateObject("System.Collections.ArrayList")
            For i = 2 To UBound(c, 1)
                If Not .Contains(c(i, 2)) Then .Add c(i, 2)
            Next
                .Sort: a = .ToArray: .Clear
            For i = 2 To UBound(c, 1)
                b = c(i, 2) & "," & c(i, 3)
                If Not .Contains(b) Then .Add b
            Next
                .Sort: b = .ToArray: .Clear
        End With
    c = c(2, 1)
   
    With Application.CommandBars("Cell")
        .Reset
        With .Controls.Add(Type:=msoControlPopup, Before:=1)
            .Tag = "Poziom0"
            .Caption = c
            For i = 0 To UBound(a, 1)
                With .Controls.Add(Type:=msoControlPopup, Before:=i + 1)
                    .Tag = "Poziom1"
                    .Caption = a(i)
                    For j = k To UBound(b, 1)
                        If b(j) Like a(i) & "*" Then
                            With .Controls.Add(Type:=msoControlButton)
                                .Tag = "Poziom2"
                                .Caption = StrConv(Split(b(j), ",", -1, 0)(1), vbProperCase)
                                .OnAction = pn
                            End With
                            k = k + 1
                        Else
                            Exit For
                        End If
                    Next
                End With
            Next
        End With
        .Controls(2).BeginGroup = True
    End With
   
    a = Empty: b = Empty
End Sub
ID posta: 437215 Skopiuj do schowka
 
 
kloszuu
Stały bywalec Excelforum


Pomógł: 1 raz
Posty: 253
  Wysłany: 05-10-2024, 22:06   

wow ple4, super to chyba robi cala robote, dziekuje.

Wielki szacunek dla Was wszystich za wiedze i chec pomoc tym mnie zdolnym jak ja :-)

Pozdrawiam

Piotrek
ID posta: 437216 Skopiuj do schowka
 
 
ple4
ExcelSpec


Wersja: Win Office 2003
Pomógł: 128 razy
Posty: 518
Wysłany: 05-10-2024, 22:16   

kloszuu napisał/a:
chec pomoc tym mnie zdolnym

Dlaczego mniej ... (?) ... każdy kiedyś jakoś zaczynał z czymś co go zainteresowało i nie od razu sobie dobrze radził ...
ID posta: 437218 Skopiuj do schowka
 
 
kloszuu
Stały bywalec Excelforum


Pomógł: 1 raz
Posty: 253
Wysłany: 05-10-2024, 22:23   

@Ple4, mam tylko jedno pytanie do Twojego rozwiazania ten problem nie wystepowal w tych poprzednich propozycjach.

Mianowicie w momencie gdy na Poziomie 1 nie ma wpisanej kategorii tzn jest pozostawiona pusta komorka wowczas ten kod przestaje dzialac prawidlowo. Mozna jakos temu zaradzic, zeby traktowal puste pole jako kategorie i wrzucal tam wszystko bez konkretnie przypisanej kategorii?
ID posta: 437219 Skopiuj do schowka
 
 
Tajan


Pomógł: 5548 razy
Posty: 12042
Wysłany: 05-10-2024, 23:02   

No, to jeszcze moja propozycja uzupełniona o sortowanie:
Kod:
Option Explicit

Dim dane As Object


Sub AddItemContextMenu()
    Dim ContextMenu As CommandBar
    Dim MojeMenu As CommandBarControl
    Dim i As Long, j As Long
    Dim c As Object
    Dim poz1, poz2
   
    InitializeMenuData

    Application.CommandBars("Cell").Reset

    Set ContextMenu = Application.CommandBars("cell")

    Set MojeMenu = ContextMenu.Controls.Add(Type:=msoControlPopup, before:=1)

    With MojeMenu
        .Caption = "Asortyment"
        poz1 = sortuj(dane.keys)
        For i = 0 To UBound(poz1)
            With .Controls.Add(Type:=msoControlPopup, before:=1)
                .Tag = "Poziom1"
                .Caption = poz1(i)
                poz2 = dane(poz1(i))
                For j = 0 To UBound(poz2)
                    With .Controls.Add(Type:=msoControlButton, before:=1)
                        .Tag = "Poziom2"
                        .Caption = poz2(j)
                        .OnAction = "'" & ThisWorkbook.Name & "'!" & "module1.dodawanie"
                    End With
                Next
                End With
            Next

        End With

    End Sub

Private Sub InitializeMenuData()
    Dim arr, i As Long, j As Long
    Dim kat As String, c As Object

    Set dane = CreateObject("Scripting.Dictionary")

    With ThisWorkbook.Sheets(1)
        arr = .Range("C8:E" & .Cells(.Rows.Count, "C").End(xlUp).Row).Value
    End With

    For i = 1 To UBound(arr)
        kat = arr(i, 2)
        If Not dane.exists(kat) Then
            Set c = CreateObject("Scripting.Dictionary")
            For j = i To UBound(arr)
                If arr(j, 2) = kat Then c(arr(j, 3)) = arr(j, 3)
            Next
            dane(kat) = sortuj(c.keys)
        End If
    Next
End Sub


Private Function sortuj(tbl)
    Dim el
    With CreateObject("System.Collections.ArrayList")
        For Each el In tbl
            .Add el
        Next
        .Sort
        .Reverse
        sortuj = .toarray
    End With
End Function

Sub dodawanie()
    Dim nazwa As String
    nazwa = Application.CommandBars.ActionControl.Caption

    MsgBox "Wybrano " & nazwa
End Sub
ID posta: 437220 Skopiuj do schowka
 
 
ple4
ExcelSpec


Wersja: Win Office 2003
Pomógł: 128 razy
Posty: 518
Wysłany: 06-10-2024, 00:18   

kloszuu napisał/a:
gdy na Poziomie 1 nie ma wpisanej kategorii

... można by np. tak:
Kod:
        With CreateObject("System.Collections.ArrayList")
            For i = 2 To UBound(c, 1)
                If Len(Trim$(c(i, 2))) <> 0 Then
                    If Not .Contains(c(i, 2)) Then .Add c(i, 2)
                End If
            Next
                .Sort: a = .ToArray: .Clear
            For i = 2 To UBound(c, 1)
                If Len(Trim$(c(i, 2))) <> 0 Then
                    b = c(i, 2) & "," & c(i, 3)
                    If Not .Contains(b) Then .Add b
                End If
            Next
                .Sort: b = .ToArray: .Clear
        End With

zamiast dotychczasowego bloku z 'ArrayList'.
ID posta: 437223 Skopiuj do schowka
 
 
kloszuu
Stały bywalec Excelforum


Pomógł: 1 raz
Posty: 253
Wysłany: 06-10-2024, 14:36   

Witam ple4,

Chyba bardziej szukalem taiego rozwiazania, troche przerobilem Twoje poniewaz ono wykluczalo artykul jezeli nie mial przypisanej kategorii na Poziomie1. Natomiast ja je klasywfikuje w odrebnej kategorii jako "BRAK"



Kod:

With CreateObject("System.Collections.ArrayList")
            For i = 2 To UBound(c, 1)
                If Len(Trim$(c(i, 2))) <> 0 Then
                    If Not .Contains(c(i, 2)) Then .Add c(i, 2)
                    Else
                    If Not .Contains(c(i, 2)) Then .Add "BRAK"
                End If
            Next
                .Sort: a = .ToArray: .Clear
            For i = 2 To UBound(c, 1)
                If Len(Trim$(c(i, 2))) <> 0 Then
                    b = c(i, 2) & "," & c(i, 3)
                    If Not .Contains(b) Then .Add b
                    Else
                    b = "BRAK" & "," & c(i, 3)
                    If Not .Contains(b) Then .Add b
                End If
            Next
                .Sort: b = .ToArray: .Clear
        End With


Natomiast nie moge sobie poradzic zeby zmodyfikowac Twoj kod tak aby nie bral pod uwage wielosci liter. Moga pojawic sie sytuacje ze jedna osoba napisze "Pieczywo" a druga "pieczywo" to powinna byc nadal jedna kategoria natomiast Twoj kod traktuje je oddzielnie.

Czy mozn cos z tym zrobic?

Pozdrawiam

Piotrek
ID posta: 437238 Skopiuj do schowka
 
 
ple4
ExcelSpec


Wersja: Win Office 2003
Pomógł: 128 razy
Posty: 518
Wysłany: 07-10-2024, 07:07   

kloszuu napisał/a:
Czy mozn cos z tym zrobic?

Taka prośba ... przede wszystkim nie "stopniuj" swoich wymagań, bo z procedury koniec-końców wyjdzie bohomaz a la sałatka po pół litrze dnia następnego, a pisać procedurę od początku za każdym razem, gdy coś sobie "przypomnisz" to nużące się stanie ... :-> ... sprawdź:
Kod:
Option Explicit

Sub AddItemContextMenu()
    Dim i As Long, j As Long, k As Long
    Dim pn As String
    Dim a, b, c
   
    pn = "'" & ThisWorkbook.Name & "'!" & "Module1.dodawanie"
   
    c = ThisWorkbook.ActiveSheet.Range("C7").CurrentRegion.Value
        With CreateObject("System.Collections.ArrayList")
            For i = 2 To UBound(c, 1)
                If Len(Trim$(c(i, 2))) = 0 Then c(i, 2) = "BRAK" _
                    Else c(i, 2) = StrConv(c(i, 2), vbProperCase)
                If Len(Trim$(c(i, 3))) = 0 Then c(i, 3) = "BRAK" _
                    Else c(i, 3) = StrConv(c(i, 3), vbProperCase)
                If Not .Contains(c(i, 2)) Then .Add c(i, 2)
            Next
                .Sort: a = .ToArray: .Clear
            For i = 2 To UBound(c, 1)
                b = c(i, 2) & "," & c(i, 3)
                If Not .Contains(b) Then .Add b
            Next
                .Sort: b = .ToArray: .Clear
        End With
    c = c(2, 1)
   
    With Application.CommandBars("Cell")
        .Reset
        With .Controls.Add(Type:=msoControlPopup, Before:=1)
            .Tag = "Poziom0"
            .Caption = c
            For i = 0 To UBound(a, 1)
                With .Controls.Add(Type:=msoControlPopup, Before:=i + 1)
                    .Tag = "Poziom1"
                    .Caption = a(i)
                    For j = k To UBound(b, 1)
                        If b(j) Like a(i) & "*" Then
                            With .Controls.Add(Type:=msoControlButton)
                                .Tag = "Poziom2"
                                .Caption = Split(b(j), ",", -1, 0)(1)
                                .OnAction = pn
                            End With
                            k = k + 1
                        Else
                            Exit For
                        End If
                    Next
                End With
            Next
        End With
        .Controls(2).BeginGroup = True
    End With
   
    a = Empty: b = Empty
End Sub
ID posta: 437243 Skopiuj do schowka
 
 
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum
Dodaj temat do Ulubionych
Wersja do druku

Skocz do:  

Powered by phpBB modified by Przemo © 2003 phpBB Group
Theme xandgreen created by spleen& Programosy modified v0.3 by warna
Opieka techniczna www.wip.pl

Archiwum

Strona uĹźywa plikĂłw cookies.

Kliknij tutaj, żeby dowiedzieć się jaki jest cel używania cookies oraz jak zmienić ustawienia cookie w przegl�darce.
Korzystając ze strony użytkownik wyraża zgodę na używanie plików cookies, zgodnie z bieżącymi ustawieniami przeglądarki.
SprawdĹş, w jaki sposĂłb przetwarzamy dane osobowe