Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[vba][excel] Sprawdzenie czy plik jest otworzony

19 Maj 2010 22:11 7779 6
  • Poziom 11  
    Witam, Prośba dotyczy Excela i VBA, proszę o pomoc w rozwiązaniu następującego problemu, który jak sądzę jest banalny i dla tego nie udało mi się znaleźć odpowiedzi w googlach. Nie jetem zbyt biegły w VBA, ale korzystając z tego, co można wyczytać w sieci udało mi się zrobić kilka całkiem użytecznych i rozbudowanych makr. Teraz próbuję zrobić bazę zleceń w Excelu Wprowadzając zlecenie, korzystam w tym celu z UserForm i różnych TextBoxów, m.in. generuje formularz zlecenia w wordzie i chciałbym część danych wpisać do trzech oddzielnych skoroszytów, Excela, w których muszę robić codzienne raporty. Raporty te składają się w większości z tych samych informacji, ale wpisywane są w różnym układzie. Ale to jest mniej istotne, potrafię z poziomu VBA wpisywać dane do innych skoroszytów. Problem mam, gdy próbuję otworzyć skoroszyt, który jest już otworzony. Procedura moja przewiduje otworzenie skoroszytu, do którego chcę wprowadzić dane i po zapisaniu, zamknięcie go. Stworzyłem coś takiego (oczywiście to istotny dla mojego problemu fragmencik):

    Sub sprawdz()

    Dim plik As Workbook
    Set plik = Workbooks.Open(Filename:=ThisWorkbook.Path & "\RAPORT DZIENNY.xls")

    plik.Sheets("Arkusz1").Range("d100") = ThisWorkbook.ActiveSheet.Range("b20")

    Set plik = Nothing
    End Sub

    Jeżeli skoroszyt jest zamknięty to działa, ale gdy ponownie uruchamiam procedurę, a zapomnę wcześniej zamknąć skoroszyt „RAPORT DZIENNY” to dostaję komunikat, że plik jest już otwarty i ponowne otworzenie spowoduje utratę niezapisanych zmian, co jest logiczne i nie budzi mojego zaskoczenia. Myślę, że przed Workbook.Open należałoby wstawić linijkę kodu albo więcej nie wiem, która by sprawdziła czy plik jest otworzony i jeżeli tak to nie wykonywało by się polecenie open. I tego właśnie nigdzie nie mogą znaleźć. Jest mnóstwo przykładów jak otwierać pliki, jak przenosić dane między nimi, ale jak sprawdzić czy plik jest otworzony i tą informację później wykorzystać, nie ma. Proszę o pomoc jak to powinno być zrobione najprościej i poprawnie. Generalnie mój sposób na otwieranie i kopiowanie danych zapewne nie jest optymalny, ale jak wcześniej napisałem, moja znajomość VBA nie jest powalająca. Mam skłonność do wybierania krótkich kodów, które co nie co jestem w stanie ogarnąć i zrozumieć. Ale jak trzeba przeanalizować 500 linii kodu, no cóż jak nie ma wyjścia to trzeba.
    Muszę niestety zakładać, że plik może być otworzony gdy będzie wykonywane makro, bo będzie on na dysku sieciowym i jest często przeglądany.
    Będę wdzięczny za pomoc, to na pewno jak znam życie i moją przygodę z visual basic-iem, jakaś pierdoła.

    Poprawiłem temat.
    Dr.Vee
  • Pomocny post
    Poziom 40  
    siwek62 napisał:
    ...Mam skłonność do wybierania krótkich kodów,

    Żebyś tak jeszcze miał skłonność do pisania krótszych postów ;P

    Niedawno miałem podobny problem, który rozwiązałem w ten sposób, że przed otwarciem pliku sprawdzam wszystkie otwarte arkusze. Coś w stylu:
    Code:

    otwarty = false
    for each ws in Workbooks
       if ws.Name = "RAPORT DZIENNY.xls" then
          otwarty = true
          Exit For
       end if
    next ws

    if not otwarty then
       Set plik = Workbooks.Open(Filename:=ThisWorkbook.Path & "\RAPORT DZIENNY.xls")
    else
       Set plik = Workbooks("RAPORT DZIENNY.xls")
    end if

    ...

    Uwaga: sprawdzane są nazwy, nie ścieżki, więc zakładamy że jeżeli jest otwarty plik takiej nazwie to jest to plik, którego szukamy (tzn. C:\ala.xls potraktuje tak samo jak C:\archiwum\ala.xls)
  • Poziom 11  
    [/quote]Żebyś tak jeszcze miał skłonność do pisania krótszych postów ;P
    To dlatego, że naczytałem się postów, gdzie większość odpowiedzi zaczyna się od "podałeś za mało informacji" albo "jeśli cię dobrz zrozumiałem...". Ale masz rację, mam kłopot ze zwięzłością wypowiedzi.

    Wracając do tematu, nie możnaby dopisać ścieżki dostępu do pliku?

    Dodano po 26 [minuty]:

    Trzeba chyba coś innego wymyślić, bo w pracy korzystam z Excela i wszystkiego innego za pomocą łącza internetowego, i już teraz tempo przesyłania danych jest „zabójcze” (nie wiem jak to się nazywa, ale u siebie mam tylko takie małe pudełko za pomocą, którego tylko mogę się połączyć z centralą). Jak pomyślę, że jeszcze miałbym przeglądać zdalnie wszystkie foldery, to już sobie wyobrażam ja „szybko” to makro będzie działać. Do niektórych folderów nie mam także dostępu.
  • Poziom 40  
    Mimo wszystko rozważ to o czym Ci pisałem, zrób testy i sprawdź czy Ci to pasuje. To makro nie przegląda wszystkich plików w katalogu, a jedynie otwarte przez Ciebie w Excelu.
    Jeżeli masz otwarty plik ala.xls to i tak nie otworzysz innego pliku o tej samej nazwie, choćby z innej ścieżki.
    Musisz więc:
    - albo otworzyć (utworzyć) plik o innej nazwie, np. ala2.xls -> wtedy problem o którym piszesz nie istnieje,
    - albo zastosować podane przeze mnie makro -> wtedy zakładamy że plik "RAPORT DZIENNY.xls" może być przez Ciebie otwarty tylko raz,
    - albo zmodyfikować lekko to makro tak, żeby zamiast ustawiać zmienną na otwarty plik zamykało plik o nazwie "RAPORT DZIENNY.xls", a potem otwierało/tworzyło nowy o tej nazwie tak, jak w Twoim kodzie.
  • Poziom 11  
    OK, testowałem oczywiście, co prawda na razie w domu, i jest w porządku, bardzo ci dziękuje za to rozwiązanie.
    Trochę się zamotałem opisując problem, jasne że nie chcę otwierać drugi raz tego samego pliku. Powinienem wyraźniej zaznaczyć, że chodzi o zatrzymanie procedury gdy plik jest używany przez kogoś innego. Ten raport jest na dysku wspólnym i mają do niego dostęp inne osoby. Nie chcę oczywiście nikomu nic zamykać bez jego wiedzy, tylko chciałbym uniknąć komunikatu o błędzie, czyli przerwać procedurę. Ewentualnie zaznaczyć jedynie w swoim arkuszu, że dana pozycja nie została wpisana do raportu i potem jakąś inną procedurą mieć możliwość uzupełniania tych wpisów.
  • Pomocny post
    Moderator Programowanie
    siwek62 napisał:
    Powinienem wyraźniej zaznaczyć, że chodzi o zatrzymanie procedury gdy plik jest używany przez kogoś innego.
    Rozumuję następująco
    Code:
    On Error Resume Next
    
    Set plik = Workbooks("RAPORT DZIENNY.xls")
    If Err = 9 Then 'jeśli próba przypisania zakończona błędem
      On Error GoTo 0
      Set plik = Workbooks.Open(Filename:=ThisWorkbook.Path & "\RAPORT DZIENNY.xls")
    Else 'jeśli plik jest otwarty
      MsgBox "Plik jest otwarty. Spróbuj później..."
      Set plik = Nothing
      Exit Sub
    End If

    A może wystarczy
    Code:
    On Error Resume Next
    
    Set plik = Workbooks.Open(Filename:=ThisWorkbook.Path & "\RAPORT DZIENNY.xls")
    'w przypadku próby otwarcia używanego pliku otrzymujesz komunikat, wybierasz NIE
    If Err = 0 Then
      On Error GoTo 0
      plik.Sheets("Arkusz1").Range("d100") = ThisWorkbook.ActiveSheet.Range("b20")
    End If
    Set plik = Nothing
  • Poziom 11  
    Spróbowałem połączyć twoje kody, chciałem osiągnąć taki efekt, że jak raport jest otworzony przeze mnie to procedura działa normalnie, a jak jest otworzony na innym komputerze to dostaję komunikat. Ale niestety nie zadziałało.
    Zrobiłem sobie symulację sieci w domu, mam 2 komputery podłączone do sieci przez switch.

    Code:
    Sub sprawdz()
    
    On Error Resume Next
    Set plik = Workbooks("RAPORT DZIENNY.xls")
    If Err = 9 Then 'jeśli próba przypisania zakończona błędem
      On Error GoTo 0
     
        otwarty = False
        For Each ws In Workbooks
        If ws.Name = "RAPORT DZIENNY.xls" Then
          otwarty = True
          Exit For
        End If
        Next ws
       
        If Not otwarty Then
            Set plik = Workbooks.Open(Filename:="\\Edyta-pc\public\test\RAPORT DZIENNY.xls")
        Else
            MsgBox "Plik jest otwarty. Spróbuj później..."
            Exit Sub
        End If
    End If


    Efekt jest taki że jak raport jest otworzony na drugim kompie to u mnie otwiera mi RAPORT DZIENNY do odczytu.