Συμπτώματα
Η γραμμή κύλισης μετακινείται συνεχώς ακόμη και μετά την κυκλοφορία του αριστερού κουμπιού του ποντικιού. Ο τύπος της γραμμής κύλισης δεν έχει καμία σχέση με αυτό το πρόβλημα, δηλαδή, το ίδιο πρόβλημα παρουσιάζεται ανεξάρτητα από το εάν η γραμμή κύλισης είναι τμήμα του παραθύρου ή είναι ένα στοιχείο ελέγχου γραμμής κύλισης.
Αιτία
Αυτό το πρόβλημα παρουσιάζεται συνήθως όταν εκτελείται ένας βρόχος ανάκτησης μηνύματος ως αποτέλεσμα των ενεργειών που έχουν ληφθεί για την κύλιση κατά τη λήψη ενός από τα μηνύματα ειδοποίησης της γραμμής κύλισης. Κατά την κύλιση, ένας εσωτερικός βρόχος ανάκτησης μηνυμάτων ξεκινά στα Windows. Η εργασία αυτού του βρόχου μηνύματος είναι να παρακολουθείτε την κύλιση και να στέλνετε τα κατάλληλα μηνύματα ειδοποίησης της γραμμής κύλισης, WM_HSCROLL και WM_VSCROLL. Η κύλιση τερματίζεται μετά τη λήψη του WM_LBUTTONUP. Εάν ξεκινήσει κάποιος άλλος βρόχος μηνύματος κατά την κύλιση, η WM_LBUTTONUP ανακτάται από αυτόν τον βρόχο μηνύματος και επειδή μια εφαρμογή δεν έχει πρόσβαση στον εσωτερικό βρόχο ανάκτησης μηνυμάτων της γραμμής κύλισης, δεν είναι δυνατή η σωστή αποστολή του WM_LBUTTONUP. Επομένως, το WM_LBUTTONUP δεν λαμβάνεται ποτέ από την εσωτερική Retriever μηνυμάτων και η κύλιση δεν τερματίζεται ποτέ. Η εφαρμογή που πραγματοποιεί κύλιση δεν χρειάζεται να ανακτήσει μηνύματα ρητά για να προκαλέσει αυτό το πρόβλημα. Η κλήση οποιασδήποτε από τις παρακάτω συναρτήσεις ή η επεξεργασία οποιουδήποτε μηνύματος που έχει ένα βρόχο ανάκτησης μηνύματος, κατά την κύλιση, μπορεί να προκαλέσει την απώλεια του WM_LBUTTONUP. Οι συναρτήσεις που παρατίθενται παρακάτω εμπίπτουν σε αυτή την κατηγορία:
DialogBox() DialogBoxIndirect() DialogBoxIndirectParam() DialogBoxParam() GetMessage() MessageBox() PeekMessage()
Επίλυση
Κατά την κύλιση, το μήνυμα WM_LBUTTONUP δεν πρέπει να ανακτάται από την ουρά με οποιονδήποτε βρόχο ανάκτησης μηνύματος εκτός από τον εσωτερικό της γραμμής κύλισης. Μια εφαρμογή μπορεί να συναντήσει αυτό το πρόβλημα ως εξής:
-
Μια εφαρμογή υλοποιεί ένα βρόχο ανάκτησης μηνυμάτων για την υλοποίηση επεξεργασίας φόντου, για παράδειγμα, την επεξεργασία φόντου κατά την εκτέλεση μιας χρονοβόρας βαφής.
-
Μια εφαρμογή υλοποιεί ένα βρόχο ανάκτησης μηνυμάτων για την υλοποίηση της επικοινωνίας με μια άλλη εφαρμογή ή DLL. Για παράδειγμα, για να κάνετε κύλιση, η εφαρμογή πρέπει να λαμβάνει δεδομένα από αλλού.
Πιθανές λύσεις
Παρακάτω παρατίθενται δύο πιθανές λύσεις. Η πρώτη λύση χρησιμοποιείται από πολλές εφαρμογές εξόδου και από τα Windows. Ωστόσο, σε σπάνιες περιπτώσεις, η πρώτη λύση μπορεί να μην είναι εφικτή. Σε αυτήν την περίπτωση, μπορεί να χρησιμοποιηθεί η δεύτερη λύση. Ωστόσο, εάν είναι δυνατό, προσπαθήστε να αποφύγετε την πλήρη εφαρμογή της ανάκτησης μηνυμάτων κατά την κύλιση.
-
Χρησιμοποιήστε την επεξεργασία με χρονομέτρηση-μήνυμα. Καταγράψτε την περίπλοκη επεξεργασία σε μικρότερες εργασίες και Παρακολουθήστε πού ξεκινά και τελειώνει κάθε εργασία και, στη συνέχεια, εκτελέστε κάθε εργασία με βάση ένα μήνυμα χρονιστή. Όταν ολοκληρωθούν όλα τα στοιχεία της επεξεργασίας, σκοτώστε το χρονόμετρο. Δείτε παρακάτω για ένα παράδειγμα αυτής της λύσης.
-
Εφαρμόστε έναν βρόχο ανάκτησης μηνυμάτων, αλλά βεβαιωθείτε ότι το WM_LBUTTONUP δεν ανακτάται από αυτό. Αυτό μπορεί να επιτευχθεί με τη χρήση φίλτρων. Δείτε παρακάτω για ορισμένα παραδείγματα αυτής της λύσης.
Παράδειγμα επίδειξης λύσης 1
Μια εφαρμογή έχει σύνθετη διαδικασία βαφής. Η κλήση του ScrollWindow (), για κύλιση, δημιουργεί μηνύματα ζωγραφικής. Η επεξεργασία φόντου πραγματοποιείται κατά τη ζωγραφική.
-
Όταν εμφανιστεί το μήνυμα WM_PAINT, κάντε τα εξής:
-
Call BeginPaint ().
-
Αντιγράψτε την ακυρωμένη ορθογώνια σε μια καθολική μεταβλητή ορθογωνίου (για παράδειγμα, grcPaint) που θα χρησιμοποιηθεί στο βήμα 2. Το καθολικό grcPaint θα ήταν μια Ένωση με την προηγουμένως αποκτηθείσα ορθογώνια (grcPaint) και τη νέα άκυρη ορθοορθογώνια (PS. rcPaint). Ο κωδικός για αυτό θα μοιάζει με το εξής:
RECT grcPaint; // Should be initialized before getting the // first paint message. : : UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);
-
Επικοινωνήστε με το ValidateRect () με το PS. rcPaint.
-
Call EndPaint ().
-
Ορίστε ένα χρονόμετρο.
Με αυτόν τον τρόπο, δεν δημιουργούνται περισσότερα WM_PAINT μηνύματα, επειδή δεν υπάρχουν περιοχές που δεν είναι έγκυρες και έχει ρυθμιστεί ένας χρονιστής, ο οποίος θα δημιουργήσει WM_TIMER μηνύματα.
-
-
Μετά τη λήψη ενός WM_TIMER μηνύματος, επιλέξτε την καθολική μεταβλητή ορθογώνια. Εάν δεν είναι κενό, πάρτε μια ενότητα και χρωματίστε την. Στη συνέχεια, προσαρμόστε την καθολική μεταβλητή ορθογώνιας ώστε να μην περιλαμβάνει πλέον την περιοχή που έχει χρωματιστεί.
-
Μόλις αδειάσει η καθολική μεταβλητή ορθογωνίου, τότε σκοτώστε το χρονόμετρο.
Παράδειγμα επίδειξης λύσης 2
Μια εφαρμογή πρέπει να αποκτήσει ορισμένα δεδομένα μέσω DDE ή κάποιου άλλου μηχανισμού από άλλη εφαρμογή, η οποία στη συνέχεια εμφανίζεται στο παράθυρο. Για να κάνετε κύλιση, η εφαρμογή πρέπει να ζητήσει και, στη συνέχεια, να αποκτήσει τα δεδομένα από μια εφαρμογή διακομιστή. Υπάρχουν τρία διαφορετικά φίλτρα που μπορούν να χρησιμοποιηθούν για τη ρύθμιση ενός PeekMessage () και τη λήψη των πληροφοριών. Τα φίλτρα μπορούν να ρυθμιστούν με χρήση των παραμέτρων uFilterFirst και uFilterLast του PeekMessage (). uFilterFirst καθορίζει το μήνυμα γροθιάς στην περιοχή προς έλεγχο και το uFilterLast καθορίζει το τελευταίο μήνυμα στην περιοχή προς έλεγχο.
-
Επιλέξτε και ανακτήσετε μόνο τα σχετικά μηνύματα για τη λήψη των απαιτούμενων δεδομένων.
-
Αναζητήστε WM_LBUTTONUP χωρίς να την καταργήσετε, επιλέξτε τη μορφή της ουράς. Εάν βρίσκεται στην ουρά, διαλυθείτε. Διαφορετικά, ανάκτηση και αποστολή όλων των μηνυμάτων.
-
Ανάκτηση όλων των μηνυμάτων που είναι μικρότερα από WM_LBUTTONUP και μεγαλύτερα από WM_LBUTTONUP, αλλά χωρίς ανάκτηση WM_LBUTTONUP.
Περισσότερες πληροφορίες
Βήματα για την αναπαραγωγή του ζητήματος
Ακολουθεί η ακολουθία των συμβάντων που οδηγούν στην απώλεια του μηνύματος WM_LBUTTONUP:
-
Κάντε κλικ στη γραμμή κύλισης χρησιμοποιώντας το ποντίκι.
-
Το βήμα 1 δημιουργεί ένα WM_NCLBUTTONDOWN μήνυμα.
-
Το βήμα 2 προκαλεί την έναρξη ενός εσωτερικού βρόχου μηνύματος των Windows. Αυτός ο βρόχος μηνύματος αναζητά μηνύματα που σχετίζονται με τη γραμμή κύλισης. Ο σκοπός αυτού του βρόχου μηνύματος είναι η δημιουργία κατάλληλων WM_HSCROLL ή WM_VSCROLL μηνυμάτων. Ο βρόχος μηνύματος και η κύλιση τερματίζονται μόλις ληφθεί το WM_LBUTTONUP.
-
Κατά τη λήψη του μηνύματος WM_HSCROLL ή WM_VSCROLL, η εφαρμογή λαμβάνει άμεσα έναν βρόχο ανάκτησης μηνύματος ή καλεί συναρτήσεις που έχουν ως αποτέλεσμα την ανάκτηση μηνυμάτων.
-
Το WM_LBUTTONUP καταργείται από την ουρά με το βρόχο μηνύματος που αναφέρεται στο βήμα 4. Στη συνέχεια, το WM_LBUTTONUP αποστέλλεται.
-
Ως αποτέλεσμα του βήματος 5, το μήνυμα WM_LBUTTONUP αποστέλλεται αλλού και ο εσωτερικός βρόχος ανάκτησης μηνυμάτων, που αναφέρεται στο βήμα 3, δεν το λαμβάνει ποτέ. Ο βρόχος μηνύματος στο βήμα 3 αναζητά το WM_LBUTTONUP για να διακόψετε την κύλιση. Επειδή δεν λαμβάνεται, η γραμμή κύλισης συνεχίζει να κινείται.