ID tematu: 72800
 |
ComboBox wywoływane przez DoubleClick |
Autor |
Wiadomość |
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 10-05-2022, 16:27 ComboBox wywoływane przez DoubleClick
|
|
|
Szanowni Forumowicze,
Zwracam się do Was z gorącą prośbą o pomoc w rozwiązaniu poniższego zadania:
W arkuszu znajduje się tabela, podwójne kliknięcie w komórkę określonego wiersza z pierwszej kolumny powoduje otwarcie Combobox w polu klikniętej komórki. Combo zawiera listę składającą się z dwóch kolumn. Po wybraniu danej pozycji z listy, do komórki, w której otwarte jest Combo, zostaje wprowadzona wartość z pierwszej kolumny listy z wybranej pozycji. Następnie Combo zostaje zamknięte (znika).
W załączeniu zamieszczam plik obrazujący przedstawione zadanie.
Za odpowiedzi z góry bardzo dziękuję.
ComboBox wywoływane przez Doubleclick.xlsm
|
Pobierz Plik ściągnięto 22 raz(y) 17.09 KB |
|
|
 | ID posta:
417058
|
|
|
 |
|
|
|
Tajan

Pomógł: 5234 razy Posty: 11414
|
Wysłany: 10-05-2022, 21:06
|
|
|
Przykładowe rozwiązanie w załączniku. Opiera się na jednej kontrolce ComboBox1, która jest wyświetlana za pomocą podwójnego kliknięcia w aktywnej komórce pierwszej kolumny tabeli. Lista wartości dla combo jest obliczana za pomocą formuły: Kod: | =PRZESUNIĘCIE(Arkusz1!$K$5;0;0;ILE.NIEPUSTYCH(Arkusz1!$K:$K);3) | do której przypisano nazwę "LISTA" i która dynamiczne reaguje na zmianę liczby wierszy.
Kod to trzy procedury zdarzeniowe w module kodu arkusza:
Kod: | Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim cmb As ComboBox
Dim tbl As ListObject
Set cmb = Me.ComboBox1
Set tbl = Me.ListObjects("Tabela1")
With Target
If Not Intersect(.Cells, tbl.ListColumns(1).DataBodyRange) Is Nothing Then
Cancel = True
cmb.Top = .Top - 1
cmb.Left = .Left
cmb.Height = .Height + 2
cmb.Width = .Width + 15
cmb.ListFillRange = "LISTA"
cmb.LinkedCell = .Address(0, 0)
cmb.Visible = True
End If
End With
End Sub
Private Sub ComboBox1_Change()
Dim cmb As ComboBox
Set cmb = Me.ComboBox1
If cmb.LinkedCell = "" Then Exit Sub
With Me.Range(cmb.LinkedCell).Offset(0, 1)
If cmb.ListIndex > -1 Then
.Value = cmb.Column(2)
Else
.Value = ""
End If
End With
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cmb As ComboBox
Set cmb = Me.ComboBox1
cmb.Visible = False
cmb.LinkedCell = ""
End Sub
|
W sumie nie przyłożyłem się zbytnio do zadania i nie jest spełnione założenie:
Cytat: | Następnie Combo zostaje zamknięte (znika). | W przykładzie kontrolka nie znika automatyczne po wybraniu wartości lecz po zmianie aktywnej komórki. Tak jest prościej
ComboBox wywoływane przez Doubleclick(tj).xlsm
|
Pobierz Plik ściągnięto 22 raz(y) 23.92 KB |
|
|
 | ID posta:
417064
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 11-05-2022, 10:10
|
|
|
Tajan, bardzo bardzo dziękuję za przedstawiony kod. Jestem pod wielkim wrażeniem jego pomysłowości.
Chciałbym jeszcze dopytać o funkcjonowanie kodu.
W poniższym fragmencie:
Kod: |
With Me.Range(cmb.LinkedCell).Offset(0, 1)
If cmb.ListIndex > -1 Then
.Value = cmb.Column(2)
Else
.Value = ""
End If
End With
|
Następuje wstawienie wartości do kolumny 2 tabeli, czyli do komórki sąsiedniej po prawej względem LinkedCell,
ale nie mogę dociec, w którym miejscu kodu następuje wstawienie wartości do kolumny 1 tabeli, tj. do LinkedCell.
I jeszcze jedna rzecz: dlaczego liczba wstawiona do kolumny 1 formatowana jest jako tekst? Czy można uniknąć takiego formatowania?
Za odpowiedzi z góry bardzo dziękuję.
P.S.
Cytat: |
W sumie nie przyłożyłem się zbytnio do zadania i nie jest spełnione założenie:
Cytat:
Następnie Combo zostaje zamknięte (znika).
|
Tajan, zdaje się, że zaradziłem Twojemu "nieprzyłożeniu się zbytniemu", wstawiając "cmb.Visible = False" do Sub ComboBox1_Change() i combo znika po wybraniu wartości. |
|
 | ID posta:
417076
|
|
|
 |
|
|
Tajan

Pomógł: 5234 razy Posty: 11414
|
Wysłany: 11-05-2022, 15:35
|
|
|
Leon M napisał/a: | nie mogę dociec, w którym miejscu kodu następuje wstawienie wartości do kolumny 1 tabeli, tj. do LinkedCell | Jeżeli do LinkedCell przypiszemy adres komórki to spowoduje, że wartość tej komórki będzie automatycznie zapisywana oraz pobierana przez ComboBox. Oczywiście, czasem to rodzi pewne problemy, w rodzaju:
Leon M napisał/a: | iczba wstawiona do kolumny 1 formatowana jest jako tekst | spowodowane tym, że wartość ComboBox'a jest zawsze typu tekstowego. W związku z tym pojawia się konieczność korygowania typu wartości poprzez użycie jednej z funkcji konwersji. W twoim przypadku można to zrobić zmieniając:
Kod: | With Me.Range(cmb.LinkedCell).Offset(0, 1)
If cmb.ListIndex > -1 Then
.Value = cmb.Column(2)
Else
.Value = ""
End If
End With | na kod który konwertuje wartość komórki przy użyciu funkcji CVar :
Kod: | With Me.Range(cmb.LinkedCell)
.Value = CVar(.Value)
With .Offset(0, 1)
If cmb.ListIndex > -1 Then
.Value = cmb.Column(2)
Else
.Value = ""
End If
End With
End With |
Leon M napisał/a: | zaradziłem Twojemu "nieprzyłożeniu się zbytniemu", wstawiając "cmb.Visible = False" do Sub ComboBox1_Change() i combo znika po wybraniu wartości. | Przyznam, że była to z mojej strony taka mała prowokacja abyś sam spróbował pokombinować coś przy kodzie Cieszę się, że się udało. |
|
 | ID posta:
417090
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 13-05-2022, 09:36
|
|
|
Tajan, bardzo dziękuję za dalsze wyjaśnienia w temacie niniejszego wątku.
Powiem, że pochwalam takie prowokacje, które nasilają walor dydaktyczny prowadzonego wykładu, a ucznia nakłaniają do wytężenia swych szarych komórek.
Chciałbym zwrócić się o pomoc w jednej jeszcze kwestii:
Otóż dopisałem dwie linie kodu, które powodują, że po zatwierdzeniu wartości z listy następuje dodatkowo umieszczenie w kolumnie 3 tekstu "sekcja nr 1" i zaznaczenie komórki w kolumnie 4, do której wartość wprowadzana jest manualnie.
Chciałbym rozbudować procedurę o następującą funkcjonalność:
Po wprowadzeniu wartości do kolumny 4 i jej zatwierdzeniu, następuje automatyczne otwarcie ComboBox w wierszu poniżej w kolumnie 1.
Podjąłem samodzielnie próbę rozwiązania zadania, ale niestety nieudatnie, czego ślad widoczny jest w module.
Bardzo proszę o pomoc.
W załączeniu zamieszczam plik.
ComboBox wywoływane przez Doubleclick(tj) 3.xlsm
|
Pobierz Plik ściągnięto 13 raz(y) 26.46 KB |
|
|
 | ID posta:
417173
|
|
|
 |
|
|
Tajan

Pomógł: 5234 razy Posty: 11414
|
Wysłany: 13-05-2022, 19:22
|
|
|
Nowa funkcjonalność to nieco bardziej skomplikowana sprawa. Zgodnie z logiką należy tu wykorzystać procedurę zdarzeniowa Worksheet_Change. Jednak tutaj pojawia się problem z przeniesieniem zaznaczenia do pierwszej kolumny gdyż zmiana w czasie wykonywania tej procedury jest ignorowana przez Excela i po zakończeniu procedury aktywowana jest komórka do której Excel standardowo przechodzi po zakończeniu edycji. Z tego względu proponuję następujące rozwiązanie:
Kod: | Private Sub Worksheet_Change(ByVal Target As Range)
Dim tbl As ListObject
If Target.Count > 1 Then Exit Sub
Set tbl = Me.ListObjects("Tabela1")
With Target
If Not Intersect(.Cells, tbl.ListColumns(4).DataBodyRange) Is Nothing Then
Application.OnTime Now, "'NextRecord """ & .Address & """'"
End If
End With
End Sub | Zmiana zaznaczenia jest realizowana za pomocą procedury NextRecord, która jest uruchamiana poprzez metodę OnTime. Ten sposób uruchamiana gwarantuje, że procedura NextRecord zostanie uruchomiona po zakończeniu procedury Worksheet_Change i ustawieniu aktywnej komórki.
Ze względu na wymogi metody OnTime procedura NextRecord została umieszczona w Module1 i jest skonstruowana nastepująco:
Kod: | Sub NextRecord(trg As String)
Dim thisRec As Range
Dim nextRec As Range
Application.EnableEvents = False
With Arkusz1
Set thisRec = .Range(trg)
With .ListObjects("Tabela1").ListRows
If Not Intersect(thisRec, .Item(.Count).Range) Is Nothing Then .Add
End With
Set nextRec = thisRec.Offset(1, -3)
nextRec.Select
.Worksheet_BeforeDoubleClick nextRec, True
End With
Application.EnableEvents = True
End Sub
| Jej zadaniem, oprócz przeniesienia zaznaczenia i otwarcia combo, jest dodanie wiersza do tabeli w przypadku edycji ostatniego wiersza. Otwarcie kontrolki następuje poprzez wywołanie procedury Worksheet_BeforeDoubleClick z modułu Arkusz1. Z tego względu zakres widoczności tej procedury zmieniłem z Private na Public aby była widoczna w Module1.
Dodatkowo, w module Arkusz1, dodałem zmienną noChange aby wyeliminować zbędne wywołanie procedury ComboBox1_Change w czasie konfigurowania combo w procedurze Worksheet_BeforeDoubleClick.
ComboBox wywoływane przez Doubleclick(tj2).xlsm
|
Pobierz Plik ściągnięto 18 raz(y) 28.08 KB |
|
|
 | ID posta:
417193
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 14-05-2022, 13:17
|
|
|
Tajan, bardzo bardzo dziękuję za przedstawiony kod rozbudowujący aplikację o nową funkcjonalność oraz za szczegółowy opis jego działania.
Sposób rozwiązania postawionej powyżej kwestii jest jak dla mnie rewelacyjnie przemyślny. Nie będę ukrywał, że rzecz przyprawiła mnie o podziw dla Twej inwencji twórczej i programistycznych umiejętności.
Chciałbym dopytać nieco o funkcjonowanie kodu.
Kod: |
Application.OnTime Now, "'NextRecord """ & .Address & """'"
|
Następuje tutaj wywołanie procedury NextRecord z argumentem Target.Address, jest natomiast dla mnie niewiadomą układ zastosowanych znaków cudzysłowu i apostrofu.
Druga kwestia to, czy zastosowane w procedurach "Me." jest substytutem instancji skoroszytu.
I jeszcze, czy można zlikwidować poziomy ScrollBar listy Combo przy szerokości kolumny1 tabeli 150 pikseli?
Ponadto zauważyłem, że procedura zamieszczona w Module1 NextRecord nie jest widoczna w Menadżerze Makr. Dlaczego?
Jest jeszcze jedna rzecz w niniejszym temacie, w kwestii której chciałbym zagadnąć.
Otóż mam kilka plików, w których zbudowana przez Tajana aplikacja mogłaby znaleźć wielce użyteczne zastosowanie.
Ale na drodze do zastosowania w nich aplikacji w aktualnej postaci stoi to, że wykorzystywane są tam tabele nakreślone metodą manualną (nie są to standardowe tabele excelowskie). Dlatego też ciekawi mnie, w jaki sposób należałoby zmodyfikować odpowiednie części kodu, aby funkcjonował nie w standardowej tabeli, ale w zwykłych komórkach. Dodatkowo jeszcze, gdyby dane do Listy ComboBox były obsługiwane nie przez formułę nazwaną, lecz zostały zapisane w tablicy vba.
Za odpowiedzi z góry bardzo dziękuję.
P.S.
Zamieszczony w załączeniu plik zawiera procedurę, która wypełnia tablicę wartościami dla ComboBox.List
ComboBox wywoływane przez Doubleclick(tj2) (b).xlsm
|
Pobierz Plik ściągnięto 15 raz(y) 29.73 KB |
|
|
 | ID posta:
417204
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 14-05-2022, 15:00
|
|
|
Szanowni Forumowicze,
Proszę o pomoc w następującej kwestii:
Przeniosłem procedury ułożone przez Tajana do innego pliku i pojawił się problem.
Otóż w nowym skoroszycie kompilator zgłasza błąd " User-defined type not defined",
wskazując na linię"
Jak się okazuje nie jest dostępna możliwość zadeklarowania zmiennej jako typ ComboBox.
W jaki sposób zaradzić temu problemowi?
Za odpowiedzi z góry bardzo dziękuję. |
|
 | ID posta:
417207
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 14-05-2022, 15:31
|
|
|
Szanowni Forumowicze,
Sprawa załatwiona!
Miałem chwilowe, mam nadzieje, zaćmienie umysłu. Nie utworzyłem w arkuszu ComboBox.
Przepraszam za zamieszanie i niepotrzebny alarm. |
|
 | ID posta:
417208
|
|
|
 |
|
|
Tajan

Pomógł: 5234 razy Posty: 11414
|
Wysłany: 14-05-2022, 23:03
|
|
|
Leon M, zadajesz sporo pytań. Mam nadzieję, ze odpowiem na wszystkie. A zatem:
Leon M napisał/a: | Następuje tutaj wywołanie procedury NextRecord z argumentem Target.Address, jest natomiast dla mnie niewiadomą układ zastosowanych znaków cudzysłowu i apostrofu. |
Standardowo metoda OnTime wymaga podania nazwy procedury w cudzysłowach, jednak, jeżeli chcemy użyć argumentów to nazwę oraz argumenty należy dodatkowo ująć w apostrofy.
Leon M napisał/a: | Druga kwestia to, czy zastosowane w procedurach "Me." jest substytutem instancji skoroszytu. |
To zależy od miejsca zastosowania. W module kodu arkusza odnosi się do danego arkusza, w module Ten_Skoroszyt (ThisWorkbook) do skoroszytu, w module formularza do formularza. Inaczej mówiąc jest substytutem obiektu w którego module kodu to odwołanie zostało użyte.
Leon M napisał/a: | I jeszcze, czy można zlikwidować poziomy ScrollBar listy Combo przy szerokości kolumny1 tabeli 150 pikseli? |
Można, należy tylko samemu określić szerokość kolumn, które będą wyświetlane na liście comba ustawiając odpowiednio wartości właściwości ColumnWidths tej kontrolki. Należy jednak mieć na uwadze, że podanie zbyt małych szerokości noże spowodować ucinanie tekstów w wyświetlanych kolumnach. Przykładowo, w twoim pliku zadeklarujemy, że lista zawiera trzy kolumny i wartość dwóch pierwszych ustawimy na połowę szerokości listy a trzecią ukryjemy nadając jej zerową szerokość: Kod: | With Target
'...
cmb.Width = .Width + 15
cmb.ColumnCount = 3
cmb.ColumnWidths = Int(.Width * 0.5) & ";" & Int(.Width * 0.5) & ";0"
'...
End With |
Zauważ jednak, że do obliczeń nie używam szerokości kontrolki, lecz szerokość komórki aby pozostawić miejsce (te +15) na ewentualny scollbar pionowy. Oczywiście, należy liczyć się z tym, że przy zbyt małych szerokościach kolumn część danych może zostać nie pokazana w całości.
Leon M napisał/a: | procedura zamieszczona w Module1 NextRecord nie jest widoczna w Menadżerze Makr. Dlaczego? | Procedury wymagające argumentów nie są widoczne w Menadżerze gdyż nie ma możliwości ich uruchomienia "z palca" z powodu braku możliwości podania wartości argumentu.
Leon M napisał/a: | Dlatego też ciekawi mnie, w jaki sposób należałoby zmodyfikować odpowiednie części kodu, aby funkcjonował nie w standardowej tabeli, ale w zwykłych komórkach. |
Po prostu należy zmienić kod, który odwołuje się do tablicy. Są to proste operacje, które łatwo przełożyć na zwykłe obszary. W sumie są dwa takie miejsca:
-sprawdzenie czy kliknięta komórka znajduje się w pierwszej kolumnie tabeli:
Kod: | If Not Intersect(.Cells, tbl.ListColumns(1).DataBodyRange) Is Nothing Then | gdzie odwołanie do pierwszej kolumny tabeli należałoby zastąpić odwołaniem do pierwszej kolumny obszaru danych.
-sprawdzenie czy edytowana komórka znajduje się w czwartej kolumnie tabeli:
Kod: | If Not Intersect(.Cells, tbl.ListColumns(4).DataBodyRange) Is Nothing Then | wymagająca identycznych zmian jak w poprzednim przypadku
Konieczne jest też usunięcie kodu dodającego nowy wiersz do tabeli w pocedurze NextRecord:
Kod: | With .ListObjects("Tabela1").ListRows
If Not Intersect(thisRec, .Item(.Count).Range) Is Nothing Then .Add
End With
| i to chyba wszystko.
Leon M napisał/a: | gdyby dane do Listy ComboBox były obsługiwane nie przez formułę nazwaną, lecz zostały zapisane w tablicy vba.
...
w załączeniu plik zawiera procedurę, która wypełnia tablicę wartościami dla ComboBox.List | Do tworzenia tablicy prościej byłoby użyć funkcji zwracającej tablicę, za pomocą której można byłoby przypisać ją bezpośrednio do właściwości List kontrolki. Przykładowo, bazując na twojej procedurze, można użyć takiej funkcji:
Kod: | Function Tablica() As Variant
Dim doListy()
Dim j As Byte
Dim ost As Integer
With Arkusz1
ost = .Cells(.Rows.Count, "K").End(xlUp).Row
ReDim doListy(5 To ost, 1 To 3)
For j = 5 To ost
doListy(j, 1) = CStr(.Cells(j, 11))
doListy(j, 2) = .Cells(j, 12)
doListy(j, 3) = .Cells(j, 13)
Next j
End With
Tablica = doListy
End Function | i zastosować ją przy konfiguracji kontrolki w taki sposób:
Kod: | cmb.List = Tablica() |
ComboBox wywoływane przez Doubleclick(tj3).xlsm
|
Pobierz Plik ściągnięto 21 raz(y) 30.39 KB |
|
|
 | ID posta:
417210
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 15-05-2022, 14:36
|
|
|
Tajan, bardzo dziękuję za tak szczegółowe wyjaśnienia i wskazówki. Przekazałeś tym sposobem pokaźną porcję wielce przydatnej wiedzy. Jeszcze raz wielkie dzięki.
Wedle Twych wskazówek przebudowa aplikacji na działanie w zwykłych obszarach arkusza faktycznie nie jawi się nader skomplikowanie, i podobnie jeśli chodzi o zastosowanie tablicy do przekazania pozycji do listy Combo, więc sądzę, że rzecz zdołam zmodyfikować samodzielnie.
Na marginesie mówiąc, rozwiązanie z funkcją zwracającą tablicę z pozycjami do listy jest bardzo pomysłowe i istotnie upraszcza kwestię.
Chciałbym jeszcze zapytać, czy przebudowa aplikacji z ComboBox na ListBox będzie polegała tylko na zmianie tych fragmentów kodu, które odnoszą się do Combo, na analogiczne odnoszące się do List Box, czy rzecz będzie wymagała jeszcze jakichś dodatkowych zabiegów.
Za odpowiedź z góry bardzo dziękuję. |
|
 | ID posta:
417220
|
|
|
 |
|
|
Tajan

Pomógł: 5234 razy Posty: 11414
|
Wysłany: 15-05-2022, 17:14
|
|
|
Myślę, że nie będą potrzebne jakieś duże zmiany. Oczywiście, na początek typ zmiennej jako MsForms.ListBox i "ręczne" określenie wysokości kontrolki. |
|
 | ID posta:
417223
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 18-05-2022, 10:55
|
|
|
Tajan, dziękuję za ostatnie podpowiedzi, a ogólnie jeszcze raz wielkie dzięki za aplikację i cały materiał dydaktyczny przedstawiony w niniejszym wątku. |
|
 | ID posta:
417332
|
|
|
 |
|
|
Leon M
Stały bywalec Excelforum

Wersja: Win Office 2016
Posty: 471
|
Wysłany: 18-05-2022, 19:20
|
|
|
Nie wiem, czy powinienem założyć nowy wątek dla pytania, które chcę zadać, ale na razie spróbuję postawić je tutaj.
Otóż przystąpiłem do próby przebudowy aplikacji Tajana na wersję z ListBox i już na samym początku pojawił się problem.
w procedurze Sub Worksheet_BeforeDoubleClick zadeklarowałem zmienną typu ListBox i przypisałem do niej LstBox1:
Kod: |
Dim lstb As ListBox
Set lstb = Me.ListBox1
|
po wywołaniu pojawia się komunikat o błędzie:
Run-time error 13
Type mismatch
W czym tkwi przyczyna błędu? Bardzo proszę o pomoc.
Za odpowiedzi z góry bardzo dziękuję. |
|
 | ID posta:
417338
|
|
|
 |
|
|
Tajan

Pomógł: 5234 razy Posty: 11414
|
Wysłany: 18-05-2022, 19:36
|
|
|
Jak pisałem wyżej, zadeklaruj:
Kod: | Dim lstb As MsForms.ListBox |
Ponadto, dla ListBoxa, proponuję użyć zdarzenia DoubleClick zamiast Change. |
|
 | ID posta:
417340
|
|
|
 |
|
|
|
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
|
|
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
|