การใช้หน้าต่างปกติใน Delphi
สรุป ในไลบรารี VCL ของ Delphi เพื่อความสะดวกในการใช้งานและการใช้งานแอปพลิเคชันวัตถุแอปพลิเคชันสร้างหน้าต่างที่ซ่อนอยู่สำหรับการตอบสนองต่อการประมวลผลข้อความ มันเป็นหน้าต่างนี้ที่ทำให้โปรแกรมที่พัฒนาขึ้นด้วย VCL ดูเหมือนจะผิดรูปเช่นไม่สามารถจัดเรียงและกระเบื้องตามปกติกับหน้าต่างอื่น ๆ ผ่านการวิเคราะห์เชิงลึกของ VCL บทความนี้เป็นวิธีแก้ปัญหาที่สามารถแก้ปัญหาได้โดยการปรับเปลี่ยนรหัส 3 บรรทัดไปยังไฟล์โครงการแอปพลิเคชันโดยไม่มีการเปลี่ยนแปลงวิธีการเขียนโปรแกรมดั้งเดิม
คำหลัก VCL, หน้าต่างปกติ, การทำให้เป็นมาตรฐาน
1 บทนำ
แอปพลิเคชัน Windows ที่เขียนในไลบรารีคลาส VCL ที่จัดทำโดย Delphi มีคุณสมบัติที่แตกต่างซึ่งแตกต่างจากหน้าต่างมาตรฐานหน้าต่าง - เมนูระบบของหน้าต่างหลักนั้นแตกต่างจากเมนูระบบบนแถบงาน โดยทั่วไปเมนูระบบในหน้าต่างหลักมีรายการเมนูหกรายการในขณะที่เมนูระบบแถบงานมีเพียงสามรายการเมนู ในการใช้งานจริงเราพบว่าโปรแกรมที่พัฒนาขึ้นด้วย VCL มีความอับอายต่อไปนี้:
1) ไม่สวยพอ นี่คือแน่นอนถ้ามันไม่ตรงกับมาตรฐานมันจะปรากฏขึ้นตามธรรมชาติเล็กน้อย
2) ไม่มีเอฟเฟกต์ภาพเคลื่อนไหวเมื่อหน้าต่างหลักถูกย่อให้เล็กสุด
3) ไม่สามารถจัดหน้าต่างและกระเบื้องตามปกติกับหน้าต่างอื่น ๆ
4) เมนูระบบแถบงานมีความสำคัญสูงสุด ในการปรากฏตัวของหน้าต่างโมดอลโปรแกรมทั้งหมดยังสามารถย่อเล็กสุดซึ่งตรงกันข้ามกับการออกแบบหน้าต่างโมดอล
ปัญหาของการลดเอฟเฟกต์ภาพเคลื่อนไหวในหน้าต่างหลักได้รับการแก้ไขโดยฟังก์ชั่น showwinnoanimate ในรูปแบบ pas ในรุ่นหลังจาก Delphi 5.0 แต่ปัญหาที่เหลืออยู่มีอยู่เสมอ แม้ว่าสิ่งนี้จะไม่ส่งผลกระทบต่อการใช้งานในกรณีส่วนใหญ่ แต่ก็ไม่สามารถยอมรับได้ในบางสถานการณ์ที่มีการติดตามผลมืออาชีพ เนื่องจาก C ++ Builder และ Delphi ใช้ชุดไลบรารีคลาสเดียวกันปัญหาข้างต้นจึงมีอยู่ในแอปพลิเคชัน Windows ที่เขียนโดยใช้ C ++ Builder
ฉันได้พูดถึงปัญหานี้ในบทความก่อนหน้านี้ (สามารถพบได้ที่บ้านของ Forrest Gump) และการเล่าเรื่องในเวลานั้นดูเหมือนจะเป็นเคล็ดลับและฉันพบวิธีการนั้นโดยบังเอิญ งานของบทความนี้คือการวิเคราะห์ไลบรารีคลาส VCL เพื่ออธิบายหลักการของการทำสิ่งนี้จากนั้นให้วิธีการที่ใช้รหัส 3 บรรทัดเพียง 3 บรรทัดเพื่อแก้ปัญหาของ "หน้าต่างผิดปกติ" นี้อย่างสมบูรณ์ใน Delphi
2 หลักการ
2.1 กระบวนการสร้างแอปพลิเคชัน
นี่คือไฟล์โครงการ Delphi แอปพลิเคชันทั่วไป
โครงการ โครงการ 1;
ใช้
แบบฟอร์ม
UNIT1 ใน 'UNIT1.PAS' {Form1};
{$ r *.res}
เริ่ม
Application.initialize;
application.createform (tform1, form1);
Application.run;
จบ .
หน้าต่างที่ซ่อนอยู่ถูกสร้างขึ้นโดยวัตถุแอปพลิเคชันดังนั้นวัตถุแอปพลิเคชันมาจากไหน? กด Ctrl ค้างไว้ในหน้าต่างการแก้ไขรหัสของ Delphi และคลิกแอปพลิเคชันคุณจะพบว่าวัตถุแอปพลิเคชันเป็นหนึ่งในวัตถุส่วนกลางหลายอย่างที่กำหนดไว้ในหน่วยฟอร์ม PAS สิ่งนี้ไม่เพียงพอสิ่งที่เราต้องการทราบคือจุดที่วัตถุแอปพลิเคชันถูกสร้างขึ้นเนื่องจากอินสแตนซ์ของคลาส tapplication จะต้องสร้างสำเร็จก่อนที่เราจะสามารถอ้างอิงได้
ลองคิดดูมีรหัสใดที่จะดำเนินการก่อนแอปพลิเคชันเริ่มต้นหรือไม่? โดยวิธีการคือรหัสในส่วนรหัสเริ่มต้น หลังจากการดีบักซอร์สโค้ด VCL อย่างรอบคอบคุณสามารถรู้ได้ว่าหลายหน่วยใน VCL มีส่วนรหัสเริ่มต้น การเริ่มต้นการเริ่มต้นทั้งหมด
การค้นหาในไดเรกทอรีซอร์สซอร์ส VCL ด้วยคำหลัก "tapplication.create" เราพบรหัสเพื่อสร้างวัตถุแอปพลิเคชันในหน่วยควบคุมหน่วย ในส่วนรหัสการเริ่มต้นของหน่วยควบคุม PAS มีการเรียกใช้ขั้นตอนการเริ่มต้นและการใช้งาน initControls มีดังนี้:
การควบคุม หน่วย ;
-
การเริ่มต้น
-
initControls;
ขั้นตอน initControls;
เริ่ม
-
เมาส์: = tmouse.create;
หน้าจอ: = tscreen.create ( ไม่มี );
แอปพลิเคชัน: = tapplication.create ( ไม่มี );
-
จบ ;
ตกลง ณ จุดนี้การวิเคราะห์ของเราได้เสร็จสิ้นขั้นตอนแรกเนื่องจากการแก้ปัญหาของหน้าต่างที่ผิดปกติเราต้องทำสิ่งหนึ่งก่อนที่จะเริ่มต้นวัตถุแอปพลิเคชันดังนั้นจึงเป็นเรื่องสำคัญมากที่จะต้องเข้าใจกระบวนการเริ่มต้นของแอปพลิเคชัน
2.2 ตัวแปร iSlibrary
ตัวแปร ISLIBRARY เป็นหนึ่งในตัวแปรธงทั่วโลกที่กำหนดไว้ใน System.PAS Unit หากค่าของ ISLIBRARY เป็นจริงหมายความว่าโมดูลโปรแกรมเป็นไลบรารีลิงก์แบบไดนามิกมิฉะนั้นจะเป็นโปรแกรมที่เรียกใช้งานได้ กระบวนการบางอย่างในไลบรารีคลาส VCL เสร็จสิ้นการกระทำที่แตกต่างกันตามค่าที่แตกต่างกันของตัวแปรตั้งค่าสถานะนี้ นั่นคือตัวแปรนี้มีบทบาทสำคัญในการแก้ปัญหาหน้าต่างผิดปกติของ Delphi
ดังที่ได้กล่าวไว้ก่อนหน้านี้เพื่อความสะดวกหน้าต่างที่มองไม่เห็นถูกสร้างขึ้นเมื่อวัตถุแอปพลิเคชันเริ่มต้น (นั่นคือหน้าต่างที่มี "tapplication" เป็นชื่อคลาสที่เห็นด้วยเครื่องมือเช่น Spy ++) แต่ก็เป็นเพราะหน้าต่างนี้มองไม่เห็น โปรแกรมที่พัฒนาขึ้นด้วย Delphi แสดงความผิดปกติมากมาย ตกลงถ้าเราสามารถลบหน้าต่างที่มองไม่เห็นนี้ (และลบเมนูระบบแถบงานในเวลาเดียวกัน) และแทนที่ด้วยหน้าต่างหลักแอปพลิเคชันของเราจะไม่แก้ไขปัญหาทั้งหมดหรือไม่?
มันง่ายที่จะพูด แต่จำเป็นต้องมีการผ่าตัดที่สำคัญเพื่อใช้ซอร์สโค้ด VCL หรือไม่ นั่นจะไม่เป็นการวางเกวียนไว้ก่อนม้าหรือ? แน่นอนคำตอบคือไม่มิฉะนั้นบทความนี้จะไม่สามารถใช้ได้ สิ่งที่ฉันต้องการจะพูดที่นี่คือในการวิเคราะห์ครั้งต่อไปเราจะเห็นว่าสิ่งที่เรียกว่า "วิธีการเขียนโปรแกรมอยู่ในใจเดียว" การฝึกการปลูกวิลโลว์ที่ไม่ได้ตั้งใจในการออกแบบ tapplication ทำให้เราแก้ปัญหานี้ได้จริง . หากคุณไม่ทำการวิเคราะห์ซอร์สโค้ดคุณอาจต้องเดินไปรอบ ๆ เป็นวงกลม แต่ในความเป็นจริงเราจะเห็นว่าการออกแบบอัจฉริยะทำให้เราไม่มากหรือน้อยก็ถูกต้อง
เปิดตัวสร้างตัวสร้างของคลาส tapplication และเราจะพบบรรทัดของรหัส
constructor tapplication.create (aowner: tComponent);
เริ่ม
-
ถ้า ไม่ใช่ Islibrary ให้ CreateHandle;
-
จบ ;
สิ่งที่กล่าวไว้ที่นี่คือหากโมดูลโปรแกรมไม่ใช่ไลบรารีลิงก์แบบไดนามิกให้ดำเนินการ CreateHandle และงานที่ทำโดย CreateHandle มีดังนี้ในความช่วยเหลือ: "หากไม่มีหน้าต่างแอปพลิเคชันให้สร้างโปรแกรมแอปพลิเคชัน", ที่นี่ " หน้าต่าง "เป็นหน้าต่างที่มองไม่เห็นที่กล่าวถึงข้างต้นซึ่งเป็นผู้กระทำผิดในคลาส tapplication ตัวแปร fhandle ใช้เพื่อบันทึกที่จับหน้าต่าง นี่คือการดำเนินการที่แตกต่างกันตามค่าของ ISLIBRARY เนื่องจากในไลบรารีลิงก์แบบไดนามิกโดยทั่วไปจะไม่จำเป็นต้องใช้ลูปข้อความ แต่ใช้วัตถุแอปพลิเคชันเพื่อพัฒนาไลบรารีลิงก์แบบไดนามิกด้วย VCL ดังนั้นนี่คือการออกแบบ ตกลงเราเพียงแค่ต้องหลอกวัตถุแอปพลิเคชันกำหนด Islibrary ให้เป็นจริงก่อนที่มันจะถูกสร้างขึ้นและกรองการดำเนินการของ CreateHandle และลบหน้าต่างที่น่ารำคาญนี้
รหัสที่กำหนดให้กับ ISLIBRARY ควรวางไว้อย่างชัดเจนในส่วนรหัสเริ่มต้นของหน่วยบางหน่วย วัตถุแอปพลิเคชันถูกสร้างขึ้นในไฟล์โครงการเราต้องวางหน่วยที่มีรหัสการกำหนดก่อนหน่วยฟอร์มดังต่อไปนี้ (สมมติว่าหน่วยมีชื่อว่า untdllexe.pas):
เทมเพลต โปรแกรม
ใช้
Unitdllexe ใน 'Unitdllexe.pas'
แบบฟอร์ม
formmain ใน 'formmain.pas' {mainform}
-
รายการรหัส Unitdllexe.pas มีดังนี้:
หน่วย Unitdllexe;
ส่วนต่อประสาน
การดำเนินการ
การเริ่มต้น
islibrary: = true;
// บอกวัตถุ Applciation ว่านี่เป็นไลบรารีลิงก์แบบไดนามิกและไม่จำเป็นต้องสร้างหน้าต่างที่ซ่อนอยู่
จบ .
โอเครวบรวมและเรียกใช้ Windows. แต่ปัญหาคือไม่สามารถย่อหน้าต่างได้ เกิดอะไรขึ้น? มันยังคงเป็นวิธีเก่าติดตามมัน
2.3 การย่อขนาดหน้าต่างหลัก
การย่อขนาดเป็นของคำสั่งระบบและในที่สุดมันจะต้องเรียกว่าฟังก์ชั่น API defwindowProc เพื่อลดหน้าต่างดังนั้นเราจึงพบฟังก์ชั่น wmsyscommand ใน tcustomform ที่ตอบสนองต่อข้อความ WM_SyScommand โดยไม่มีปัญหาใด ๆ .wndproc เพื่อจัดการ:
ขั้นตอน tcustomform.wmsyscommand (ข้อความ var : twmsyscommand);
เริ่ม
ด้วย ข้อความ ทำ
เริ่ม
if (cmdType และ $ fff0 = sc_minimize) และ (application.mainform = self) จากนั้น
Application.wndproc (tmessage (ข้อความ))
-
จบ ;
จบ ;
ในแอปพลิเคชัน WNDPROC วิธีการลดขนาดของแอปพลิเคชันจะเรียกว่าการตอบสนองต่อข้อความย่อเล็กสุดดังนั้นปัญหาของปัญหาจะต้องอยู่ในกระบวนการย่อ
procedure tapplication.wndproc (ข้อความ var : tmessage);
-
เริ่ม
-
ด้วย ข้อความ ทำ
CASE MSG ของ
WM_SYSCOMMAND:
กรณี WPARAM และ $ FFF0 ของ
SC_MINIMIZE: ย่อเล็กสุด;
SC_RESTORE: กู้คืน;
อื่น
ค่าเริ่มต้น;
-
จบ ;
สุดท้ายค้นหา tapplication.minimize และคุณจะเข้าใจทุกอย่าง การโทรไปยังฟังก์ชั่น defwindowProc ที่นี่ไม่ได้ให้เอฟเฟกต์ใด ๆ ทำไม? เนื่องจากเราหลอกลวงวัตถุแอปพลิเคชันมาก่อนให้กรองการเรียกของ CreateHandle และไม่ได้สร้างหน้าต่างที่จำเป็นในการตอบสนองต่อข้อความของวัตถุแอปพลิเคชันการจัดการ fhandle คือ 0 และการโทรไม่ประสบความสำเร็จแน่นอน หากคุณสามารถชี้ไปที่หน้าต่างแอปพลิเคชันหลักของเรามันจะแก้ปัญหาได้
Procedure tapplication.minimize;
เริ่ม
-
defwindowProc (fhandle, wm_syscommand, sc_minimize, 0);
// ค่า fhandle ที่นี่คือ 0
-
จบ ;
3 การดำเนินการ
การออกแบบอัจฉริยะของบอร์แลนด์โดยไม่ได้ตั้งใจทำให้เราสามารถแก้ปัญหาได้อีกครั้ง จากการวิเคราะห์ก่อนหน้านี้เรารู้ว่าในไลบรารีลิงก์แบบไดนามิกที่พัฒนาขึ้นด้วย VCL ไม่มีหน้าต่างที่ซ่อนอยู่เพื่อรับข้อความ Windows (CreateHandle ไม่ได้ดำเนินการ) แต่ในไลบรารีลิงก์แบบไดนามิกหากคุณต้องการแสดงหน้าต่างคุณต้องการ หน้าต่างหลัก วิธีแก้ปัญหานี้? VCL Designer ออกแบบตัวแปร fhandle ที่เก็บด้ามจับหน้าต่างที่มองไม่เห็นเป็นงานเขียนได้ดังนั้นเราจึงสามารถกำหนดค่าให้กับ Fhandle เพื่อให้หน้าต่างแม่สำหรับหน้าต่างเด็กที่ต้องแสดง ตัวอย่างเช่นในปลั๊กอินไลบรารีลิงก์แบบไดนามิกเพื่อแสดงแบบฟอร์มเรามักจะผ่านที่จับของวัตถุแอปพลิเคชันผ่านฟังก์ชั่นของไลบรารีลิงก์แบบไดนามิกในไฟล์ปฏิบัติการโมดูลหลักและกำหนดให้กับแอปพลิเคชัน Link Library ในไฟล์ปฏิบัติการหลักและกำหนดให้กับ Application.handle ของไลบรารีลิงก์แบบไดนามิกในแอปพลิเคชัน
ขั้นตอน setApplicationHandle (MainAppWnd: HWND)
เริ่ม
application.handle: = mainappwnd;
จบ ;
ตกลงเนื่องจาก Application.handle เป็นเพียงการจัดการหน้าต่างที่ใช้ภายในเพื่อตอบสนองต่อข้อความและหน้าต่างที่มองไม่เห็นที่ควรสร้างขึ้นนั้นถูกลบออกโดยเรา มันเพียงพอที่จะซ่อนที่จับของหน้าต่างที่ไม่จำเป็น แต่เดิม? ฉันจะหาหน้าต่างดังกล่าวได้ที่ไหน หน้าต่างหลักของแอปพลิเคชันเป็นตัวเลือกที่ดีที่สุดดังนั้นรหัสต่อไปนี้จึงพร้อมใช้งาน
เทมเพลต โปรแกรม
ใช้
Unitdllexe ใน 'Unitdllexe.pas'
แบบฟอร์ม
formmain ใน 'formmain.pas' {mainform};
{$ r *.res}
เริ่ม
Application.initialize;
application.createform (tformmain, formmain);
application.handle: = formmain.handle;
Application.run;
จบ .
ดังนั้นปัญหาทั้งหมดได้รับการแก้ไข คุณไม่จำเป็นต้องทำการปรับเปลี่ยนซอร์สโค้ด VCL และคุณไม่จำเป็นต้องทำการปรับเปลี่ยนโปรแกรมดั้งเดิม จากรหัสสามบรรทัดเพื่อให้หน้าต่างแอปพลิเคชันของคุณเป็นปกติเหมือนหน้าต่างหน้าต่างมาตรฐานใด ๆ
1) แถบงานและแถบชื่อหน้าต่างมีเมนูระบบที่สอดคล้องกัน
2) มีเอฟเฟกต์ภาพเคลื่อนไหวเมื่อหน้าต่างหลักถูกย่อให้เล็กสุด
3) หน้าต่างสามารถจัดและเรียงต่อกันตามปกติกับหน้าต่างอื่น ๆ
4) เมื่อมีหน้าต่างแบบโมดอลมันไม่สามารถทำงานบนหน้าต่างหลักได้
รหัสการใช้งานข้างต้นใช้ใน Delphi ทุกรุ่น