Wykorzystanie Immediate Window z UserForm'a i ComboCooki   strona główna:
A po co ten Excel ;-)
 
 
  Wersja (2) poprawione kilka aspektów pomysłu.  
 
 
    Najpierw dwa słowa na temat całego pomysłu. Dość często wykorzystuję do różnych celów okno Immediate Edytora VBA. Można je  
włączyć uruchamiając Edytor VBA (L_Alt + F11) i Menu View / Immediate Window (Ctrl+G). Wykorzystuje się je najczęściej w instrukcji  
Debug.Print które następujące po tej komendzie instrukcji zwraca do tego okna. Można jednak robić za jego pomocą wiele różnych  
rzeczy: dokonywać zmian w arkuszach, skoroszytach, i ich obiektach, formułach, komentarzach.. (no sam nie wiem co jeszcze pisać)  
słowem wszystko co można zapisać "jedną linią" i wykonać jak procedurę.  
    Mi się wymarzyło żebym mógł wykorzystywać te możliwości okna Immediate bez wywołania okna Edytora VBA. Najlepiej z UserForm'a.  
I tak żeby to mogło działać w każdym otwartym skoroszycie. Jak bym sobie tego nie wyobrażał to byłem pewien że z podpowiedzi VBA  
trzeba będzie zrezygnować a o literówkę nie trudno. Może więc trzeba dodać możliwość wyboru najczęściej używanych komend z listy.  
Po to właśnie wymyśliłem ComboCooki ;-P Jest to zwykły ComboBox jednak zawartość jego listy jest pobierana z pliku txt w którym z  
poziomu samego combo będziemy mogli dokonywać zapisów tych komend które chcemy zapamiętać.  
 
    Jak się do czegoś takiego zabrać?  
Żeby pomysł działał w każdym skoroszycie postanowiłem wszystko tworzyć w skoroszycie makr osobistych (Personal.xls) i wywoływać  
ze skrótu klawiaturowego Ctrl+Shift+I.   
 
W mod.Thisworkbook (Ten_skoroszyt E2010) wstawiamy kod:  
 
Option Explicit  
 
Private Sub Workbook_Open()  
    Application.OnKey "^+i", "StartImmediate"  
End Sub  
 
W mod.Standardowym  
 
Sub StartImmediate()  
    UserForm1.Show 0  
End Sub  
 
W kodzie UserForm'a  
 
Option Explicit  
 
Private Declare Function FindWindow _  
    Lib "user32" _  
    Alias "FindWindowA" ( _  
        ByVal lpClassName As String, _  
        ByVal lpWindowName As String) As Long  
 
Private Declare Function FindWindowExA _  
    Lib "user32" ( _  
        ByVal hWnd1 As Long, _  
        ByVal hWnd2 As Long, _  
        ByVal lpsz1 As String, _  
        ByVal lpsz2 As String) As Long  
          
Private Declare Function GetWindowText _  
    Lib "user32" _  
    Alias "GetWindowTextA" ( _  
        ByVal hwnd As Long, _  
        ByVal lpString As String, _  
        ByVal cch As Long) As Long  
          
Private Declare Function GetForegroundWindow _  
    Lib "user32" () As Long  
 
Private Declare Function ShellExecute _  
    Lib "shell32.dll" _  
    Alias "ShellExecuteA" ( _  
        ByVal hwnd As Long, _  
        ByVal lpOperation As String, _  
        ByVal lpFile As String, _  
        ByVal lpParameters As String, _  
        ByVal lpDirectory As String, _  
        ByVal nShowCmd As Long) As Long  
 
Private Function GetImmediateWindowHwnd() As Long  
    Dim hwnd As Long, hMain As Long  
    Dim sMain As String: sMain = Application.VBE.MainWindow.Caption  
      
    Const strClassName As String = "VbaWindow"  
    Const strWindowText As String = "Immediate"  
      
    Dim sWindowText As String, r As Long  
      
    Do  
        hMain = FindWindow("wndclass_desked_gsk", sMain)  
        hwnd = FindWindowExA(hMain, hwnd, strClassName, vbNullString)  
        If hwnd = 0 Then  
            Exit Do  
        Else  
            sWindowText = Space(255)  
            r = GetWindowText(hwnd, sWindowText, 255)  
            sWindowText = Left(sWindowText, r)  
            If strWindowText = sWindowText Then  
                GetImmediateWindowHwnd = hwnd  
                Exit Do  
            End If  
        End If  
    Loop  
 
End Function  
 
Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, _  
                              ByVal Shift As Integer)  
    Select Case KeyCode  
        Case vbKeyEscape  
 
            Unload Me  
 
            Application.VBE.MainWindow.SetFocus  
            Application.SendKeys "%{F4}", True  
            Application.OnTime Now() + TimeSerial(0, 0, 0), "XLAppActivate"  
 
              
        Case vbKeyReturn  
          
            If bSave Then  
                Dim nr As Integer: nr = VBA.FreeFile  
                Open ThisWorkbook.Path & "\txt\ComboCooki.txt" For Append As #nr  
                    Print #nr, Me.ComboBox1.Text  
                Close #nr  
            End If  
              
            SendToImmediate Me.ComboBox1.Text  
          
        Case vbKeyF1  
          
            ShellExecute 0, _  
                         "OPEN", _  
                         ThisWorkbook.Path & "\txt\ComboCooki.txt", _  
                         vbNullString, _  
                         vbNullString, _  
                         vbNormalFocus  
    End Select  
          
End Sub  
 
Sub SendToImmediate(strText As String)  
    Dim hwnd As Long  
    hwnd = GetImmediateWindowHwnd  
      
    Dim objClipboard As New MSForms.DataObject  
    If hwnd > 0 Then  
 
        With objClipboard  
            .SetText strText  
            .PutInClipboard  
        End With  
 
        SetFocus hwnd  
 
        With Application  
            .SendKeys "^v", True  
            .SendKeys "~", True  
        End With  
 
        Application.OnTime Now() + TimeSerial(0, 0, 0), "ClearClipboard"  
    End If  
End Sub  
 
Private Sub UserForm_Activate()  
    lUFhWnd = GetForegroundWindow  
End Sub  
 
Private Sub UserForm_Initialize()  
    Dim strTxtPAth As String: strTxtPAth = ThisWorkbook.Path & "\txt\ComboCooki.txt"  
      
    Dim objFSO As Object 'Scripting.FileSystemObject  
    Dim objFile As Object 'Scripting.TextStream  
      
    Const ForReading = 1  
      
    Set objFSO = CreateObject("Scripting.FileSystemObject")  
      
    With objFSO  
        If Not .FolderExists(ThisWorkbook.Path & "\txt") Then _  
               .CreateFolder ThisWorkbook.Path & "\txt"  
          
        If .FileExists(strTxtPAth) Then  
            Set objFile = .OpenTextFile(Filename:=strTxtPAth, _  
                                        IOMode:=ForReading, _  
                                        Create:=False)  
            Me.ComboBox1.List = Split(objFile.ReadAll, vbCrLf)  
            objFile.Close  
        End If  
    End With  
      
    Set objFile = Nothing  
    Set objFSO = Nothing  
End Sub  
   
 
   Fragmentami:  
 - UserForm_Initialize  
 
    Set objFSO = CreateObject("Scripting.FileSystemObject")  
      
    With objFSO  
        If Not .FolderExists(ThisWorkbook.Path & "\txt") Then _  
               .CreateFolder ThisWorkbook.Path & "\txt"  
 
Posługując się obiektami biblioteki Scripting.Runtime tworzę folder ..\txt na ścieżce Thisworkbook.Path jezel itaki folder nie istnieje.  
Będzie to folder dla pliku   
 
    Dim strTxtPAth As String: strTxtPAth = ThisWorkbook.Path & "\txt\ComboCooki.txt"  
 
w którym będę przychowywał zapisane do tej pory elementy listy mojego Combo.  
 
        If .FileExists(strTxtPAth) Then  
            Set objFile = .OpenTextFile(Filename:=strTxtPAth, _  
                                        IOMode:=ForReading, _  
                                        Create:=False)  
            Me.ComboBox1.List = Split(objFile.ReadAll, vbCrLf)  
            objFile.Close  
        End If  
 
Jeżeli ten plik istnieje to go otwieram, czytam - dzieląc po znaku nowej linii, zapisuję do listy Combo i plik txt zamykam.  
 
 - UserForm_Activate  
 
Private Sub UserForm_Activate()  
    lUFhWnd = GetForegroundWindow  
End Sub  
 
lUFhWnd to zmienna publiczna w której przechowuję uchwyt okna naszego UserForm'a.  
 
 - ComboBox1_KeyDown  
 
Czemu ComboBox? Bo zależało mi na podpowiedziach (MatchEntry). Jak obsłużyć działanie takiego pomysłu? Wg mnie nieźle działa   
oprogramowując zdarzenie KeyDown naszego Combo. A wiec: Select Case KeyCode  
 
        Case vbKeyEscape  
 
            Unload Me  
 
            Application.VBE.MainWindow.SetFocus  
            Application.SendKeys "%{F4}", True  
            Application.OnTime Now() + TimeSerial(0, 0, 0), "XLAppActivate"  
 
Pod Esc. Chcę wyłączyć Userform i chciałby żeby aktywnym oknem był arkusz na którym pracowałem. Jednak w różnych sytuacjach  
różnie to działało. Jeżeli odpalimy UserForm i natychmiast zrezygnujemy z pracy na nim -> Esc to wystarczyłoby Unload Me. Jeżeli  
jednak wpiszemy choć jedną komendą to po zamknięciu formy aktywnym oknem będzie Edytor VBA. Stąd następne 3 linijki.  
    Procedura XLAppActivate to maleństwo z mod. Standardowego.  
 
Sub XLAppActivate()  
    SetForegroundWindow Application.hwnd  
End Sub  
 
        Case vbKeyF1  
          
            ShellExecute 0, _  
                         "OPEN", _  
                         ThisWorkbook.Path & "\txt\ComboCooki.txt", _  
                         vbNullString, _  
                         vbNullString, _  
                         vbNormalFocus  
 
   Pod F1 chciałbym móc włączyć mój plik ComboCooki.txt żeby, w razie potrzeby, dokonać w nim ręcznych zmian.  
 
        Case vbKeyReturn  
          
            If bSave Then  
                Dim nr As Integer: nr = VBA.FreeFile  
                Open ThisWorkbook.Path & "\txt\ComboCooki.txt" For Append As #nr  
                    Print #nr, Me.ComboBox1.Text  
                Close #nr  
            End If  
              
            SendToImmediate Me.ComboBox1.Text  
 
   No i pod Enterem.  
bSaveto zmienna publiczna która ustawiona na True zezwoli na zapis Me.ComboBox1.Text do pliku ComboCooki.txt. Jak określić wartość  
tej zmiennej na True/False? Oczywiście poprzez nasze Immediate :-)  
 - wywołujemy okno UserForma (ctrl+shift+I)   
 - wpisujemy: bSave = True i klikamy enter  
Następne komendy potwierdzone enterem zostaną zapisane do ComboCooki.txt.   
 - bSave = False  
 - reset UserForm'a  
I mamy możliwość wyboru na naszym Combo zarówno poprzez strzałki jak i podpowiedź (zaczynając pisać).  
 
 - SendToImmediate Me.ComboBox1.Text  
 
Sub SendToImmediate(strText As String)  
    Dim hwnd As Long  
    hwnd = GetImmediateWindowHwnd  
      
    Dim objClipboard As New MSForms.DataObject  
    If hwnd > 0 Then  
 
        With objClipboard  
            .SetText strText  
            .PutInClipboard  
        End With  
 
        SetFocus hwnd  
 
        With Application  
            .SendKeys "^v", True  
            .SendKeys "~", True  
        End With  
 
        Application.OnTime Now() + TimeSerial(0, 0, 0), "ClearClipboard"  
    End If  
End Sub  
 
Fragmentami:  
 
    Dim hwnd As Long  
    hwnd = GetImmediateWindowHwnd  
 
Zapisuję uchwyt okna Immediate do zmiennej hwnd funkcją GetImmediateWindowHwnd. Funkcja ta:   funkcja
  GetImmediateWindowHwnd
Private Function GetImmediateWindowHwnd() As Long   napisana na podstawie
    Dim hwnd As Long, hMain As Long  
    Dim sMain As String: sMain = Application.VBE.MainWindow.Caption   Function GetXlApps
      
    Const strClassName As String = "VbaWindow"  
    Const strWindowText As String = "Immediate"  
      
    Dim sWindowText As String, r As Long  
      
    Do  
        hMain = FindWindow("wndclass_desked_gsk", sMain)  
        hwnd = FindWindowExA(hMain, hwnd, strClassName, vbNullString)  
        If hwnd = 0 Then  
            Exit Do  
        Else  
            sWindowText = Space(255)  
            r = GetWindowText(hwnd, sWindowText, 255)  
            sWindowText = Left(sWindowText, r)  
            If strWindowText = sWindowText Then  
                GetImmediateWindowHwnd = hwnd  
                Exit Do  
            End If  
        End If  
    Loop  
 
End Function  
 
Jeżeli mam już uchwyt..  
 
    Dim objClipboard As New MSForms.DataObject  
    With objClipboard  
       .SetText strText  
       .PutInClipboard  
    End With  
 
Kopiuję do schowka tekst komenty.  
 
        SetFocus hwnd  
 
        With Application  
            .SendKeys "^v", True  
            .SendKeys "~", True  
        End With  
 
Przełączam Focus na okno immediate i wysyłam do niego Ctrl+v (wklej) i Enter  
 
        Application.OnTime Now() + TimeSerial(0, 0, 0), "ClearClipboard"  
 
Nastepnie "bezzwłocznie" po wykonaniu tej procedury...  
 
Sub ClearClipboard()  
    OpenClipboard (0&)  
    EmptyClipboard  
    CloseClipboard  
      
    SetFocus lUFhWnd  
 
    With UserForm1  
        .Hide  
        .Show  
    End With  
End Sub  
 
 - czyszczę schowek  
 - przełączam focus na UserForma  
 - i go resetuję.  
 
No i chyba tyle nt. Teorii. Teraz przykłady wykorzystania :-)  
 
Selection.Clear  
 
Mamy jakiś zakres z wartościami i formatowaniem (kolor, obramowanie) Jak to wyczyścić?  
 - zaznaczyć zakres  
 - Przycisk DEL - czyści zawartość komórek  
 - (E2003) Pasek Formatowanie / kolor wypełenienia /  kliknąć na DropdownButton / Brak Wypełeninia  
 - (E2003) jw.. / Obramowanie / "bez krawędzi"  
MASA Roboty. Zawsze mnie to denerwowało :-). A poprzez Immediate: jedno polecenie.  
 
inne :-)  
ActiveWorkbook.Worksheets.Add  
ActiveSheet.Delete  
Application.Workbooks.Add  
ActiveWorkbook.Close False  
 
ale i..  
[A1].AddComment "test"  
ActiveSheet.TextBoxes.Add 100,100,200,50  
ActiveSheet.TextBoxes.Delete  
 
i czego dusza zapragnie :-DDD  
 
Można też zapisywać wartości do Arkusza1 pliku Personal.xls i je tam przechwowywać.  
 
Arkusz1.[A1] = "test"  
Arkusz1.Parent.Save  
 
i nawet po resecie pliku, Excela ...  
 
MsgBox Arkusz1.[A1]  
 
zwróci okienko MsgBOx'a z wartością test  
Skąd wiem że Arkusz1 to Arkusz w Personal.xls?  
 
[A2] = Arkusz1.Parent.FullName  
 
zwróci do kom.A2 aktywnego Arkusza C:\Program Files\Microsoft Office\OFFICE11\xlstart\PERSONAL.XLS lub analogiczną   
na innym systemie, na innym Office'się. A poprzez Arkusz1 należy rozumieć nazwę kodową arkusza Arkusz1 w pliku personal.xls.  
Trzeba być tego świadomym pisząc komendy!  
 
W załączniku:  
 - wyeksportowany UserForm i jego kod do plików  
 - wyeksportowany mod.Standardowy z Funkcjami, Procedurami, zmiennymi Publicznymi.  
 - Thisworkbook.txt - kod do modułu Thisworkbook Personala.  
 
Zaimportujcie sobie do Projektu VBA Personal.xls (z poziomu Edytora VBA)  
   
   
Poprawka głównie dotyczy mozliwości zapisywania do pliku ComboCooki.txt Pomysł ze zmienną bSave nie sprawdzał się jeśli całość   do pobrania (wersja 2)
miała trafić do Personala. Szybkie objeście tego problemu polegało na procedurze zmieniającej tę zmienną jednak musiała to być procedura    
publiczna a ja chciałem żeby takich nie było żeby po Alt+F8 nie były widoczne w oknie makr do wywołania.   imm.zip
Pod przyciskiem Add obok ComboBox'a jest procedura która zapisze zawartość Combo do ComboCooki.txt pod warunkiem że ciąg nie     
znajduje się już w tym pliku. Realizuje to procedura…  
 
Private Sub CommandButton1_Click()  
    With Me.ComboBox1  
 
        If Len(.Text) = 0 Then Exit Sub  
        If TypeName(Application.Match(.Text, .List, 0)) <> "Error" Then MsgBox "Było": Exit Sub  
          
        Dim nr As Integer: nr = VBA.FreeFile  
        Open ThisWorkbook.Path & "\txt\ComboKuki.txt" For Append As #nr  
            Print #nr, .Text  
        Close #nr  
 
    End With  
End Sub  
 
Jest kilka innych zmian ale niewielkich. Nie zdołałem jeszcze pozbyć się mrugania okna spowodowanego aktywowaniem okna VBE :-|  
Application.VBE.MainWindow.Visible nie pomogło, ale cóż - taka uroda metody :-P