Ενημέρωση βάσης από φόρμα

Ένας φίλος του ιστολογίου, έστειλε την παρακάτω ερώτηση: Σε ένα φύλλο, έχω τυποποιήσει μία φόρμα, πάνω στην οποία συλλέγω διάφορα στοιχεία. Προσπαθώ να γράψω μια μακροεντολή ώστε όταν ολοκληρώνω την δουλειά μου με την φόρμα, όλα τα δεδομένα να υποθηκεύονται σε μία βάση και η φόρμα να καθαρίζει και να είναι έτοιμη να υποδεχτεί νέα δεδομένα.
Για τη λύση του προβλήματος αυτού θα χρειαστούμε το φύλλο με τη φόρμα (πρώτη εικόνα), το φύλλο που θα υποδέχεται τα δεδομένα της φόρμας (βάση, δεύτερη εικόνα) και λίγο κώδικα ο οποίος έχει γραφτεί σε πολύ απλή μορφή, εύκολα προσαρμόσιμος στις δικές σας ανάγκες.
Στην πρώτη εικόνα είναι ένα απλό παράδειγμα φόρμας.

Το φύλλο “Φόρμα”

Κάποια από τα κελιά (B2,B4, B6,…) ενημερώνονται χειριστικά και κάποια (B12, B14, B16, D19) από συναρτήσεις. Όταν ο χρήστης ολοκληρώσει τη δουλειά που έχει να κάνει με την φόρμα, πατά το πλήκτρο: “Μεταφορά στη βάση & καθάρισμα της φόρμας” και τα δεδομένα της, δημιουργούν μια νέα εγγραφή (σειρά) στη βάση. (εικόνα 2).

Το φύλλο “Βάση” / Κλίκ για μεγέθυνση

Η ίδια η φόρμα καθαρίζει και είναι έτοιμη να υποδεχτεί νέα δεδομένα. (εικόνα 3).

εικόνα 3

Ακολουθεί ο κώδικας που θα χρειαστείτε και αναλυτικές οδηγίες για να τον προσαρμόσετε στις δικές σας ανάγκες.

 

Sub UpdateBaseAndCleanForm()
Dim t1, t2, t3, t4, t5
Dim t6, t7, t8, t9, t10

Dim arrayData As Variant
Dim cleanData As Range
Dim keli As Range
Dim baseSheet As Object
Dim formaSheet As Object
Dim meter As Long

Set baseSheet = Sheets("Βάση")
Set formaSheet = Sheets("Φόρμα")

Set t1 = formaSheet.Range("B2")
Set t2 = formaSheet.Range("B4")
Set t3 = formaSheet.Range("B6")
Set t4 = formaSheet.Range("B8")
Set t5 = formaSheet.Range("B10")
Set t6 = formaSheet.Range("B12")
Set t7 = formaSheet.Range("B14")
Set t8 = formaSheet.Range("B16")
Set t9 = formaSheet.Range("D19")
Set t10 = formaSheet.Range("D20")

meter = Application.WorksheetFunction.CountA(baseSheet.Range("A:A"))
arrayData = VBA.Array(meter, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
Set cleanData = Union(t1, t2, t3, t4, t5, t10)

With cleanData.Cells
 Set keli = .Find(What:="*", LookIn:=xlValues)
 If keli Is Nothing Then GoTo telos
 End With

baseSheet.Cells(meter + 1, 1).Resize(, 11) = arrayData
cleanData.ClearContents

telos:
End Sub


Στο παράδειγμα μεταφέρονται  από τη φόρμα στη βάση 10 τιμές από 10 κελιά. Αν οι τιμές που θα εσείς θα μεταφέρνετε από τη φόρμα σας προς τη βάση σας, είναι περισσότερες, προσθέστε μεταβλητές t.  Παράδειγμα για 17 τιμές προσθέστε μια ακόμα γραμμή κώδικα:
 Dim t11, t12, t13, t14, t15, t16, t17
Παρόμοια, αν οι τιμές σας είναι λιγότερες, διαγράψτε μεταβλητές t.
Το φύλλο που φιλοξενεί τη φόρμα λέγετε «Φόρμα» και το φύλλο της βάσης λέγετε «Βάση». Αν τα δικά σας φύλλα λέγονται διαφορετικά αλλάξτε τα ονόματα αυτά, στις σειρές 12 & 13. Αλλάξτε, αν χρειάζεται, μόνο τα ονόματα μέσα στα εισαγωγικά.
Στις σειρές 15-24, οι μεταβλητές t αντιστοιχίζονται στα κελιά της φόρμας, κελιά όπου εισάγονται εγγραφές, οι οποίες θα μεταφέρονται στη βάση. Αλλάξτε τις διευθύνσεις των κελιών μέσα στα εισαγωγικά ώστε να ταιριάζουν με τις διευθύνσεις των κελιών της δικιά σας φόρμας. Ενδεχομένως θα προσθέσετε ή θα αφαιρέσετε αντιστοιχίες. Οι αντιστοιχίες θα είναι τόσες, όσες και οι μεταβλητές t.
Στη σειρά 27 γράψτε όλες τις μεταβλητές t στην παρένθεση του πίνακα Array.
Στην επόμενη σειρά 28, μέσα στην παρένθεση: Union( ), πρέπει να γραφούν, μόνο οι μεταβλητές t που αντιστοιχούν σε κελιά τα οποία ενημερώνονται χειριστικά ή από επικυρώσεις. Δεν θα γραφούν εδώ οι μεταβλητές t που αντιστοιχούν σε κελιά τα οποία ενημερώνονται από τύπους, όπως είναι τα κελιά B12, B14, B16, D19 του παραδείγματος. Εδώ θα γραφούν μόνο τα κελιά τα οποία θέλουμε να «καθαρίζονται» μετά την ενημέρωση της βάσης.
Τέλος στη σειρά 35 στην παρένθεση Resize(, 11) αλλάξτε τον αριθμό 11. Πρέπει να είναι κατά ένα μεγαλύτερος από τον πλήθος των μεταβλητών t.
Αν θέλετε κατεβάστε το excel βιβλίο: UpdateBaseAndCleanForm για να δείτε το παραπάνω παράδειγμα στην πράξη.
This entry was posted in excel, Μακροεντολές, VBA and tagged , , , , . Bookmark the permalink.

35 Responses to Ενημέρωση βάσης από φόρμα

  1. Ο/Η Γιώργος λέει:

    Πολύ καλό και χρήσιμο. Νομίζω ότι θα ήταν επίσης πολύ χρήσιμο αν περιλάμβανε δυνατότητα (ένα κουμπί όπως σε βάσεις δεδομένων) για επιλογή εγγραφής ή εισαγωγή νέας σε περίπτωση που θέλουμε να επανέλθουμε για συμπλήρωση-τροποποίηση κλπ.

  2. Ο/Η Νίκος λέει:

    Να ‘ναι καλά ο φίλος που το ζήτησε, αυτό ακριβώς που έψαχνα!
    Ανακάλυψα σήμερα το site σου και όσα περιέχει είναι πολύ βοηθητικά. Σε ευχαριστούμε πολύ για όλα. Εύχομαι καλή συνέχεια.

  3. Ο/Η Fotis λέει:

    ΣΥΓΧΑΡΗΤΗΡΙΑ και πάλι, αγαπητέ κύριε Βαρλάμη.
    Με αφορμή αυτή τη ΛΥΣΗ, που μας προσφέρατε, δοκίμασα να την εφαρμόσω σε ένα Ερασιτεχνικό «προγραμματάκι» μου και τα κατάφερα αρχικά, αλλά όταν θέλησα να αυξήσω τις μεταβλητές της vbArray, μπόρεσα να βάλω μέχρι 159, ενώ χρειαζόμουν 302.
    Ευχαριστώ ούτως ή άλλως, ασχέτως αν βρείτε χρόνο να το δείτε.
    Με εκτίμηση, ένας ακόμη της ίδιας γενιάς (’53).

  4. Ο/Η vioannis λέει:

    Φώτη
    Μπορείς να χωρίσεις τις μεταβλητές σε διάφορους πίνακες (arrayData)
    Dim arrayData As Variant
    Dim arrayDataB As Variant
    Dim arrayDataC As Variant

    arrayData = VBA.Array(meter, t1, t2, t3, t4, t5, t6, t7, t8, t9,……. t100)
    arrayDataB = VBA.Array(t101, t102,……….t200)
    arrayDataC = VBA.Array(t201, t202,……….t300)

    baseSheet.Cells(meter + 1, 1).Resize(, 101) = arrayData
    baseSheet.Cells(meter + 1, 102).Resize(, 100) = arrayDataB
    baseSheet.Cells(meter + 1, 202).Resize(, 100) = arrayDataC

    Δηλαδή ο πρώτος arrayData έχει 100 στοιχεία, θα χρειαστεί 101 κελιά μιας σειράς για να εναποθέσει τα στοιχεία του, διότι ο πρώτος arrayData έχει μέσα και τον μετρητή (meter). Εμμέσως μετά εναποθέτει ο arrayDataΒ στην ίδια σειρά (meter+1), από τη στήλη 102 και 100 κελιά δεξιά κλπ. Το resize τώρα είναι Resize(, 100) όσα δηλαδή τα στοιχεία του arrayDataB.
    Ακολουθεί ο πίνακας arrayDataC από τη στήλη 202 και δεξιά, με resize όσα στοιχεία περιέχει.
    Τόσες πολλές στήλες όμως, μόνο για excel 2007, 2010. Τα πιο παλιά έχουν μόνο 256 στήλες στο φύλλο.
    Ελπίζω να δουλέψει.

  5. Ο/Η Fotis λέει:

    Ακολούθησα τις οδηγίες (τροποποιώντας τον Κώδικα) και (μετά από μερικές προσπάθειες) λειτούργησε.
    ΕΥΧΑΡΙΣΤΩ πάρα-πάρα πολύ και επιφυλάσσομαι, ευελπιστώντας να φανώ και εγώ κάπου χρήσιμος.
    Με ιδιαίτερη εκτίμηση,
    Φώτης.

  6. Ο/Η george λέει:

    Συγχαρητήρια και απο εμένα κ.Βαρλάμη!!!
    Με έχει βοηθήσει και εμένα πάρα πολύ αυτή η φόρμα και την χρησιμοποιώ σε προσωπικές εργασίες.
    Το πρόβλημα που παρατήρησα σε μία εφαρμογή είναι το εξής
    Ενώ το έχω αντιγράψει σωστά επιλέγω πια κελιά θα είναι ξεκλείδωτα και στα υπόλοιπα επιλέγω προστασία φύλλου.Κάνω την καταχωρηση και μου βγάζει πρόβλημα .Πηγαίνω στην vba και μου έχει κιτρινήσει στο τέλος το κείμενο «Cleandata.ClearContents »
    Εαν πατήσω κατάργηση φύλλου και επιλέξω να μεταφέρω την καταχώρηση στην βάση μου τιν περνάει κανονικά.
    Γνωρίζει κανείς τί κάνω λάθος?

    Ευχαριστώ
    Γιώργος

  7. Ο/Η vioannis λέει:

    george, αυτό, πιθανά, συμβαίνει διότι κάποιο ή κάποια από τα κελιά που προσπαθεί να καθαρίσει η εντολή ClearContents (σειρά 36 του κώδικα), το βρίσκει κλειδωμένο. Τα κελιά που καθαρίζει η εντολή αυτή, έχουν καθοριστεί στη σειρά 28: Set cleanData = Union( )
    Βεβαιώσου ότι όταν τρέχεις την μάκρο, αυτά τα κελιά δεν είναι κλειδωμένα.
    Εναλλακτικά, δοκίμασε το παρακάτω: Στον κώδικα μετά την γραμμή 13 πρόσθεσε την εντολή:
    formaSheet.Unprotect
    και μετά τη γραμμή 38 την εντολή:
    formaSheet.Protect
    Επανέρχεσαι αν το πρόβλημα εξακολουθεί.

  8. Ο/Η Γιώργος λέει:

    Καλημέρα
    Ευχαριστώ πολύ για την άμεση απάντηση σας.
    Τελικά είχα κάνει λάθος και υπήρχε ενα κελί που το έβρισκε κλειδώμένο.
    Καλή εβδομάδα σε όλους τους φίλους του ιστολογίου!!!

    Γιώργος

  9. Ο/Η Manios λέει:

    θεωρώ ότι είναι ένας από τους καλύτερους χώρους για το excel. ΑΠΛΑ ΣΥΓΧΑΡΗΤΗΡΙΑ!

  10. Ο/Η vioannis λέει:

    Μάνιο, ευχαριστώ για τα καλά σου λόγια και για την ενθάρρυνση

  11. Ο/Η mixalis λέει:

    Μπορεί να γραφτεί μια vba που να σβήνει τα περιεχόμενα της βάσης, αλλά να βρίσκεται σε άλλο φύλλο εργασίας; Για παράδειγμα, από ένα τυχαίο φύλλο διαφορετικό της βάσης να σβήνω τις καταχωρήσεις της βάσης

  12. Ο/Η vioannis λέει:

    Μιχάλη, δεν διευκρινίζεις με ποιο κριτήριο θα γίνεται η διαγραφή των εγγραφών (σειρών) της βάσης. Σου δίνω δύο vba ρουτίνες που μπορείς να τις καλέσεις από οποιοδήποτε φύλλο του βιβλίου που είναι η βάση. Στην πρώτη (testA) η διαγραφή γίνεται με βάση τον αριθμό γραμμής. Όταν τρέξεις τη μάκρο, ένα InputBox θα σου ζητήσει τον αριθμό ή τους αριθμούς γραμμής. Αν είναι περισσότεροι από έναν θα τους γράψεις διαχωρισμένους με κόμμα: πχ 5,7,15,28,35,47,512. Μόλις πατήσεις το ΟΚ του InputBox, ολόκληρες οι γραμμές αυτές θα διαγραφτούν οριστικά από τη βάση σου. Για αυτό, πριν αποφασίσεις αν σε εξυπηρετεί, δοκίμασε τη πρώτα με ένα αντίγραφο της βάσης ή με ένα παράδειγμα. Στη μάκρο το φύλλο της βάσης έχει όνομα «ΦύλλοΒάσης». Εσύ θα το αλλάξεις με το δικό σου, στην γραμμή 8 του κώδικα

    Sub testA()
    
    Dim j As Integer
    Dim RowNumbers As String
    Dim RowSplit As Variant
    Dim SheetName As String
    
    SheetName = "ΦύλλοΒάσης"
    On Error GoTo telos
    
    RowNumbers = Application.InputBox _
        (prompt:="Αριθμοί γραμμών που θα διαγραφούν" _
        + vbLf + "διαχωρισμένοι με κόμμα (,)", _
        Title:="Διαγραφή εγγραφών βάσης", _
        Type:=2, Left:=150, Top:=80)
            
    RowSplit = VBA.Split(RowNumbers, ",")
    For j = LBound(RowSplit) To UBound(RowSplit)
        Sheets(SheetName).Rows(RowSplit(j)).Delete Shift:=xlUp
    Next j
    
    telos:
    End Sub
    
    

    Η δεύτερη ρουτίνα (testB), διαγράφει μία ή περισσότερες εγγραφές, αφού αναζητήσει τις τιμές που θέλεις σε κάποιο πεδίο (στήλη) της βάσης. Παράδειγμα: Αν στη στήλη Β έχεις κωδικούς και θέλεις να διαγράψεις τους κωδικούς Α512, ΖΖΚ703, 456 κλπ, καλείς τη ρουτίνα και στο InputBox που θα εμφανιστεί, γράφεις τους κωδικούς χωρισμένους με κόμματα. Μόλις πατήσεις ΟΚ , η μάκρο θα ψάξει για του κωδικούς αυτούς στη στήλη Β και θα διαγράψει οριστικά τις εγγραφές (γραμμές) αυτές. Αν οι κωδικοί είναι μοναδικοί θα κάνει μία διαγραφή για τον καθένα, αν δεν είναι μοναδικοί θα κάνει πολλές, όλες τις διαγραφές για τον καθένα Αν κάποιος κωδικός δεν υπάρχει θα τον αγνοήσει σιωπηλά.
    Άλλο παράδειγμα: Στη στήλη C έχεις μικρά ονόματα και θέλεις από τη βάση σου να διαγραφούν όσοι έχουν όνομα Γιάννης, Τάκης, Ελένη. Καλείς τη testB και στο InputBox γράφεις τα παραπάνω ονόματα χωρισμένα πάντα με κόμματα. Η μάκρο θα ψάξει στη στήλη C για όλους με τα ονόματα αυτά και θα διαγράψει τις αντίστοιχες εγγραφές (γραμμές). Η διαγραφή είναι οριστική, για αυτό όλες οι δοκιμές να γίνουν σε πρόχειρο αντίγραφο. Στην testB πρέπει να αλλάξεις εκτός από το όνομα του φύλλου της βάσης (γραμμή 10 του κώδικα) και το γράμμα της στήλης στο οποίο θα γίνεται το ψάξιμο (γραμμή 11 του κώδικα).

    Sub testB()
    Dim j As Integer
    Dim i As Integer
    Dim LastRow As Long
    Dim RowNumbers As String
    Dim RowSplit As Variant
    Dim SC As String
    Dim WS As Worksheet
    
    Set WS = Worksheets("ΦύλλοΒάσης")
    SC = "b" 'Search Column
    On Error GoTo telos
    
    RowNumbers = Application.InputBox _
        (prompt:="Κωδικοί που θα διαγραφούν" _
        + vbLf + "διαχωρισμένοι με κόμμα(,)", _
        Title:="Διαγραφή εγγραφών βάσης", _
        Type:=2, Left:=150, Top:=80)
            
    RowSplit = VBA.Split(RowNumbers, ",")
    For j = LBound(RowSplit) To UBound(RowSplit)
    
        LastRow = WS.Cells(Rows.Count, SC).End(xlUp).Row
        For i = LastRow To 1 Step -1
            If VBA.CStr((WS.Cells(i, SC).Value)) = RowSplit(j) Then
            WS.Cells(i, "A").EntireRow.Delete
        End If
        Next i
    Next j
    
    telos:
    End Sub
    
    
  13. Ο/Η γιώργος Νάκος λέει:

    καλησπέρα κύριε Βαρλάμη
    χρησιμοποιώ την βάση σε αρκετές προσωπικές εργασίες χωρίς κανένα πρόβλημα.
    Σε μία βάση που θέλω να φτιάξω με 46 μεταβλητές t στην σειρά set cleandata =union μου βγάζει το εξής μήνυμα
    compile error:
    Wrong number or arguments or invalid property assignment
    Μπορείτε να με βοηθήσετε γιατί μου βγάζει αυτό το πρόβλημα?

    Ευχαριστώ εκ τον προτέρων
    Γιώργος

  14. Ο/Η vioannis λέει:

    Γιώργο, οφείλεται στο γεγονός ότι η μέθοδος Union δέχεται έως 30 το πολύ ορίσματα. Αυτό όμως ξεπερνιέται εύκολα, διότι τα ορίσματα της Union μπορούν να είναι άλλες Union. Έτσι γράψε:

    Set cleanData = Union(Union(t1, t2,……), Union(t31,t32….))
    

    Χωρίς να ξεπερνάς τις 30 μεταβλητές t σε κάθε εσωτερική Union

  15. Ο/Η γιώργος Νάκος λέει:

    Σας ευχαριστώ πάρα πολύ για την άμεση και εύστοχη βοήθεια σας!!!

  16. Ο/Η Μάκης Αντωνίου λέει:

    Καλημέρα σας και συγχαρητήρια για το μεστό περιεχόμενο στης σελίδας σας, θα ήθελα να ρωτήσω πώς είναι δυνατό να συμπληρωθεί η παραπάνω λειτουργία με τη φόρμα ώστε όταν εισάγω τα στοιχεία μιας γραμμής για να προστεθεί στη βάση αυτή να αποθηκεύεται ταξινομημένα με βάση π.χ. ένα όρισμα με ημερομηνία και ένα άλλο όρισμα το όνομα.
    Ευχαριστώ

  17. Ο/Η Μάκης Αντωνίου λέει:

    Επίσης πώς μπορεί να γίνει τα στοιχεία της φόρμας να αποθηκεύονται σε μη γειτονικά κελιά στη βάση μας τα οποία θα ορίσουμε εμείς;
    Ευχαριστώ και πάλι

  18. Ο/Η vioannis λέει:

    Μάκη, Ωραίο ερώτημα.
    Στο τέλος του κώδικα (πριν τη γραμμή telos:), πρόσθεσε αυτές τις γραμμές κώδικα.

    With baseSheet
    .Range("A1").Sort _
    Key1:=.Range("J1"), Order1:=xlAscending, _
    Key2:=.Range("B1"), Order2:=xlAscending, _
    Header:=xlYes
    End With
    

    Ο κώδικας αυτός, κάθε φορά που εισάγεις μία νέα εγγραφή (γραμμή), στη βάση ταξινομεί τα δεδομένα της βάσης σε αύξουσα ταξινόμηση ως προς δύο πεδία (στήλες). Πρώτα ως προς την J (ημερομηνία) και μετά ως προς την B (όνομα). Θα αλλάξεις τα J1 και Β1 στον κώδικα, με βάση ως προς ποια πεδία (στήλες) θέλεις να ταξινόμησης τη δικιά σου βάση. Ο κώδικας υπολογίζει ότι η βάση ξεκινά από το κελί Α1 και επεκτείνεται κάτω και δεξιά. Η μέθοδος sort δεν έχει πρόβλημα να εκτιμήσει αυτόματα μόνη της την ενεργή περιοχή (active region) όλης της βάσης από ένα και μόνο κελί (το Α1). Αρκεί βέβαια η βάση να είναι δομημένη σωστά, χωρίς ενδιάμεσες, εντελώς κενές γραμμές, ή στήλες. Αν, τώρα, στη στήλη Α έχεις (όπως στο παράδειγμα του ιστολογίου) μία συνεχή αρίθμηση των εγγραφών (γραμμών) της βάσης, και δεν θέλεις η στήλη Α να συμμετέχει στην ταξινόμηση τότε τροποποίησε τη δεύτερη γραμμή του κώδικα ως εξής:

    Range("B1:K" & meter + 1).Sort _
    

    Εδώ K είναι η τελευταία στήλη της βάσης. Θα αλλάξεις το K με το γράμμα της τελευταίας στήλης της δικιάς σου βάσης. Η γραμμή του κώδικα Header:=xlYes, ορίζει ότι η πρώτη γραμμή της βάσης είναι τίτλοι και έτσι η γραμμή αυτή δεν συμμετέχει στην ταξινόμηση. Αν παρ’ ελπίδα η βάση σου δεν έχει τίτλους στη πρώτη γραμμή (δεν το συμβουλεύω καθόλου, θα είναι μία “κακή” βάση), τότε άλλαξε αυτή τη γραμμή έτσι: Header:=xlNo. Αν για κάποιο από τα δύο πεδία (ή και για τα δύο) θέλεις φθίνουσα ταξινόμηση άλλαξε την σταθερά xlAscending σε xlDescending
    Τέλος, όσο μεγάλη και να είναι η βάση σου, μη φοβάσαι ότι θα δημιουργείται καθυστέρηση, η ταξινόμηση είναι από τις πιο γρήγορες και δυνατές λειτουργίες του excel.

  19. Ο/Η vioannis λέει:

    Για τη δεύτερη ερώτηση. Αν αφήνεις κενά κελιά (καθόλου καλή ταχτική) κινδυνεύεις τελικά να μην πάρεις μία βάση με τα δεδομένα σου. Αν θέλεις να έχεις ένα κενό κελί μεταξύ τις τιμής t2 και t3 τροποποίησε έτσι την γραμμή 27 του κώδικα

    arrayData = VBA.Array(meter, t1, t2, "", t3, t4, t5, t6, t7, t8, t9, t10)
    

    Για κάθε κενό (“”) που παρεμβάλεις, θα αυξάνεις κατά 1 το Resize στη γραμμή 35.
    Ο γενικός πάντως τρόπος για μεταφορά δεδομένων από το κελί Α1 του Φύλλου1, στο κελί C5 του Φύλλου2 είναι:

    Sheets("Φύλλο1").Range("A1").Copy Destination:=Sheets("Φύλλο2").Range("C5")
    

    Αν δεν θέλεις να μεταφερθεί στο C5 η μορφοποίηση του Α1 ή αν στο κελί Α1 είναι συνάρτηση και θέλεις στο κελί C5 να μεταφερθεί μόνο η αξία που επιστρέφει η συνάρτηση και όχι ο τύπος τότε:

    Sheets("Φύλλο2").Range("C5").Value = Sheets("Φύλλο1").Range("A1").Value
    
  20. Ο/Η Γιώργος λέει:

    ΣΥΓΧΑΡΗΤΗΡΙΑ κύριε Βαρλάμη !!!
    Με έχει βοηθήσει πάρα πολύ αυτή η φόρμα και την χρησιμοποιώ σε προσωπικές εργασίες.
    Το πρόβλημα που αντιμετώπισα στην εφαρμογή είναι το εξής
    έχω τρεις στήλες , Α/Α, ΕΠΙΘΕΤΟ , ΟΝΟΜΑ , όταν συμπληρώνω με την φόρμα την βάση όλα οκ ,όταν όμως βάζω χειρόγραφα στοιχεία στην βάση και κατόπιν βάζω στοιχεία με την φόρμα δεν συνεχίζει τα νέα στοιχεία να τα αριθμεί και να τα βάζει μετά τα χειρόγραφα αλλά τα τοποθετεί επάνω στα χειρόγραφα
    Μπορείτε να με βοηθήσετε σ αυτό το πρόβλημα?

    Ευχαριστώ εκ τον προτέρων
    Γιώργος

  21. Ο/Η vioannis λέει:

    Γιώργο, όταν βάζεις χειρόγραφα στοιχεία στη βάση, συμπληρώνεις το κελί με α/α; Αν το συμπληρώνεις, λογικά δεν πρέπει να συμβαίνει αυτό που περιγράφεις. Η στήλη με τους α/α πρέπει να είναι σε όλα τα κελιά της συμπληρωμένη, ακόμα και αν στη βάση έχεις γραμμές κενές (που είναι κακή συγκρότηση βάσης). Η μακροεντολή πριν πάει να γράψει μια νέα γραμμή στη βάση, μετρά το πλήθος των προηγούμενων εγγραφών(σειρών) από τη στήλη Α, και τη γράφει στην επόμενη κενή γραμμή. Αν, λοιπόν, στη στήλη Α, βρει κενά κελιά, δεν θα κάνει καλή μέτρηση, με αποτέλεσμα την επικάλυψη. Δεν είναι απαραίτητο οι α/α να είναι συνεχόμενοι αριθμοί, ούτε καν απαραίτητο να είναι αριθμοί. Απλά είναι το πεδίο (στήλη) που όλα του τα στοιχεία (κελιά) πρέπει να είναι συμπληρωμένα. Πες μου αν λύθηκε το πρόβλημα.

  22. Σ ευχαριστώ πολύ !!! όντως το πρόβλημα μου λύθηκε .
    Τώρα αντιμετωπίζω δύο άλλα προβληματάκια
    α/ πως μπορώ το κείμενο ενός κελιού να το κάνω να αναβοσβήνει ?
    β/στο φύλλο της βάσης έχω 6 στήλες (Α/Α, ΟΝΟΜΑ, ΕΠΙΘΕΤΟ , ΑΔΕΙΑ, ΑΦΜ, ΙΚΑ) η βάση ενημερώνεται από την φόρμα αλλά θέλω η στήλη ΑΔΕΙΑ να είναι κλειδωμένη γιατί περιέχει τύπους ενώ οι άλλες στήλες ανοικτές για να δέχονται τα δεδομένα της φόρμας
    Μπορείτε να με βοηθήσετε ?

    Ευχαριστώ εκ τον προτέρων
    Γιώργος

  23. Ο/Η vioannis λέει:

    Γιώργο
    Α) Γιατί θέλεις να κάνεις το αρχείο σου American bar, όπως έλεγε ο Διονύσης Παπαγιαννόπουλος. Αν επιμένεις, θα βρεις στο Google πολλές σχετικές μακροεντολές ανάλογα με την έκδοση που έχεις και τι θες να κάνεις με τη λειτουργία αυτή. Ψάξε με τις φράσεις: excel how to make a cell blink ή excel flashing cells. Η διαδικασία αυτή δουλεύει συνεχώς στο παρασκήνιο και βαραίνει το φύλλο, δεν την συνιστώ καθόλου. Β) Κάνε τη στήλη ΑΔΕΙΑ τελευταία της βάσης και έξω από το εύρος των στηλών που ενημερώνει η μακροεντολή από τα δεδομένα της φόρμας. Η συγκεκριμένη μάκρο ενημερώνει συνεχόμενα και μη κλειδωμένα κελιά και αυτό δεν αλλάζει.

  24. Ο/Η Μιχάλης λέει:

    Νομίζω ότι η δουλεία που γίνεται σε αυτό το μπλογκ είναι εξαιρετική. Θα ήθελα όμως και άλλη μια ερώτηση να κάνω:
    Έχω φτιάξει πρόγραμμα που σε ένα φύλλο («ΦΥΛΛΟ 1») εισάγω παραμέτρους, στο ίδιο φύλλο κάποιες συναρτήσεις κάνουνε πράξεις και με vba στέλνω στοιχεία και αποτελέσματα συναρτήσεων σε μια βάση («ΒΑΣΗ») και συγχρόνως σβήνω αυτά που έστειλα από το ΦΥΛΛΟ1, ώστε να συνεχιστεί η διαδικασία με άλλες, νέες, παραμέτρους. Πως μπορώ να στείλω πίσω κάποια στοιχεία (όλα τα στοιχεία μιας γραμμής) από την βάση, αν ενδεχομένως έβαλα κάποια από τις παραμέτρους λάθος ώστε να τις αλλάξω; και να μπούνε στην θέση που τις είχα αρχικά. Η νέα εγγραφή θα στείλει στις κενές θέσεις της ΒΑΣΗΣ όπως θα ήθελα;

  25. Ο/Η vioannis λέει:

    Μιχάλη, ο κώδικας που θα κάνει αυτό που ζητάς δεν είναι δύσκολο να γραφτεί . Πρώτα όμως πρέπει να διευκρινιστούν ορισμένα πράγματα α) Πως θα επιλέγεται η εγγραφή (γραμμή) από τη βάση; Από τον αριθμό γραμμής του φύλλου ή από τον μοναδικό α/α ή από έναν άλλο (οπωσδήποτε μοναδικό) κωδικό; Το πιο εύκολο και γρήγορο είναι το πρώτο. β) Όταν θα φέρνεις την εγγραφή στη φόρμα θα έρχονται όλα τα δεδομένα (κελιά) της εγγραφής; Αν η απάντηση είναι ΝΑΙ, τότε τα δεδομένα που έχουν προκύψει από συναρτήσεις θα διαγράψουν τις συναρτήσεις στη φόρμα. Στο παράδειγμα στην αρχή της σελίδας, θα διαγραφούν οι συναρτήσεις στα κελιά B12, B14, B16. Άρα πρέπει να προβλεφτεί κώδικας, ώστε σε κατάλληλο σημείο να ξανατοποθετούνται οι συναρτήσεις στη φόρμα. Αν η απάντηση είναι ΟΧΙ και θα έρχονται στη φόρμα μόνο τα κελιά της εγγραφής που έχουν προκύψει από χειριστική εισαγωγή, τότε προκύπτει ένα άλλο ερώτημα. Οι τύποι που υπάρχουν στη φόρμα, έχουν διαχρονική αξία και για τα παλιά δεδομένα; Παράδειγμα: Αν ένας τύπος υπολογίζει ΦΠΑ με σημερινό ποσοστό α%, θα υπολογίσει το ίδιο α% και στα παλιά δεδομένα. Μήπως αυτό δεν είναι σωστό; Αν οι περιπτώσεις αυτές είναι πολλές, δεν υπάρχει εύκολη απάντηση. Κατά τα άλλα, με απλές τεχνικές μπορούμε να κάνουμε την μακροεντολή να καταλαβαίνει αν μια εγγραφή είναι νέα ή παλιά διορθωμένη, και να την στέλνει στην κατάλληλη θέση στη βάση.

  26. Ο/Η Nikos Gkikas λέει:

    Οσο περισσοτερο ψαχνω το site σου τοσο με εκπλησεις με τις γνωσεις σου και το κυριοτερο που τις μοιραζεσαι μαζι μας .
    Εχω και εδω καποιες αποριες , τα δεδομενα που θελω εγω να καταχωρω και να ενημερωνεται η λιστα ειναι περιπου 20 με 25 (αναλογως)
    α) πως μπορω να τα προσθεσω
    β) οι εγγραφες οταν γινεται αυτοματα παει και κανει εγγραφη απο στην βαση απο κατω προς τα πανω και οχι απο πανω προς τα κατω !! Αυτα προς το παρον .

    Νικος

  27. Ο/Η vioannis λέει:

    Νίκο, ο κώδικας αυτός είναι πολυδοκιμασμένος από πολλούς φίλους του ιστολογίου. Για το πρώτο ερώτημα, βάλε τα δεδομένα σου σε όποιο κελί θέλεις στο φύλλο Φόρμα και φτιάξε αντιστοιχίες για όλες τις μεταβλητές t1,t2..t25 με τα κελιά αυτά. Το περιγράφω στο σημείωμα αναλυτικά. Το άλλο πρόβλημα που περιγράφεις, δεν μπορώ να φανταστώ γιατί συμβαίνει. Μήπως στο φύλλο Βάση, έχεις κενές σειρές ή άλλες άσχετες εγγραφές;

  28. Ο/Η Nikos Gkikas λέει:

    Τον κωδικα το εχω φτιαξει καπως ετσι αλλα !!

    Sub UpdateBaseAndCleanForm()
    Dim t1, t2, t3, t4, t5
    Dim t6, t7, t8, t9, t10
    Dim t11, t12, t13, t14, t15
    Dim t16, t17, t18, t19, t20
    Dim t21, t22,t23,t24
    
    Dim arrayData As Variant
    Dim cleanData As Range
    Dim keli As Range
    Dim baseSheet As Object
    Dim formaSheet As Object
    Dim meter As Long
    
    Set baseSheet = Sheets("Table")
    Set formaSheet = Sheets("Éïõíéïò_Öïñìá")
    
    Set t1 = formaSheet.Range("B2")
    Set t2 = formaSheet.Range("B4")
    Set t3 = formaSheet.Range("B6")
    Set t4 = formaSheet.Range("B8")
    Set t5 = formaSheet.Range("B10")
    Set t6 = formaSheet.Range("B12")
    Set t7 = formaSheet.Range("B14")
    Set t8 = formaSheet.Range("B16")
    Set t9 = formaSheet.Range("B18")
    Set t10 = formaSheet.Range("B20")
    Set t11 = formaSheet.Range("B22")
    Set t12 = formaSheet.Range("D24")
    Set t13 = formaSheet.Range("F2")
    Set t14 = formaSheet.Range("F4")
    Set t15 = formaSheet.Range("F6")
    Set t16 = formaSheet.Range("F8")
    Set t17 = formaSheet.Range("F10")
    Set t18 = formaSheet.Range("F12")
    Set t19 = formaSheet.Range("F14")
    Set t20 = formaSheet.Range("F16")
    Set t21 = formaSheet.Range("F18")
    Set t22 = formaSheet.Range("F20")
    Set t23 = formaSheet.Range("F22")
    Set t24 = formaSheet.Range("B28")
    
    meter = Application.WorksheetFunction.CountA(baseSheet.Range("A:A"))
    meter = Application.WorksheetFunction.CountA(baseSheet.Range("B:B"))
    arrayData = VBA.Array(meter, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24)
    Set cleanData = Union(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24)
    
    With cleanData.Cells
     Set keli = .Find(What:="*", LookIn:=xlValues)
     If keli Is Nothing Then GoTo telos
     End With
    
    baseSheet.Cells(meter + 1, 1).Resize(, 11) = arrayData
    cleanData.ClearContents
    telos:
    End Sub
    

    Μου βγαζει run time error 1004 και ου κιτρινιζει στον κωδικα το {cleanData.ClearContents}

    =================================
    Υποψιν επειδη εχω αρκετα πεδια (24) τα εχω κανει σε 2 στηλες τα πεδια.
    Στο πεδιο {meter = Application.WorksheetFunction.CountA(baseSheet.Range(«A:A»)) τι βαζω για τα δεδομενα επικεφαλιδες στην στηλη E: ?
    ΥΓ
    sorry Αν γινομαι κουραστικος αλλα δεν ξερω καθολου απο vba !!

  29. Ο/Η vioannis λέει:

    Νίκο, να ξεκαθαρίσουμε τι κάνει αυτό το μικρό πρόγραμμα. Έχεις ένα φύλλο Φόρμα (ή όπως αλλιώς θέλεις να λέγεται) στο οποίο σε κάποια κελιά(όποια θέλεις) εισάγεις δεδομένα, και σε κάποια κελιά (πάλι όποια θέλεις) έχεις γράψει τύπους που κάνουν υπολογισμούς. Όταν τελειώσεις με την εισαγωγή των δεδομένων στο φύλλο Φόρμα (το οποίο μπορεί να είναι ένα τιμολόγιο, ένα δελτίο αποστολής, μια καρτέλα αποθήκης, ο έλεγχος ενός μαθητή, η καρτέλα ενός πελάτη, ένα απογραφικό δελτίο ή χίλια άλλα πράγματα κλπ) και κάνεις κάτι με αυτό, πχ το τυπώσεις, και στη συνέχεια θέλεις να αποθηκεύσεις τα δεδομένα αυτής της φόρμας σε μία βάση, που θα την έχεις σαν αρχείο και η φόρμα θα καθαρίσει για να δεχτεί νέα στοιχεία (νέο τιμολόγιο, νέο δελτίο αποστολής κλπ) Ο κώδικας κάνει αυτό. Μεταφέρει όλες τις εγγραφές από το φύλλο Φόρμα, στο φύλλο Βάση (ή όπως αλλιώς το ονομάζεις). Στο φύλλο Βάση, που πρέπει να είναι ένα νέο καθαρό φύλλο, στην πρώτη γραμμή (κελιά Α1,Β1,C1 κλπ) γράψε οποίους τίτλους θέλεις και σε βολεύουν και μετά, με το πάτημα του κουμπιού, μεταφέρεις κάθε φορά και μία νέα φόρμα στη βάση. Όλα τα δεδομένα της φόρμας δημιουργούν κάθε φορά μια και μόνο μια νέα γραμμή. Στον κώδικα που έστειλες έχεις προσαρμόσει σωστά τις αντιστοιχίες , αλλά δεν έχεις αλλάξει τον αριθμό 11 στο Resize(, 11). Για 24 μεταβλητές πρέπει να είναι 25.Διάβασε με προσοχή τις οδηγίες. Τα λένε όλα, ώστε να προσαρμόσεις τον κώδικα στις δικές σου ανάγκες και ας μην έχεις γνώσεις vba. Επίσης ο κώδικας δεν δουλεύει με κλειδωμένα κελία. Πιθανότατα για αυτό πήρες μήνυμα λάθους. Δες στην ίδια σελίδα και τις άλλες συζητήσεις. Η μεταβλητή meter δημιουργεί στη βάση μια συνεχή αρίθμηση στη στήλη Α της Βάσης και μετρά κάθε νέα εγγραφή, άρα γράψε στο κελί Α1 της Βάσης τον τίτλο Α/Α και μην εισάγεις άλλη μεταβλητή meter. Σβήσε λοιπόν την γραμμή:

    meter = Application.WorksheetFunction.CountA(baseSheet.Range("B:B"))
    
  30. Ο/Η Nikos Gkikas λέει:

    Αγαπητε Γιαννη το ειδα και εγω το λαθος που ειχα κανει με αριθμό 11 στο Resize και το αλλαξα ,αλλα το προβλημα εμενει θα δοκιμασω την αλλαγη που μου εστειλες και θα επανελθω .
    Υπαρχει περιπτωση να κανω στην φορμα search να μου φερει καποια καταχωρηση που εχω κανει στην Βαση ετσι ως ωστε να αλλαξω καποια δεδομενα και να γινει overright στην αντιστοιχη εγγραφη της βασης ?? !

    Τι ειπα τωρα , εβαλά δυσκολο προβλημα .
    Το ρχειο αυτο το δουλευω για επαφες που εχουν κανει πωλητες με διαφορους πελατες και ενημερωνουν μια βαση .Επ[ειδη ομως πανε στην αρχικη βαση και μου κανουν ανω κατω την βαση με copy paste ,μου χαλανε εγγραφες αλλων πωλητων .Γιαυτο βρηκα πολυ χρησιμη την λυση σου …
    Ευχαριστω για την κατανοηση και παλι

    =============
    το προβλημα οσο αφορα τα δεδομενα δεν τα εχω βαλει σε αλλη 2 στηλες αλλα σε μια (μικρο το κακο) αυτο που δεν δουλευει ειναι οτι δεν κανει clear την φορμα και μου βγαζει το μυνημα λαθους πυ σου περιεγραψα– {Μου βγαζει run time error 1004 και μου κιτρινιζει στον κωδικα το {cleanData.ClearContents}

  31. Ο/Η vioannis λέει:

    Το πρόβλημα είναι πιθανά στο βιβλίο σου και όχι στον κώδικα. Αν τρέξεις τον δικό σου κώδικα σε ένα νέο βιβλίο, όπως έκανα εγώ, θα δεις ότι δεν υπάρχει πρόβλημα. Δες αυτή εδώ την απάντηση μου στο ίδιο θέμα. Ο κώδικας κάνει αυτό που περιέγραψα. Αυτό που ζητάς με το search και του overright είναι άλλο θέμα και άλλου κώδικα.

  32. Ο/Η Nikos Gkikas λέει:

    Γιαννη επιτελους τα καταφερα επρεπε να περναω χειροκινητα τα t1,t2…. στο union και οχι με copy paste

  33. Ο/Η Nikos Gkikas λέει:

    Γιαννη καλημερα ,ι επανερχομαι με ενα απλο μαλλον ερωτημα .. τα αρχεια xlsm ειναι μεγαλα σε ογκο>=10mb υπαρχει αλλο τροπος να μικρυνουν αλλα να εχουν διατηρησει τις μακροεντολες-vba

  34. Ο/Η vioannis λέει:

    Νίκο οι μακροεντολές (όταν δεν τρέχουν) είναι απλό κείμενο. Σε καμία περίπτωση δεν διογκώνουν ένα αρχείο.

  35. Ο/Η Nikos Gkikas λέει:

    Δεν ξερω γιατι μου το εκανε αυτο Γιαννη , το δοκιμασα σε ενα κανουργιο βιβλιο και ολα ειναι οκ .
    Ευχαριστω και παλι για την βοηθεια σου ..

Τα σχόλια είναι απενεργοποιημένα.