อาการ
แถบเลื่อนจะเลื่อนอย่างต่อเนื่องแม้หลังจากที่คุณปล่อยปุ่มเมาส์ด้านซ้าย ชนิดของแถบเลื่อนไม่เกี่ยวข้องกับปัญหานี้นั่นคือปัญหาเดียวกันจะเกิดขึ้นโดยไม่คำนึงถึงว่าแถบเลื่อนเป็นส่วนหนึ่งของหน้าต่างหรือเป็นตัวควบคุมแถบเลื่อน
สาเหตุ
ปัญหานี้เกิดขึ้นโดยปกติเมื่อมีการวนรอบการเรียกข้อความเป็นผลลัพธ์ของการดำเนินการที่ใช้สำหรับการเลื่อนเมื่อได้รับข้อความแจ้งเตือนแถบเลื่อนหนึ่งรายการ เมื่อเลื่อนการวนรอบการเรียกข้อความภายในเริ่มต้นใน Windows งานของการวนรอบข้อความนี้คือการติดตามการเลื่อนและการส่งข้อความการแจ้งเตือนของแถบเลื่อนที่เหมาะสม WM_HSCROLL และ WM_VSCROLL การเลื่อนจะสิ้นสุดเมื่อ WM_LBUTTONUP ได้รับ ถ้าการวนรอบข้อความอื่นเริ่มการทำงานในระหว่างการเลื่อน WM_LBUTTONUP จะถูกดึงมาจากการวนรอบข้อความนั้นและเนื่องจากแอปพลิเคชันไม่มีการเข้าถึงการวนรอบการเรียกข้อความภายในของแถบเลื่อน WM_LBUTTONUP ไม่สามารถส่งได้อย่างถูกต้อง ดังนั้น WM_LBUTTONUP ไม่เคยได้รับโดยที่ไม่ได้รับข้อความภายในและการเลื่อนจะไม่สิ้นสุดลง แอปพลิเคชันที่เลื่อนไม่จำเป็นต้องเรียกข้อความให้ทำให้เกิดปัญหานี้อย่างชัดเจน การโทรไปยังฟังก์ชันใดฟังก์ชันหนึ่งต่อไปนี้หรือการประมวลผลข้อความใดๆที่มีการวนรอบการเรียกใช้ข้อความในขณะที่เลื่อนอาจทำให้ WM_LBUTTONUP สูญหายได้ ฟังก์ชันที่แสดงรายการอยู่ด้านล่างจะตกอยู่ในประเภทนี้:
DialogBox() DialogBoxIndirect() DialogBoxIndirectParam() DialogBoxParam() GetMessage() MessageBox() PeekMessage()
การแก้ไข
ในขณะที่เลื่อนข้อความ WM_LBUTTONUP ไม่ควรถูกดึงมาจากคิวโดยการวนรอบการเรียกใช้ข้อความอื่นนอกเหนือจากแถบเลื่อนภายในของแถบเลื่อน แอปพลิเคชันอาจพบปัญหานี้ต่อไปนี้:
-
แอปพลิเคชันจะดำเนินการวนรอบการรับข้อความเพื่อนำการประมวลผลพื้นหลังไปใช้ตัวอย่างเช่นการประมวลผลเบื้องหลังขณะที่ดำเนินการสีที่ใช้เวลานาน
-
แอปพลิเคชันจะดำเนินการวนรอบการเรียกใช้ข้อความเพื่อนำการสื่อสารกับแอปพลิเคชันอื่นหรือ DLL ตัวอย่างเช่นเมื่อต้องการเลื่อนแอปพลิเคชันจำเป็นต้องได้รับข้อมูลจากที่อื่น
วิธีแก้ไขปัญหาที่เป็นไปได้
การแก้ไขปัญหาสองวิธีที่เป็นไปได้จะแสดงรายการด้านล่าง วิธีแก้ไขปัญหาครั้งแรกจะถูกใช้โดยการออกจากแอปพลิเคชันต่างๆและ Windows อย่างไรก็ตามภายใต้สถานการณ์ที่ไม่ค่อยมีวิธีแก้ไขปัญหาครั้งแรกอาจไม่สามารถใช้งานได้อย่างถูกต้อง ในกรณีนี้อาจมีการใช้วิธีแก้ไขปัญหาที่สอง อย่างไรก็ตามถ้าเป็นไปได้โปรดลองหลีกเลี่ยงการใช้การเรียกใช้ข้อความทั้งหมดในขณะที่เลื่อน
-
ใช้ตัวจับเวลา-การประมวลผลที่ยึดตามข้อความ แบ่งการประมวลผลที่ซับซ้อนเป็นงานที่มีขนาดเล็กลงและติดตามตำแหน่งที่แต่ละงานเริ่มต้นและสิ้นสุดแล้วดำเนินการแต่ละงานโดยยึดตามข้อความตัวจับเวลา เมื่อคอมโพเนนต์ทั้งหมดของการประมวลผลเสร็จสมบูรณ์แล้วให้ฆ่าตัวจับเวลา ดูตัวอย่างการแก้ไขปัญหาชั่วคราวด้านล่างนี้
-
ใช้การวนรอบการเรียกใช้ข้อความแต่ตรวจสอบให้แน่ใจว่า WM_LBUTTONUP ไม่ได้รับการเรียกใช้ การทำเช่นนี้สามารถทำได้โดยใช้ตัวกรอง ดูตัวอย่างการแก้ไขปัญหาชั่วคราวด้านล่างนี้
ตัวอย่างการแก้ไขปัญหาชั่วคราว1
แอปพลิเคชันมีกระบวนการสีที่ซับซ้อน การโทร ScrollWindow () เมื่อต้องการเลื่อนให้สร้างข้อความสี การประมวลผลพื้นหลังจะเกิดขึ้นในขณะที่การวาด
-
เมื่อคุณได้รับข้อความแสดงข้อ WM_PAINT ให้ทำดังต่อไปนี้:
-
โทร BeginPaint ()
-
คัดลอก rect การทำให้เป็นตัวแปร rect ส่วนกลาง (ตัวอย่างเช่น grcPaint) ที่จะใช้ในขั้นตอนที่2 ส่วนกลาง rect grcPaint จะเป็นสหภาพของ rect ที่ได้รับก่อนหน้านี้ (grcPaint) และใหม่ rect (ps. rcPaint) โค้ดสำหรับสิ่งนี้จะมีลักษณะดังต่อไปนี้:
RECT grcPaint; // Should be initialized before getting the // first paint message. : : UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);
-
โทร ValidateRect () ด้วย rcPaint
-
โทร EndPaint ()
-
ตั้งค่าตัวจับเวลา
วิธีนี้จะไม่มีการสร้างข้อความ WM_PAINT เพิ่มเติมเนื่องจากไม่มีขอบเขตที่ไม่ถูกต้องและตัวจับเวลาจะถูกตั้งค่าซึ่งจะสร้างข้อความ WM_TIMER
-
-
เมื่อได้รับข้อความ WM_TIMER ให้ตรวจสอบตัวแปร rect ส่วนกลาง ถ้าไม่ว่างให้ใช้ส่วนและระบายสี จากนั้นปรับตัวแปร rect ส่วนกลางดังนั้นจึงไม่มีขอบเขตการทาสีอีกต่อไป
-
เมื่อตัวแปร rect ส่วนกลางว่างเปล่าแล้วฆ่าตัวจับเวลา
ตัวอย่างที่สาธิตการแก้ไขปัญหา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 เพื่อหยุดการเลื่อน เนื่องจากไม่ได้รับการเลื่อนแถบเลื่อนจะยังคงอยู่