Quan điểm lập trình

Chia sẻ: Hoang Nhan | Ngày: | Loại File: PDF | Số trang:0

0
95
lượt xem
53
download

Quan điểm lập trình

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Thế là bạn nghĩ rằng lập trình là một thế giới vô cùng thú vị, và bạn muốn tham gia vào thế giới ấy? Trước khi bạn bắt đầu, điều duy nhất mà tôi muốn khuyên là: nếu bạn thực sự yêu thích lập trình thì đó rõ ràng là công việc tốt nhất mà bạn có thể có được.

Chủ đề:
Lưu

Nội dung Text: Quan điểm lập trình

  1. Như vậy là bạn muốn trở thành một lập trình viên? Việt Thanh Tổng hợp từ Internet Giới thiệu Bạn cần gì để trở thành một lập Thế là bạn nghĩ rằng lập trình trình viên? là một thế giới vô cùng thú vị, và Tôi không nghĩ rằng có một vài Không bao giờ sợ phải bạn muốn tham gia vào thế giới ấy? yêu cầu khó khăn nào đó khiến bạn bắt đầu. Trước khi bạn bắt đầu, điều duy không thể trở thành lập trình viên, nhất mà tôi muốn khuyên là: nếu tôi chỉ đơn giản nghĩ rằng bất cứ Tôi sẽ không viết hai lần bạn thực sự yêu thích lập trình thì ai có một ít (hay rất nhiều) mong cùng một đoạn mã giống đó rõ ràng là công việc tốt nhất mà muốn đều có thể trở thành lập trình nhau. bạn có thể có được. Ngược lại, nếu viên. Vấn đề chỉ là bạn dành ra bao bạn chỉ cảm thấy thích, hay không nhiêu thời gian. Điều đó có nghĩa Khi phát triển phần mềm, quan tâm lắm đến lập trình, thì đó là tôi nghĩ có nhiều quan niệm sai hãy nghĩ đến tương lai. rõ ràng là công việc tồi tệ nhất của lầm về những kỹ năng cần có để Viết mã càng ít bao nhiêu, bạn. Bởi vì bạn đang gia nhập vào trở thành lập trình viên. Trước tiên, mắc lỗi càng ít bấy nhiêu. một thế giới mà sự cạnh tranh luôn bạn không cần phải thật xuất sắc là nỗi ám ảnh không thể tránh khỏi. trong môn Toán, bạn chỉ cần có Bạn sẽ không bao giờ trở Phát triển phần mềm gần như là khả năng hiểu được những điều cơ thành một lập trình viên một cuộc đua tranh. Trong đó, cuộc bản. Dĩ nhiên là có những ngoại giỏi nếu chỉ tập luyện 2 sống của bạn là một con đường và lệ, nếu bạn có hứng thú trong lĩnh giờ mỗi ngày. bạn phải chạy càng nhanh càng tốt, vực đồ họa hay lập trình game thì không cần biết dưới chân có gì, một kiến thức Toán vững vàng sẽ Tất cả các công việc đều cho đến khi gặp đồng bằng hoặc là giúp bạn rất nhiều. Một quan niệm có phần thú vị và phần đụng phải vách đá cheo leo. Nếu sai lầm khác là bạn cần phải là buồn chán, không có bạn sẩy chân, mọi thứ kết thúc, và thiên tài logic. Nói chung, điều đó ngoại lệ. đó hoàn toàn là lỗi của bạn. Nghe không phải là bắt buộc, dĩ nhiên có vẻ hơi ghê gớm đúng không? tư duy logic càng tốt thì càng dễ Kẻ thù số một của các Nhưng đừng để những điều đó làm dàng hơn khi tiếp cận thế giới lập lập trình viên là gì? Kiêu bạn nản lòng. Tôi chỉ không muốn trình. Vậy thì kỹ năng nào là cần căng. vẽ nên một viễn cảnh tươi đẹp, thiết? Bị thúc đẩy bởi những thách nơi có những cánh đồng xanh ngút thức là yếu tố quan trọng nhất. Đơn Lập trình viên sử dụng ngàn và những đám mây lững lờ giản là vì bạn đang tham gia vào hầu hết thời gian của trôi trên nền trời xanh thẳm. Thực một trò chơi trong đó thách thức mình vào việc sửa lỗi. tế là có thể chỉ vài phút sau đó trời xuất hiện trong mọi ngõ ngách. Chương trình càng dễ đọc sẽ mưa và bạn thì chẳng mang theo Một điều quan trọng khác là phải bao nhiêu càng tiết kiệm dù. Thế nhưng, chính những điều không ngừng theo đuổi mục tiêu, thời gian bấy nhiêu. không chắc chắn, những thách thức nhưng vẫn phải luôn uyển chuyển và áp lực sẽ làm cho cuộc sống trở để không đuổi theo một cách mù Trường học khiến các nên đầy hứng thú. quáng những mục tiêu xa vời. bạn tin rằng chương trình Bạn vẫn còn đọc đến đây ư? của bạn chỉ cần thỏa mãn Rất tốt, thế có nghĩa là bạn hoàn Còn trường học thì sao? một mình bạn là đủ. Điều toàn nghiêm túc về điều này. Bây Trường học là nơi tuyệt vời để này hoàn toàn sai lầm. giờ điều tôi sẽ nói với bạn là một học mọi thứ ngoại trừ công nghệ. Chương trình phải thỏa bản phác thảo về những gì đang Đừng cho là tôi sai, tôi không nói mãn khách hàng và các chờ đợi bạn trong thế giới lập trình, rằng tôi nghĩ trường học là không lập trình viên khác. chúng ta sẽ nói một ít về kỹ thuật quan trọng. Ngược lại, tôi nghĩ và cả những niềm vui của thế giới trường học là rất quan trọng, nhưng ấy. không phải để học lập trình. Những 3
  2. gì bạn nên tập trung thật sự ở trường là học quyển sách đó đề cập chính là ngôn ngữ cách để làm việc với những người khác trong bạn nên học đầu tiên. Bây giờ hãy chọn một đề án. Cũng như học cách những người thêm vài quyển sách về ngôn ngữ đó, mỗi xung quanh giải quyết vấn đề và cách thức quyển, bạn hãy đọc một phần chương đầu giải quyết của họ khác cách của bạn ở chỗ tiên, bạn có cảm thấy quan tâm đến nó nào. Trường học thường bắt bạn phải làm không? Nếu không, hãy bỏ quyển sách ấy những thứ có thể bạn không thích. Chẳng và chọn một quyển khác; nếu có, hãy lật hạn, tôi nhớ lúc tôi học môn “Thiết kế trình đến giữa quyển sách và một phần chương biên dịch”, tôi tự nhủ: “Thật là mất thời gian mà bạn bắt gặp, vẫn cảm thấy quan tâm một cách vô ích, tôi chẳng bao giờ cần phải đến quyển sách ấy đúng không? Tốt, đó là thiết kế trình biên dịch làm gì”. Nhưng, điều quyển sách có thể bạn sẽ chọn. Đừng cố tôi đã học được là làm thế nào để giải quyết hiểu nó viết cái gì, chỉ cần tìm hiểu xem nó những vấn đề hoàn toàn khác nhau, và kiến có mang đến cho bạn sự quan tâm về ngôn thức này giúp tôi làm được nhiều việc khác. ngữ đó hay không. Tiếp tục phương pháp Một trong những thuận lợi bạn có được này cho đến khi không còn quyển sách nào từ trường học là bạn có thể gặp gỡ bạn bè có cả, bạn có thể tìm được quyển sách gây cùng chí hướng và có thể sau này trở thành cho bạn nhiều hứng thú nhất để học ngôn đồng nghiệp của bạn. Ngành công nghiệp ngữ đó. phần mềm ở nhiều khía cạnh rất giống với ngành công nghiệp điện ảnh, khi có ai đó bị Những công cụ cần thiết lôi cuốn vào một đề án đầy tham vọng, họ Hãy nhìn thẳng vào vấn đề, chọn đúng thường mời bạn bè cùng hợp tác. Nếu bạn công cụ sẽ làm cho công việc trở nên dễ không biết họ từ trước, bạn sẽ không thể mời dàng hơn. Điều này càng chính xác hơn (hay thuê), và trong nhiều trường hợp, trường trong lĩnh vực phát triển phần mềm. Có thể học chính là nơi bạn có thể tìm được những Microsoft đã tạo ra môi trường phát triển người có cùng sở thích. Một khía cạnh khác tốt nhất, Microsoft Developers Studio. Do không thể bỏ qua là trường học không chỉ đó, nếu bạn dùng C/C++, Visual Basic,… dạy về kỹ thuật mà còn dạy về lịch sử, về tâm thì có lẽ đây sẽ là thứ bạn cần. Tuy nhiên, lý,… Và trong khi những thứ ấy có vẻ không vẫn có nhiều công cụ thay thế miễn phí liên quan trực tiếp đến lập trình, bạn có thể sẽ khác cho những ngôn ngữ này. Bạn có thể rất ngạc nhiên nếu biết rằng đó cũng là một kiểm tra thử nếu thích. trong những nguồn cảm hứng mà tôi từng có. Một công cụ khác cũng rất quan trọng, đó là trình soạn thảo mã lệnh (code Tôi nên bắt đầu từ đâu? editor). DevStudio có một trình soạn thảo Trước tiên, tôi khuyên là bạn nên cân mã lệnh tích hợp sẵn, và đó là một trong nhắc cẩn thận trước khi có một quyết định những lý do khiến nhiều người dùng nó. quan trọng. Như tôi đã nói, thế giới lập trình Cá nhân tôi không thích bị ràng buộc bởi có thể rất lý thú, nhưng cũng đầy gian nan. một môi trường phát triển nào. Do đó, tôi Do đó, đừng bao giờ nhảy bổ vào mà không thích dùng công cụ soạn thảo MultiEdit suy nghĩ kỹ. Việc đầu tiên cần làm dĩ nhiên là (http://www.analogx.com/cgi-bin/cgirdir. tìm mua một cuốn sách dạy lập trình. Nhưng exe?http://www.multiedit.com/). Tôi đã sử có quá nhiều sách và quá nhiều ngôn ngữ. Tôi dụng nó trong nhiều năm. Và tôi rất tự hào khuyên bạn nên chọn một trong các ngôn ngữ khuyên những ai muốn tìm một công cụ sau: C, C++, Visual Basic, Pascal (Delphi) thay thế cho DevStudio hãy dùng nó. hay Java. Khoan hãy nghĩ đến những ngôn ngữ khác, bởi vì chúng hoặc là quá phức Hãy là người lạc quan tạp cho người mới bắt đầu hoặc là quá đơn Tôi từng nghe người ta nói rằng kẻ lạc giản để có thể đưa bạn vào thế giới lập trình. quan nhất trên thế giới chính là nhà phát Nhưng dù thế nào thì bạn cũng nên chọn một triển phần mềm. Trong suy nghĩ của họ, ngôn ngữ vào thời điểm này. Những ngôn không có phần mềm nào là không thể viết ngữ này rất giống nhau, và vô cùng mạnh mẽ. được. Một ví dụ nhỏ, bạn hãy vào thử một Hầu như mọi ứng dụng thương mại đều có site download phần mềm nào đó mà xem. thể được viết bởi một trong những ngôn ngữ Có hàng trăm hàng ngàn phần mềm bao trên. Phương pháp của tôi là chọn 2 quyển gồm mọi lĩnh vực. Làm thế nào mà người sách cho mỗi ngôn ngữ đã nêu ở trên. Đọc sơ ta có thể sáng tạo ra từng ấy phần mềm. qua trước, và chú ý các ví dụ, mã nguồn trong Chúng nhiều và tốt đến nỗi bạn không thể đó. Sau khi đã đọc sơ qua tất cả các quyển nghĩ ra nên sáng tạo thêm phần mềm nào. sách đã chọn, hãy chọn quyển sách gây cho Thế nhưng từng ngày từng giờ, các nhà 4 bạn nhiều hứng thú nhất. Và ngôn ngữ mà
  3. phát triển phần mềm luôn sáng tạo và cho ra nhiều Rapid Development phần mềm mới hơn nữa, những phần mềm mà đã có Quyển sách này hướng đến việc lập kế hoạch cho thời người ta cho là không thể tạo ra được. Dù sao thì một dự án, tập trung vào những lỗi tiềm ẩn có thể mắc lạc quan mấy cũng phải có giới hạn. Mấu chốt của vấn phải,… Đây là quyển sách cho bạn biết thế giới thực đề là họ không nhìn mọi thứ một cách tổng thể, mà sự của ngành phát triển phần mềm. ở từng phần cụ thể. Ở một chừng mực nào đó, có thể ISBN: 1-55615-900-5 xem đấy là đặc trưng của ngành thiết kế phần mềm, chia dự án ra thành những phần nhỏ và giải quyết Dynamics of Software Development từng phần. Nếu bạn không phân phối thời gian hợp lý, Quyển sách này có một hướng tiếp cận khác, tập bạn sẽ không thể nào hoàn thành công việc. Khi bạn trung vào việc làm việc theo nhóm và động lực của bắt đầu viết chương trình “thực sự” đầu tiên (nghĩa là việc lập trình. Đây là điều thỉnh thoảng bị xem nhẹ, và chương trình có thể thực hiện được một công việc nào hậu quả có thể được thấy trong nhiều dự án bị thất bại. đó cần thiết cho mọi người, không phải cho riêng bạn), ISBN: 1-55615-823-8 phải chắc chắn rằng bạn dành đủ thời gian để vạch ra kế hoạch về những việc bạn định làm, thứ tự thực The Mythical Man-Month hiện, và kết quả cuối cùng là gì. Nếu bạn làm điều Đây thực sự là một quyển sách nên đọc. Dù rằng này, bạn sẽ thấy mọi thứ trở nên dễ dàng hơn và có thể nó đã được viết cách đây hơn 20 năm, thế nhưng vẫn hoàn thành nhanh hơn là bạn nghĩ. có nhiều điều có thể áp dụng. ISBN: 0-201-83595-9 Hãy làm việc theo nhóm! Nếu bạn dự định trở thành một lập trình viên đơn Programming Windows độc, hãy suy nghĩ lại. 99,9% các dự án đòi hỏi phải Nếu bạn có ý định lập trình trên Windows (bằng C làm việc theo nhóm. Và do đó, bạn cần phải có kinh hay C++), bạn cần phải mua quyển sách này. Theo tôi nghiệm làm việc theo nhóm, phối hợp với những đây là quyển sách dạy lập trình Windows tốt nhất. người khác trong một dự án. Một khi bạn đã hoàn ISBN: 1-57231-995-X thành những dự án nhỏ của riêng mình, đó là lúc bắt đầu tìm cách tham dự vào một dự án có nhiều người The Art of Ware tham gia. Đó có thể là một game, một bản demo, hay Tôi là một người hâm mộ cuồng nhiệt Tôn Tử, do bất cứ thứ gì. Chỉ cần đó là dự án làm bạn quan tâm. đó tôi rất thích thú khi đọc quyển sách này. Đây là một Có nhiều các để tìm dự án, bạn có thể gia nhập vào quyển sách có phong cách viết rất lôi cuốn, với những những dự án đã có, tìm kiếm những nhóm vừa mới bài học trong binh pháp Tôn Tử được vận dụng vào thành lập và xin gia nhập, hay thậm chí tự lập một dự ngành phát triển phần mềm. án và mời người khác cùng cộng tác. Điều quan trọng ISBN: 1-55851-396-5 nhất là bạn phải học cách làm việc cùng với những người khác để thực hiện mục tiêu chung. Ghi chú: các bạn có thể tìm những quyển sách trên bằng cách tìm kiếm trên Google hay những site Những thứ nên đọc! bán sách. Ở Việt Nam, bạn có thể vào site http://www. Đọc sách là nguyên tắc cơ bản… Và điều này sachtinhoc.com hay http://www.sachtuhoc.com và nhờ càng chính xác trong ngành phát triển phần mềm. họ mua giúp. Nếu bạn là người không thích đọc sách, có lẽ bạn nên chọn một công việc khác. Bởi vì đọc sách chính Tổng kết là chìa khóa để củng cố và hiện thực hóa những tiềm Hy vọng tôi đã nêu được một số điều cần thiết để năng của bạn. Bạn có thể tự hỏi vì sao tôi có thể viết trở thành một lập trình viên, không phải về mặt kỹ nhiều phần mềm trong thời gian ngắn như thế? Có 3 thuật mà là về mặt tư duy. Cá nhân tôi cho rằng lập lý do chính: kinh nghiệm, những đồng nghiệp tài năng trình là một công việc đầy hứng thú. Không có gì vui mà tôi luôn hài lòng khi được làm việc chung và cuối hơn khi nhìn thấy ai đó đang sử dụng phần mềm do cùng là những quyển sách tôi đã đọc. Tôi không thể bạn viết để làm cho cuộc sống của họ tốt hơn, dù chỉ giúp bạn có được kinh nghiệm và những bạn đồng là một phần nào đấy. Do đó, nếu bạn quyết định theo nghiệp giỏi, nhưng tôi có thể giới thiệu cho bạn những đuổi ngành phát triển phần mềm, tôi xin chúc bạn quyển sách hay: may mắn và hy vọng một ngày nào đó tôi sẽ có dịp download phần mềm do bạn viết để sử dụng. Code Complete Đây là quyển sách cần thiết cho mọi nhà phát triển phần mềm, bất kể họ đang dùng ngôn ngữ lập trình nào. Nó bao gồm nhiều bài thực hành và nhiều kỹ thuật liên quan đến phong cách viết mã. ISBN: 1-55615-484-4 5
  4. Căn bản về OpenGL Bài 1 - Thiết lập một cửa sổ OpenGL Tô Nguyễn Thanh Vũ Theo nehe.gamedev.net Bài này nhằm hướng dẫn bạn #include cách thiết lập một cửa sổ OpenGL. // File Header cho GLu32 Cửa sổ này có thể ở chế độ bình #include thường (window) hay toàn màn // File Header cho GLaux hình (fullscreen), có kích cỡ (size), độ phân giải (resolution) và độ sâu Tiếp theo là tất cả các biến toàn màu (color depth) tùy thích. Đoạn cục mà bạn sẽ dùng trong chương mã rất dễ điều chỉnh do đó có thể trình. Chương trình của chúng ta sẽ dùng lại trong tất cả các chương tạo ra một cửa sổ OpenGL trống, vì trình OpenGL khác. vậy bây giờ chúng ta không cần quá Tôi sẽ không nói dông dài về nhiều biến. Các biến mà chúng ta lý thuyết mà đi ngay vào phân tích khai báo dưới đây là rất quan trọng, phần mã chương trình. Đây cũng là và sẽ được dùng trong mọi chương một cách học tốt, bạn sẽ được giải trình OpenGL mà bạn sẽ viết sau thích từng đoạn mã trong chương này bằng cách dùng lại phần mã trình, và cả những bài viết tiếp theo này. cũng sẽ như thế. Điều đầu tiên bạn Dòng đầu tiên khai báo một RC cần phải làm là tạo một project mới (Rendering Context). Mỗi chương trong Visual C++. Nếu bạn vẫn chưa trình OpenGL đều được liên kết với biết cách tạo một project, bạn chưa một RC. Rendering Context là các nên học OpenGL lúc này, bạn nên liên kết OpenGL gọi đến Device học về Visual C++ trước. Chương Context. OpenGL Rendering trình nguồn cho bài viết này được Context được khai báo là hRC. Và xây dựng bằng chương trình Visual để chương trình vẽ một cửa sổ bạn C++ 6.0. Nhưng bằng cách thay đổi cần tạo một DC (Device Context), vài chi tiết nhỏ về tên các từ khóa, ở dòng thứ 2 của chương trình, tôi có thể biên dịch thành công Windows Device Context được khai chương trình này bằng VC++4 và báo là hDC. DC kết nối Window với VC++5. GDI (Graphics Device Interface). Sau khi bạn tạo một ứng dụng RC kết nối OpenGL với DC. Win32 mới (không phải là ứng dụng Dòng thứ 3 biến hWnd sẽ giữ console) trong Visual C++, bạn một handle (điều khiển) được cần liên kết các thư viện OpenGL gán cho cửa sổ của chúng ta bởi với chương trình của mình. Trong Windows, và cuối cùng, dòng thứ Visual C++ vào menu Project, 4 tạo một instance (thể hiện) cho Settings, và click vào tab LINK, ở chương trình của chúng ta. mục “Object/library modules” thêm vào (trước kernel32.lib) OpenGL32. HGLRC hRC=NULL; lib GLu32.lib và Glaux.lib. Click // Rendering Context OK, giờ thì bạn đã sẵn sàng viết một HDC hDC=NULL; chương trình OpenGL. // Private GDI Device Context Bốn dòng đầu tiên include các HWND hWnd=NULL; // Handle Window chúng ta dùng. HINSTANCE hInstance; // Instance của ứng dụng #include // File Header cho Windows Bây giờ chúng ta sang đoạn mã #include tiếp theo, dòng đầu tiên khai báo // File Header cho OpenGL32 một mảng dùng để quản lý các phím 6
  5. được nhấn trên bàn phím. Có nhiều cách để làm điều Các dòng tiếp theo thiết lập màn hình cho khung này, và bạn có thể tự chọn một cách theo bạn là tốt nhất. nhìn. Nghĩa là những gì ở xa hơn sẽ nhỏ hơn. Điều này Tôi chọn cách dùng mảng vì nó chính xác và có thể tạo ra một vùng nhìn thật hơn. Khung nhìn được tính quản lý nhiều hơn một phím nhấn ở một thời điểm. toán với góc nhìn 45 độ và dựa trên chiều rộng và chiều Biến active giúp cho chương trình biết được cửa sổ cao của cửa sổ. 0.1f, 100.0f là điểm bắt đầu và điểm kết của chúng ta đang thu nhỏ nằm ở taskbar (minimized) thúc cho độ sâu mà chúng ta có thể vẽ vào màn hình. hay không. Nếu như cửa sổ đang thu nhỏ, chúng ta có Lời gọi hàm lglMatrixMode(GL_PROJECTION) thể hiện thực bất kì điều gì từ tạm thời dừng chương cho biết 2 dòng mã tiếp theo sẽ ảnh hưởng đến ma trận trình cho đến thoát khỏi chương trình. Tôi thích tạm chiếu. Ma trận khung nhìn chịu trách nhiệm việc thêm dừng chương trình. khung nhìn vào vùng nhìn. glLoadIdentity() giống như Ý nghĩa của biến fullscreen rất dễ hiểu. Nếu chương reset. Nó đưa ma trận được chọn trở về trạng thái ban trình của chúng ta đang chạy ở chế độ toàn màn hình, đầu. Sau khi glLoadIdentity() được gọi chúng ta khai fullscreen sẽ bằng TRUE, ngược lại nếu chương trình báo khung nhìn mới cho vùng nhìn. glMatrixMode(GL_ chạy ở chế độ cửa sổ, fullscreen sẽ bằng FALSE. Biến MODELVIEW) cho biết bất kì sự thay đổi nào đều sẽ này nên là biến toàn cục vì mỗi thủ tục đều cần phải biết ảnh hưởng lên ma trận Modelview. Ma trận modelview chương trình đang chạy ở chế độ nào. là nơi thông tin đối tượng của chúng ta được lưu giữ. Cuối cùng chúng ta reset ma trận modelview. Đừng lo bool keys[256]; // Mảng cho phím nhấn nếu như bạn không hiểu, chỉ cần biết đây là những phần bool active=TRUE; // Cờ Active mặc định cần phải làm nếu như bạn một có một vùng nhìn tốt // là bằng TRUE (^_^). bool fullscreen=TRUE; // Cờ Fullscreen // mặc định bằng TRUE glMatrixMode(GL_PROJECTION); // Select The Projection Matrix Tiếp theo chúng ta định nghĩa hàm WndProc(). glLoadIdentity(); Lý do ta làm điều này vì hàm CreateGLWindow() có // Reset The Projection Matrix một tham khảo đến WndProc() nhưng WndProc() lại // Tính toán lại hệ số tỷ lệ của cửa sổ được đặt sau CreateGLWindow(). Trong C nếu chúng gluPerspective(45.0f,(GLfloat)width/ ta muốn truy xuất một hàm hay một phần của chương trình đang nằm sau phần chương trình hiện hành, chúng glMatrixMode(GL_MODELVIEW); ta phải khai báo phần mã chúng ta muốn truy xuất ở // Select The Modelview Matrix đỉnh chương trình. Vì vậy dòng tiếp theo chúng ta định glLoadIdentity(); // Reset The Modelview Matrix nghĩa trước WndProc() để CreateGLWindow() có thể } tham khảo tới. Trong đoạn mã tiếp theo ta thực hiện phần cài đặt LRESULT CALLBACK WndProc(HWND, cho OpenGL. Ta sẽ thiết lập màu dùng để xóa màn UINT, WPARAM, LPARAM); // Khai báo WndProc hình, bật vùng đệm độ sâu, cho phép smooth shading, v.v. Phần mã này sẽ không được gọi cho đến khi cửa Phần mã tiếp theo dùng để định lại kích thước vùng sổ OpenGL được tạo. Hàm trả về một giá trị nhưng vì nhìn OpenGL khi kích thước cửa sổ (giả sử bạn chạy phần khởi tạo của chúng ta không quá phức tạp nên chương trình ở chế độ cửa sổ) được điều chỉnh. Kể cả chúng ta cũng không cần bận tâm về giá trị này. khi bạn không có khả năng điều chỉnh lại cửa sổ (khi int InitGL(GLvoid) // Tất cả các cài đặt cho bạn ở chế độ fullscreen), phần mã này vẫn được gọi ít OpenGL đặt ở đây nhất là một lần khi chương trình chạy lần đầu để thiết { lập khung nhìn. Vùng nhìn OpenGL sẽ được định lại kích thước dựa theo chiều rộng và chiều cao của cửa sổ Dòng tiếp theo cho phép chế độ smooth shading. đang hiển thị. Chế độ này cho phép hiển thị màu sắc và ánh sáng tốt hơn. GLvoid ReSizeGLScene(GLsizei width, GLsizei glShadeModel(GL_SMOOTH); // Cho phép height) // Khởi tạo và điều chỉnh kích thước cửa sổ GL Smooth Shading { if (height==0) // Tránh lỗi Divide By Zero Dòng tiếp theo thiết lập màu của màn hình khi nó { được xóa. Tôi xin giải thích ngắn gọn về các màu. Tầm height=1; giá trị của màu từ 0.0f cho đến 1.0f. 0.0f là khi màu tối } nhất và 1.0f là khi sáng nhất. Thông số đầu tiên của hàm glViewport(0, 0, width, height); // Reset vùng nhìn glClearColor() là cường độ màu đỏ (Red), thông số thứ hiện hành hai là xanh lá (Green) và thứ ba là xanh dương (Blue). Kết hợp cường độ của ba màu này ta sẽ có các màu sắc 7
  6. khác nhau (nhớ là tầm giá trị từ 0.0f đến 1.0f). Thông số Hàm KillGLWindow() được gọi trước khi chương cuối cùng là giá trị Alpha. Khi dùng cho việc làm sạch trình kết thúc. Công việc của hàm này là giải phóng (clear) màn hình, chúng ta không bận tâm về thông số Rendering Context, Device Context và cuối cùng là thứ 4 này. Ta sẽ thiết lập nó là 0.0f. handle của cửa sổ. Tôi đã thêm vào một ít mã kiểm tra Để tạo một màu nền đen bạn thiết lập tất cả các màu lỗi. Nếu chương trình không thể giải phóng phần nào càng tối càng tốt (0.0f) của cửa sổ, một thông điệp lỗi sẽ hiển thị, cho biết phần glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // nền đen nào bị lỗi. Điều này khiến bạn dễ dàng hơn trong việc phát hiện lỗi trong lập trình. Ba dòng tiếp theo liên quan đến Depth Buffer (Bộ GLvoid KillGLWindow(GLvoid) đệm độ chiều sâu). Bạn hãy xem depth buffer như là các // hàm hủy cửa sổ lớp trong màn hình. Bộ đệm này chịu trách nhiệm về { việc các đối tượng đang ở sâu bao nhiêu trên màn hình. Ở chương trình này, chúng ta không thật sự dùng đến Đầu tiên cần phải biết chúng ta có đang ở chế độ depth buffer, nhưng mọi chương trình OpenGL vẽ màn toàn màn hình hay không. Nếu có, chúng ta sẽ chuyển hình ở chế độ 3D đều phải dùng đến depth buffer. Nó về chế độ bình thường. Chúng ta vẫn có thể hủy cửa sổ sắp xếp trật tự vẽ các đối tượng, nhờ đó một hình vuông trước khi tắt chế độ toàn màn hình, nhưng có vài card bạn vẽ sau một hình tròn sẽ không nằm trên hình tròn. màn hình nếu chúng ta hủy cửa sổ trước khi tắt chế độ Depth buffer là một phần rất quan trọng của OpenGL. toàn màn hình, thì desktop sẽ bị “treo”. Tốt nhất là ta tắt glClearDepth(1.0f); // Cài đặt Depth Buffer chế độ toàn màn hình trước khi hủy cửa sổ. glEnable(GL_DEPTH_TEST); // Cho phép kiểm if (fullscreen) // Đang ở chế độ toàn màn hình? tra độ sâu { glDepthFunc(GL_LEQUAL); // Chế độ kiểm tra Ta dùng ChangeDisplaySettings(NULL, 0) để trở Tiếp theo chúng ta thiết lập khung nhìn sao cho về. Việc truyền giá trị NULL và 0 khiến Windows dùng việc hiển thị là tối ưu. các giá trị hiện thời đang chứa trong registry (độ phân glHint(GL_PERSPECTIVE_CORRECTION_ giải mặc định, độ sâu bit màu, tần số, v.v…) để phục hồi HINT, GL_NICEST); // chọn chế độ hiển thị tốt nhất lại desktop. Sau khi chuyển sang desktop, chúng ta cho con trỏ chuột hiển thị trở lại. Cuối cùng giá trị trả về của hàm là TRUE. Nếu ChangeDisplaySettings(NULL,0); muốn biết việc cài đặt OpenGL có thành công hay // chuyển về desktop không, ta có thể kiểm tra giá trị trả về là TRUE hay ShowCursor(TRUE); // hiển thị con trỏ chuột FALSE, để làm việc này bạn cần phải thêm phần mã trả } về FALSE nếu như có lỗi xảy ra. return TRUE; Đoạn mã tiếp theo kiểm tra xem ta có một Rendering } Context (hRC) hay không. Nếu không có, chương trình sẽ nhảy đến đoạn mã kiểm tra chúng ta có Device Phần tiếp theo là nơi chứa tất cả các mã về việc vẽ Context hay không. lên màn hình. Tất cả những gì bạn muốn hiển thị trên if (hRC) // Rendering Context? màn hình đều nằm trong phần này. Nếu như bạn đã có { một số hiểu biết về OpenGL, bạn có thể tạo thử các dạng hình cơ bản bằng cách thêm mã OpenGL bên dưới Nếu có, đoạn code bên dưới sẽ cho biết liệu chúng dòng glLoadIdentity() và trước return TRUE. Hiện tại, ta có thể giải phóng nó (hRC) hay không (tách hRC khỏi chương trình của chúng ta chỉ dừng ở việc làm sạch hDC). Lưu ý cách tôi thực hiện việc kiểm tra lỗi. Đầu màn hình bằng màu đã định trước, xóa vùng đệm độ sâu tiên, cho chương trình giải phóng các Context (bằng và reset lại vùng nhìn. wglMakeCurrent(NULL,NULL), sau đó kiểm tra xem Dòng return TRUE cho biết không có lỗi xảy ra. việc giải phóng có thành công hay không). Nếu như bạn muốn chương trình dừng lại vì một vài if (!wglMakeCurrent(NULL,NULL)) // lí do nào đó, thêm vào dòng return FALSE ở nơi bạn { muốn để thông báo việc vẽ thất bại. Chương trình sẽ thoát ra khi thực thi đến dòng mã này. Nếu việc giải phóng các context DC và RC không int DrawGLScene(GLvoid) thành công, hộp thoại MessageBox() sẽ tự động bật lên { với một thông báo cho ta biết DC và RC không thể glClear(GL_COLOR_BUFFER_BIT | GL_ giải phóng được. Ý nghĩa của các thông số truyền cho DEPTH_BUFFER_BIT); // Xóa màn hình và bộ đệm hàm MessageBox() như sau: NULL nghĩa là hộp thoại glLoadIdentity(); // Reset ma trận Modelview không có các cửa sổ cha. Đoạn văn bản sau NULL sẽ return TRUE; // Mọi thứ OK được hiển thị trong hộp thoại. “SHUTDOWN ERROR” } là dòng chữ sẽ hiện trên đỉnh của hộp thoại (tiêu đề). 8
  7. Tiếp theo ta có MB_OK, có nghĩa là ta cần hộp thoại Class.”,”SHUTDOWN ERROR”,MB_OK | MB_ có một nút bấm có nhãn là “OK” và cuối cùng là MB_ ICONINFORMATION); ICONINFORMATION tạo một ký hiệu chữ i thường hInstance=NULL; // Set hInstance To NULL xuất hiện bên trong hộp thoại dùng để thông báo. } MessageBox(NULL,”Release Of DC And RC } Failed.”,”SHUTDOWN ERROR”,MB_OK | MB_ ICONINFORMATION); Kế đến là phần mã tạo nên cửa sổ OpenGL của } chúng ta. Tôi đã mất rất nhiều thời gian để quyết định nên tạo một cửa sổ toàn màn hình cố định, không đổi Tiếp theo chúng ta sẽ xóa Rendering Context. Nếu và không cần phải viết nhiều mã, hay là tạo một cửa không thành công sẽ có một hộp thoại thông báo lỗi. sổ thân thiện với người dùng và dể dàng chỉnh sửa. if (!wglDeleteContext(hRC)) Cuối cùng cửa sổ thân thiện người dùng là hướng đi tốt // có thể xóa RC hay không? nhất. Vì nhiều người bắt đầu thường rất hay thắc mắc { về những điều như: Làm thế nào để tạo ra một cửa sổ MessageBox(NULL,”Release Rendering Context thay vì toàn màn hình? Làm thế nào thay đổi tiêu đề Failed.”,”SHUTDOWN ERROR”,MB_OK | cửa sổ? Làm thế nào thay đổi độ phân giải hoặc định MB_ICONINFORMATION); dạng điểm của cửa sổ? Phần mã tiếp theo thực hiện tất } cả các điều này! hRC=NULL; // Set RC To NULL } Như bạn thấy, thủ tục trả về giá trị BOOL (TRUE hoặc FALSE), nó nhận 5 tham số: tiêu đề của cửa Tiếp theo là việc kiểm tra xem ta có một Device sổ, chiều rộng cửa sổ, chiều cao cửa sổ, số bit màu Context hay không và nếu có thì giải phóng nó. Nếu ta (16/24/32), và cuối cùng là cờ fullscreen (bằng TRUE không thành công trong việc giải phóng Device Context cho chế độ toàn màn hình, bằng FALSE cho chế độ cửa thì một thông điệp sẽ hiện ra và hDC sẽ được thiết lập sổ). Giá trị BOOL trả về cho biết cửa sổ đã được tạo là NULL. thành công hay chưa. if (hDC && !ReleaseDC(hWnd,hDC)) // có thể BOOL CreateGLWindow(char* title, int width, giải phóng DC không? int height, int bits, bool { { MessageBox(NULL,”Release Device Context Failed.”,”SHUTDOWN ERROR”,MB_OK | MB_ Khi yêu cầu Windows cung cấp cho chúng ta ICONINFORMATION); một định dạng điểm phù hợp với mong muốn, giá hDC=NULL; // Set DC To NULL trị mà Windows tìm được sẽ được cất trong biến } PixelFormat. GLuint PixelFormat; // Chứa kết quả định dạng sau Đoạn mã bên dưới là đoạn mã tìm và hủy cửa sổ khi tìm kiếm dùng hàm DestroyWindow(hWnd). Nếu chúng ta không hủy được cửa sổ, một thông điệp lỗi sẽ hiện ra và hWnd Biến wc sẽ được dùng để chứa cấu trúc Window được gán bằng NULL. Class. Cấu trúc Window Class giữ thông tin về cửa sổ. if (hWnd && !DestroyWindow(hWnd)) // Có thể Bằng việc thay đổi các vùng trong Class này chúng ta hủy cửa sổ không? có thể thay đổi cách nhìn và cách vận hành cửa sổ. Mọi { cửa sổ đều thuộc về một Window Class. Trước khi bạn MessageBox(NULL,”Could Not Release tạo một cửa sổ, bạn phải đăng kí một Class cho cửa sổ. hWnd.”,”SHUTDOWN ERROR”,MB_OK | MB_ WNDCLASS wc; // Cấu trúc Windows Class ICONINFORMATION); hWnd=NULL; // Set hWnd To NULL Các biến dwExStyle và dwStyle sẽ chứa các thông } tin về kiểu (Style) Window bình thường và mở rộng (Extended). Việc dùng các biến để chứa các thông tin Điều cuối cùng cần làm là hủy bỏ đăng kí Class này khiến cho bạn có thể thay đổi các kiểu phụ thuộc Windows của chúng ta. Điều này cho phép ta hủy cửa vào loại cửa sổ bạn muốn hiển tạo ra (một cửa sổ popup sổ một cách chính quy và sau đó có thể mở cửa sổ khác hoặc toàn màn hình hoặc một cửa sổ có viền ngoài) mà không nhận được thông báo lỗi “Windows Class DWORD dwExStyle; // Window Extended Style already registered” DWORD dwStyle; // Window Style if (!UnregisterClass(“OpenGL”,hInstance)) // Có thể hủy đăng ký không? Năm dòng mã tiếp theo chứa các giá trị góc trái { trên, và góc phải dưới của một hình chữ nhật. Ta sẽ MessageBox(NULL,”Could Not Unregister dùng các giá trị này để điều chỉnh cửa sổ sao cho vùng 9
  8. vẽ hiển thị chính xác ở độ phân giải chúng ta cần. sẽ kết thúc chương trình. if (!RegisterClass(&wc)) // đăng kí Window Class RECT WindowRect; // Giữ giá trị góc trên bên trái, { góc dưới bên phải hình chữ nhật MessageBox(NULL,”Failed To Register WindowRect.left=(long)0; // giá trị bên trái bằng The Window Class.”, “ERROR”, MB_OK|MB_ 0 ICONEXCLAMATION); WindowRect.right=(long)width; // giá trị bên phải return FALSE; // thoát và trả về FALSE bằng với chiều rộng yêu cầu } WindowRect.top=(long)0; // giá trị phía trên 0 WindowRect.bottom=(long)height; // giá trị phía Có nhiều người thường hay vấp phải lỗi trong việc dưới bằng với chiều cao yêu cầu chuyển sang chế độ toàn màn hình. Bạn nên nhớ vài điều quan trọng khi chuyển sang chế độ toàn màn hình. Ở dòng tiếp theo chúng ta cho biến toàn cục fullscreen Phải chắc chắn là chiều rộng và chiều cao bạn dùng bằng vớ ì nếu chúng ta chuyển cửa sổ trong chế độ toàn màn hình cũng chính là chiều rộng và thành toàn màn hình, biế ẽ là TRUE. chiều cao bạn dùng cho cửa sổ, và quan trọng nhất, thiết Nếu ta không gán fullscreen bằ á trị lập chế độ toàn màn hình trước khi bạn tạo cửa sổ. fullscreen sẽ vẫn là FALSE. Nếu chúng ta hủy cửa sổ, DEVMODE dmScreenSettings; // Chế độ thiết bị và máy tính vẫn đang ở chế độ toàn màn hình, nhưng memset(&dmScreenSettings,0,sizeof(dmScreenSe do biến fullscreen bằng FALSE, chương trình sẽ không ttings)); // xóa vùng nhớ chuyển về chế độ desktop trước khi hủy cửa sổ dẫn đến dmScreenSettings.dmSize= lỗi như phần trên tôi đã trình bày. sizeof(dmScreenSettings); // cập nhật biến toàn cục // Kích thước của cầu trúc Devmode fullscreen dmScreenSettings.dmPelsWidth = width; // chọn chiều rộng Các hằng CS_HREDRAW và CS_VREDRAW quy dmScreenSettings.dmPelsHeight = height; định cửa sổ sẽ được vẽ lại mỗi khi nó được cập nhật // và chiều cao kích thước. CS_OWNDC tạo một DC private cho cửa dmScreenSettings.dmBitsPerPel = bits; sổ. Nghĩa là các ứng dụng khác không chia sẻ DC này. // chọn số bít mỗi điểm WndProc là một thủ tục theo dõi các thông điệp trong dmScreenSettings.dmFields=DM_ chương trình. Do không có các dữ liệu cửa sổ nào khác BITSPERPEL|DM_PELSWIDTH|DM_ nên hai vùng cbClsExtra và cbWndExtra bằng không. PELSHEIGHT; Cho hIcon bằng NULL nghĩa là chúng ta không cần một ICON trên cửa sổ, và giá trị của hCursor cho phép Trong đoạn mã trên, chúng ta xóa vùng nhớ để chứa ta dùng con trỏ chuột chuẩn. Màu nền không quan trọng các thiết lập video. Thiết lập chiều rộng, chiều cao và số (ta đã thiết lập trong OpenGL). Ta cũng không cần một bit của chế độ toàn màn hình. Tất cả các thông tin này menu trong cửa sổ này nên cho nó bằng NULL, và tên được chứa trong dmScreenSettings. Ở dòng mã bên dưới lớp có thể là bất cứ gì bạn muốn. ChangeDisplaySettings sẽ chuyển màn hình sang chế hInstance = GetModuleHandle(NULL); // giữ một độ phù hợp với những gì chứa trong dmScreenSettings. thể hiện của cửa sổ Tôi dùng thông số CDS_FULLSCREEN khi đổi chế wc.style = CS_HREDRAW | CS_VREDRAW | độ, vì cần phải bỏ thanh start ở đáy màn hình, thêm vào CS_OWNDC; việc nó không được dịch chuyển hay định lại kích thước wc.lpfnWndProc = (WNDPROC) WndProc; // cho đến khi bạn trở lại chế độ cửa sổ bình thường. WndProc điều khiển các thông điệp if (ChangeDisplaySettings(&dmScreenSettings, wc.cbClsExtra = 0; // không có dữ liệu cửa sổ phụ CDS_FULLSCREEN)!= wc.cbWndExtra = 0;//không có dữ liệu cửa sổ phụ DISP_CHANGE_SUCCESSFUL) wc.hInstance = hInstance; // thiết lập thể hiện { wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // nạp icon mặc định Nếu không thể chuyển sang chế độ toàn màn hình, wc.hCursor = LoadCursor(NULL, IDC_ARROW); đoạn mã bên dưới sẽ được thực thi. Một hộp thoại sẽ bật // nạp con trỏ mặc định lên với hai tùy chọn… một là chạy ở chế độ cửa sổ, và wc.hbrBackground = NULL; // màu nền không cần hai là thoát chương trình. thiết nếu như ta dùng OpenGL if (MessageBox(NULL,”The Requested Fullscreen wc.lpszMenuName = NULL; // không cần menu Mode Is Not Supported By\nYour Video Card. wc.lpszClassName = “OpenGL”; // đặt tên lớp Use Windowed Mode Instead?”, “OpenGL”, MB_ YESNO|MB_ICONEXCLAMATION)==IDYES) Bây giờ ta đăng kí Window Class. Nếu có lỗi xảy { ra, một hộp thoại báo lỗi sẽ bật lên. Click vào nút OK 10
  9. Nếu người dùng quyết định dùng chế độ cửa sổ, Dòng mã tiếp theo điều chỉnh cửa sổ theo đúng như biến fullscreen được chuyển thành FALSE và chương các kiểu mà ta đã thiết lập. Sự điều chỉnh này khiến cửa trình tiếp tục chạy. sổ của chúng ta có chính xác độ phân giải như yêu cầu. fullscreen=FALSE; // chuyển sang chế độ cửa sổ Bình thường các đường viền sẽ trùng lấp một số phần } của cửa sổ. Bằng cách dùng AdjustWindowRectEx sẽ else không có phần nào của vùng nhìn OpenGL sẽ bị bao { phủ bởi đường viền, thay vào đó, cửa sổ sẽ được làm lớn hơn. Trong chế độ toàn màn hình, lệnh này không Nếu người dùng quyết định thoát, một hộp thoại bật có hiệu quả. lên cho người dùng biết chương trình sẽ đóng. FALSE AdjustWindowRectEx(&WindowRect, dwStyle, sẽ được trả về cho biết chương trình đã không hoạt FALSE, dwExStyle); động thành công. // Điều chỉnh lại kích thước cửa sổ // bật hộp thoại cho biết chương trình đang đóng MessageBox(NULL,”Program Will Now Close.”, Tiếp theo, ta tạo cửa sổ và kiểm tra xem nó được tạo ”ERROR”,MB_OK|MB_ICONSTOP); đúng hay không. Ta truyền cho hàm CreateWindowEx() return FALSE; tất cả các thông số cần thiết. Kiểu mở rộng cần dùng. // thoát chương trình và trả về FALSE Tên lớp (là tên bạn dùng khi đăng kí Window Class). } Tiêu đề cửa sổ. Kiểu cửa sổ. Góc trên bên trái của cửa } sổ. Chiều rộng và chiều cao. Ta không cần cửa sổ cha, } và cũng không có menu, vì vậy ta thiết lập cả hai thông số này là NULL. Do phần mã phía trên có thể không thành công và Lưu ý là tôi thêm vào kiểu WS_CLIPSIBLINGS và người dùng có thể quyết định chạy chương trình ở chế WS_CLIPCHILDREN dọc theo kiểu cửa sổ. Hai kiểu độ cửa sổ, ta cần kiểm tra lại biến fullscreen bằng TRUE này là hai kiểu cần thiết cho OpenGL. Các kiểu này hay FALSE trước khi thiết lập kiểu màn hình/cửa sổ. chống lại việc các cửa sổ khác vẽ đè hay vẽ vào trong if (fullscreen) // vẫn đang trong chế độ toàn màn cửa sổ OpenGL. hình? { if (!(hWnd=CreateWindowEx( dwExStyle, // kiểu mở rộng Nếu đúng, chúng ta thiết lập kiểu mở rộng (extended “OpenGL”, // tên lớp style) là WS_EX_APPWINDOW, đẩy cửa sổ đang nằm title, // tiêu đề cửa sổ trên cùng của window xuống taskbar khi cửa sổ của ta WS_CLIPSIBLINGS | bật lên. Với kiểu cửa sổ (window style) ta sẽ tạo một WS_CLIPCHILDREN | cửa sổ WS_POPUP, cửa sổ này không có đường viền dwStyle, // kiểu đã chọn bao quanh, rất thích hợp cho chế độ toàn màn hình. 0, 0, // vị trí cửa sổ Cuối cùng, ta tắt con trỏ chuột. Bạn cũng có thể để WindowRect.right-WindowRect.left, // điều chỉnh con trỏ chuột, điều này phụ thuộc vào bạn. chiều rộng dwExStyle=WS_EX_APPWINDOW; // Window WindowRect.bottom-WindowRect.top, // điều Extended Style chỉnh chiều cao dwStyle=WS_POPUP; // Windows Style NULL, // không có cửa sổ cha ShowCursor(FALSE); // giấu con trỏ chuột NULL, // không có menu } hInstance, // Instance else NULL))) // không truyền cho WM_CREATE gì cả { Nếu dùng một cửa sổ thay cho chế độ toàn màn hình, Nếu cửa sổ đã được tạo, hWnd sẽ giữ điều khiển ta sẽ thiết lập kiểu mở rộng là WS_EX_WINDOWEDGE. cửa sổ. Nếu cửa sổ không được tạo đoạn mã bên dưới Điều này khiến cho cửa sổ có vẻ 3D hơn. Với kiểu cửa sẽ khiến hiển thị một thông báo lỗi và ngừng chương sổ ta dùng WS_OVERLAPPEDWINDOW thay cho trình. WS_POPUP. WS_OVERLAPPEDWINDOW tạo một { cửa sổ có thanh tiêu đề, đường viền kích thước, menu KillGLWindow(); cửa sổ, và các nút minimize/maximize (phóng to/thu MessageBox(NULL,”Window Creation Error.”, nhỏ cửa sổ). “ERROR”, MB_OK|MB_ICONEXCLAMATION); dwExStyle=WS_EX_APPWINDOW | WS_EX_ return FALSE; // trả về FALSE WINDOWEDGE; // Window Extended Style } dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style Phần tiếp theo mô tả một định dạng điểm (Pixel } Format). Ta chọn một định dạng có hỗ trợ OpenGL 11
  10. và việc đệm đôi (double buffering), kèm theo hệ màu KillGLWindow(); RGBA (có các kênh màu đỏ, xanh lá, xanh dương, và MessageBox(NULL,”Can’t Find A Suitable alpha). Và định dạng này có hỗ trợ số bit mà ta chọn PixelFormat.”, “ERROR”, MB_OK|MB_ (16bit, 24bit, 32bit). Cuối cùng ta cài đặt một bộ đệm ICONEXCLAMATION); 16bit (16bit Z-Buffer). Các thông số còn lại không quan return FALSE; trọng hoặc không dùng đến (trừ bộ đệm stencil (mẫu tô) } và bộ đệm accumulation (tích lũy)). static PIXELFORMATDESCRIPTOR pfd= Nếu Windows tìm được định dạng ảnh phù hợp, ta { sẽ tiến hành cài đặt định dạng ảnh. Nếu định dạng ảnh sizeof(PIXELFORMATDESCRIPTOR), không cài đặt được, một thông điệp lỗi sẽ hiển thị và // kích thước của mô tả định dạng điểm chương trình kết thúc (return FALSE). 1, if(!SetPixelFormat(hDC,PixelFormat,&pfd)) // số phiên bản { PFD_DRAW_TO_WINDOW | KillGLWindow(); // định dạng phải hỗ trợ Window MessageBox(NULL,”Can’t Set The PFD_SUPPORT_OPENGL | PixelFormat.”,”ERROR”,MB_OK|MB_ // định dạng phải hỗ trợ OpenGL ICONEXCLAMATION); PFD_DOUBLEBUFFER, return FALSE; // hỗ trợ Double Buffering } PFD_TYPE_RGBA, // yêu cầu định dạng màu RGBA Khi định dạng ảnh đã được thiết lập xong, phần tiếp bits, // chọn độ sâu màu theo là nhận một Rendering Context. Nếu không lấy 0, 0, 0, 0, 0, 0, // bỏ qua các bit màu được một RC, một thông điệp lỗi sẽ được hiển thị và 0, // không có bộ đệm Alpha chương trình sẽ kết thúc (return FALSE) 0, // bỏ qua bit Shift if (!(hRC=wglCreateContext(hDC))) 0, // không có bộ đệm Accumulation { 0, 0, 0, 0, // bỏ qua các bit Accumulation KillGLWindow(); 16, // 16Bit Z-Buffer (Depth Buffer) MessageBox(NULL,”Can’t Create A GL 0, // không có bộ đệm Stencil Rendering Context.”,”ERROR”,MB_OK|MB_ 0, // không có bộ đệm Auxiliary ICONEXCLAMATION); PFD_MAIN_PLANE, // Lớp vẽ chính return FALSE; 0, // để dành } 0, 0, 0 // bỏ qua các mặt nạ lớp }; Khi không có lỗi nào xảy ra, và ta đã tạo được cả hai Device Context và Rendering Context, phần còn lại Nếu không có lỗi xảy ra khi tạo cửa sổ, ta tiếp tục là làm cho Rendering Context hoạt động. Nếu ta không lấy một OpenGL Device Context. Nếu ta không thể thể kích hoạt Rendering Context một thông điệp lỗi sẽ nhận được một DC, một thông báo lỗi sẽ hiện trên màn bật lên và chương trình kết thúc (return FALSE). hình, và chương trình kết thúc (return FALSE). if(!wglMakeCurrent(hDC,hRC)) if (!(hDC=GetDC(hWnd))) // Ta đã có Device // Kích hoạt Rendering Context Context? { { KillGLWindow(); KillGLWindow(); MessageBox(NULL,”Can’t Activate The GL MessageBox(NULL,”Can’t Create A GL Rendering Context.”, “ERROR”, MB_OK|MB_ Device Context.”, “ERROR”, MB_OK|MB_ ICONEXCLAMATION); ICONEXCLAMATION); return FALSE; return FALSE; } } Khi mọi thứ đều tốt đẹp, và cửa sổ OpenGL đã Sau khi có được một Device Context cho cửa sổ được tạo, ta bắt đầu hiển thị cửa sổ, cho nó làm cửa sổ OpenGL, ta tìm một định dạng điểm phù hợp với yêu hiện hành và ở trên cùng (bằng cách cho nó độ ưu tiên cầu đã khai báo ở trên. Nếu Windows không thể tìm ra cao). Sau đó ta gọi ReSizeGLScene với các thông số định dạng phù hợp, một thông điệp lỗi sẽ hiển thị và chiều rộng và chiều cao để thiết lập khung nhìn màn chương trình kết thúc (return FALSE). hình OpenGL. if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd) ShowWindow(hWnd,SW_SHOW); )) // Hiển thị cửa sổ { SetForegroundWindow(hWnd); 12
  11. // Có độ ưu tiên cao return 0; SetFocus(hWnd); // Là cửa sổ hiện hành } ReSizeGLScene(width, height); case WM_SYSCOMMAND: Cuối cùng ta chuyển sang hàm InitGL() là nơi có thể // các lệnh chặn hệ thống thiết lập ánh sáng, texture, ... Bạn có thể tự mình thực { hiện việc kiểm tra lỗi trong InitGL(), và trả về TRUE switch (wParam) // kiểm tra các lời gọi hệ thống (mọi thứ đều tốt) hoặc FALSE (có gì đó không ổn). Ví { dụ, nếu bạn tiến hành nạp các texture trong InitGL() case SC_SCREENSAVE: và mắc phải lỗi, có lẽ là bạn sẽ muốn chương trình kết // chuẩn bị screen saver? thúc. Nếu bạn trả về giá trị FALSE từ InitGL() đoạn mã case SC_MONITORPOWER: bên dưới sẽ được thực thi và chương trình sẽ kết thúc // chuẩn bị tắt màn hình? cùng với một thông điệp lỗi. return 0; // không cho các sự kiện trên xảy ra if (!InitGL()) // khởi tạo cửa sổ GL Window } { break; // Exit KillGLWindow(); } MessageBox(NULL,”Initialization Failed.”, “ERROR”, MB_OK|MB_ICONEXCLAMATION); case WM_CLOSE: return FALSE; // Ta nhận được một thông điệp đóng? } { PostQuitMessage(0); // Gửi thông điệp kết thúc Khi chương trình đã thực thi đến đây, ta có thể trả return 0; // Nhảy trở về về giá trị TRUE cho hàm WinMain() cho biết chương } trình không có lỗi. Và việc này khiến cho chương trình không bị kết thúc. case WM_KEYDOWN: // Có phím được nhấn? return TRUE; // thành công { } keys[wParam] = TRUE; // Nếu có, đánh dấu nó là TRUE Đây là nơi các cửa sổ thông điệp giao tiếp. Khi return 0; // quay trở về đăng ký Window Class chúng ta đã xác định nó phải } nhảy vào phần mã này để giao tiếp với các cửa sổ thông điệp. case WM_KEYUP: // Có phím được nhả ra? LRESULT CALLBACK { WndProc( HWND hWnd, keys[wParam] = FALSE; // Handle cho cửa sổ này // Nếu có, đánh dấu nó là FALSE UINT uMsg, // thông điệp cho cửa sổ này return 0; // quay trở về WPARAM wParam, // thông tin thông điệp phụ } LPARAM lParam) // thông tin thông điệp phụ { case WM_SIZE: // Định lại kích thước cửa sổ OpenGL Đoạn mã bên dưới xét các giá trị của uMsg. uMsg { chứa tên các thông điệp mà chúng ta muốn giao tiếp. ReSizeGLScene(LOWORD(lParam),HIWORD(lP switch (uMsg) // kiểm tra các thông điệp Windows aram)); // LoWord=chiều rộng, HiWord=chiều cao { return 0; // quay trở về } case WM_ACTIVATE: } { if (!HIWORD(wParam)) // kiểm tra trạng thái Những thông điệp không quan trọng khác sẽ được minimize truyền cho DefWindowProc và cho Windows tự động { giao tiếp với chúng. active=TRUE; // cửa sổ đang hoạt động } // Truyền tất cả các thông điệp else // khác cho DefWindowProc { return DefWindowProc(hWnd,uMsg,wParam,lPa active=FALSE; // chương trình đang minimize và ram); không hoạt động } } 13
  12. Đây là hàm chính của ứng dụng Windows. Đây là trình. Nhiều chương trình khác dùng GetMessage(). nơi mọi thứ được thực thi. Cũng tốt, nhưng với GetMessage() chương trình của int WINAPI WinMain( HINSTANCE hInstance, // bạn không thực hiện bất cứ gì cho đến khi nó nhận được Instance thông điệp vẽ hay vài thông điệp khác. HINSTANCE hPrevInstance, // Instance trước if (PeekMessage(&msg, LPSTR lpCmdLine, // Các tham số dòng lệnh NULL,0,0,PM_REMOVE)) int nCmdShow) // Trạng thái hiển thị cửa sổ // có thông điệp nào đang chờ không? { { Ta khai báo thêm hai biến. msg được dùng để kiểm Trong phần mã tiếp theo ta kiểm tra có một thông tra xem có thông điệp nào cần phải giao tiếp hay không. điệp thoát nào bị bỏ qua hay không. Nếu thông điệp Biến done có trạng thái bắt đầu là FALSE, điều này có hiện thời là một thông điệp WM_QUIT gây ra bởi nghĩa là chương trình của chúng ta chưa chạy xong. Khi PostQuitMessage(0) biến done sẽ được gán bằng nào done còn là FALSE, chương trình vẫn còn chạy. TRUE. Ngay khi done chuyển từ FALSE thành TRUE, chương if (msg.message==WM_QUIT) trình sẽ kết thúc. // Ta nhận được một thông điệp thoát? MSG msg; { BOOL done=FALSE; done=TRUE; // nếu đúng done=TRUE // biến luận lý để kết thúc vòng lặp } else{ Đoạn mã dưới đây là hoàn toàn tùy chọn. Nó hiển thị một hộp thoại yêu cầu xác nhận có cần chương trình Nếu không phải là thông điệp thoát, ta phiên dịch chạy ở chế độ toàn màn hình hay không. Nếu người thông điệp và gửi đi cho hàm WndProc() hoặc Windows dùng chọn NO, biến fullscreen chuyển từ TRUE (giá trị có thể xử lý. mặc định) thành FALSE và chương trình chạy ở chế độ TranslateMessage(&msg); // phiên dịch thông điệp cửa sổ thay vì chế độ toàn màn hình. DispatchMessage(&msg); // gửi thông điệp if (MessageBox(NULL,”Would You Like To Run } In Fullscreen Mode?”, “Start } FullScreen?”,MB_YESNO|MB_ else // nếu không có thông điệp ICONQUESTION)==IDNO) { { fullscreen=FALSE; // Chế độ cửa sổ Khi không có thông điệp ta tiến hành vẽ vùng nhìn } OpenGL. Dòng mã đầu tiên kiểm tra xem cửa sổ có đang hoạt động hay không. Nếu phím ESC được nhấn Đây là cách chúng ta tạo một cửa sổ OpenGL. Ta giá trị biến done sẽ bằng TRUE. truyền các thông số như tiêu đề, chiều rộng, chiều cao, if (active) // Chương trình đang chạy? độ sâu màu, và TRUE (toàn màn hình) hay FALSE (chế { độ cửa sổ) cho CreateGLWindow. Rất đơn giản! Và nếu if (keys[VK_ESCAPE]) // ESC đã được nhấn? cửa sổ không được tạo vì lý do nào đó, FALSE sẽ được { trả về và chương trình sẽ kết thúc ngay lập tức (return done=TRUE; // Nếu đúng, dừng chương trình 0). } // Tạo một cửa sổ OpenGL else // chưa phải lúc dừng, cập nhật màn hình if (!CreateGLWindow(“NeHe’s OpenGL Framewo { rk”,640,480,16,fullscreen)) { Nếu chương trình đang hoạt động và ESC không return 0; // Thoát nếu cửa sổ không được tạo được nhấn chúng ta dựng vùng nhìn và đổi bộ đệm (khi } dùng bộ đệm đôi các chuyển động trở nên trơn tru hơn). Dùng bộ đệm đôi, chúng ta vẽ mọi thứ vào một màn Bắt đầu vòng lặp, vòng lặp kết thúc khi done bằng hình ẩn và không thể nhìn thấy. Khi chúng ta hoán đổi TRUE. bộ đệm, màn hình hiện thời sẽ trở thành màn hình ẩn, và màn hình ẩn đã được cập nhật sẽ trở thành màn hình while(!done) // lặp cho đến khi done=TRUE hiển thị. Điều này làm cho việc cập nhật màn hình trở { nên nhanh hơn. DrawGLScene(); // vẽ vùng nhìn Điều đầu tiên ta cần kiểm tra là có thông điệp nào SwapBuffers(hDC); // hoán vị các bộ đệm đang đợi hay không. Dùng PeekMessage() chúng ta có } thể kiểm tra các thông điệp mà không phải ngừng chương } 14
  13. Đoạn mã tiếp theo cho phép người dùng phím F1 để chuyển đổi giữa chế độ cửa sổ và chế độ toàn màn hình. if (keys[VK_F1]) // F1 đã được nhấn? { keys[VK_F1]=FALSE; // Nếu đúng, reset vị trí phím nhấn KillGLWindow(); // Xóa cửa sổ hiện thời fullscreen=!fullscreen; // đổi giữa chế độ toàn màn hình và chế độ cửa sổ // tạo lại cửa sổ OpenGL if (!CreateGLWindow(“NeHe’s OpenGL Framewo rk”,640,480,16,fullscreen)) { return 0; // dừng chương trình nếu cửa sổ không được tạo } } } } Nếu biến done không còn bằng FALSE, chương trình sẽ kết thúc. Chúng ta hủy cửa sổ OpenGL để chắc rằng mọi thứ đã được giải phóng, và kết thúc chương trình. // Shutdown KillGLWindow(); // hủy cửa sổ return (msg.wParam); // kết thúc chương trình } Trong bài viết này, tôi đã cố gắng giải thích một cách thật chi tiết về mỗi dòng lệnh trong chương trình, mỗi một bước trong việc thiết lập, cài đặt và tạo một cửa sổ OpenGL… Và nếu bạn kết hợp tất cả các đoạn mã mà tôi đã từng bước trình bày thành một chương trình hoàn chỉnh (theo thứ tự từ trên xuống dưới), thì bảo đảm là bạn sẽ có một chương trình hoàn chỉnh và có thể chạy được trên nền VC++ 6. Nếu bạn không muốn gõ lại chương trình thì vẫn có thể liên hệ với tòa soạn để nhận source code hoàn chỉnh (tất nhiên là giống y như những đoạn mã tôi đã trình bày ^_^). Chúc bạn từng bước thành công trong việc tìm hiểu và lập trình với thư viện đồ họa OpenGL (Open Graphics Library). Trong bài viết này, các bạn chỉ mới thiết lập một cửa sổ trống rỗng, thế nhưng đây là bước quan trọng đầu tiên để có thể viết các ứng dụng OpenGL. Nếu không tạo cửa sổ OpenGL, chắc chắn bạn sẽ không thể làm được gì khác. Trong những bài viết tiếp theo, chúng ta sẽ học cách vẽ các đối tượng đồ họa vào trong cửa sổ OpenGL này. 15
  14. Lưu trữ hình ảnh vào Cơ sở dữ liệu với C#. Mai Phúc Tiến “Làm thế nào chúng ta có thể lưu trữ hình ảnh vào Nút ‘Browse’ dùng để chọn hình trang bìa, nút cơ sở dữ liệu và truy cập chúng trở lại?”, đây là câu ‘Insert’ dùng để đưa các thông tin về sách vào cơ sở hỏi thường gặp trong lập trình cơ sở dữ liệu. Trong dữ liệu. bài này chúng ta sẽ khảo sát cách thức lưu trữ hình Trước khi có thể nhập thông tin vào cơ sở dữ ảnh trong cơ sở dữ liệu và hiển thị chúng dùng ADO. liệu, chúng ta cần khởi tạo 1 kết nối đến cơ sở dữ liệu NET. Chúng ta sẽ tạo hai ứng dụng. Một ứng dụng ‘book’ của chúng ta. Để làm được điều này, bên trong để lưu trữ các thông tin về sách như tên tác giả, tên lớp Form1 bạn cần bổ sung các biến sau: sách, hình minh họa trang bìa vào cơ sở dữ liệu. Ứng String constr; //chuỗi xác định kết nối với cơ sở dụng còn lại sẽ truy xuất cơ sở dữ liệu và hiển thị dữ liệu ‘book’ những thông tin đó. Để tạo hai ứng dụng này chúng SqlConnection con; //đối tượng kết nối ta cần tạo một cơ sở dữ liệu có tên ‘book’, trong đó có một bảng là ‘bookinfo’ với các trường dữ liệu sau: Bạn cần bổ sung thêm khai báo namespace bookname(char), author(char), logo(image). Ở đây System.Data.SqlClient ở đầu chương trình để kích logo đại diện cho hình bìa của sách. hoạt lớp SqlConnection.Bên trong constructor của lớp Form1, bạn cần khởi tạo kết nối và mở cơ sở dữ liệu Ứng dụng đầu tiên ‘book’: Với ứng dụng đầu tiên, chúng ta tạo ứng dụng WinForm và thiết kế chúng như hình sau: //tạo chuỗi kết nối constr= “server=; database=books;uid=sa;pwd=”; //tạo đối tượng kết nối con=new SqlConnection(constr); //mở kết nối con.Open(); Trong đó: server: tên server. database: tên cơ sở dữ liệu. uid,pwd: lần lượt là username và password truy cập server. Sau khi đã mở được kết nối đến server cơ sở dữ liệu, người dùng có thể nhập vào các thông tin tên sách, tên tác giả, và lựa chọn hình ảnh cho trang bìa. Sử dụng các control với tên như bảng sau: Để có thể lựa chọn được hình trang bìa ta cần phải xử lí sự kiện xảy ra trên nút ‘Browse’ khi nhấn vào nó. Book Name Textbox book Dưới đây là hàm xử lí: Author Textbox author private void browse_Click ( object sender, EventArgs e ) Image Textbox { Browse button browse OpenFileDialog ofd = new OpenFileDialog( ) ; Insert button insert 16
  15. if ( ofd.ShowDialog( ) == DialogResult.OK ) kết nối với cơ sở dữ liệu. Trong ứng dụng này, bạn cần bổ sung namespace } System.IO để có thể dùng lớp FileStream. Trong đoạn mã trên chúng ta tạo một đối tượng Ứng dụng thứ hai của lớp OpenFileDialog có tên là ofd. Dùng thuộc tính Bây giờ chúng ta tạo ứng dụng thứ hai để truy cập Filter để lọc lấy những loạ à ta quan tâm đến và hiển thị dữ liệu trong bảng ‘bookinfo’. Bạn hãy trong trường hợp này là cá ảnh jpg. Sau đó gọi thiết kế ứng dụng WinForm như hình sau: hàm ShowDialog() để hiển thị hộp thoại và kiểm tra xem người dùng có chọn ảnh không. Nếu có, chúng ta gán giá trị của thuộc tính FileName của ofd cho thuộc tính Text củ Sau khi đã nhập vào đầy đủ, người dùng nhấn nút ‘Insert’ để lưu thông tin vào cơ sở dữ liệu. Để thực hiện điều này chúng ta cần xử lý hàm insert_Click, hàm quản lý sự kiện click lên nút Insert: private void insert_Click ( object sender, EventArgs e ) { FileStream f = new FileMode.Open ) ; byte[ ] buff = new byte [ f.Length ] ; Xác định các control với tên tương ứng như sau: f.Read ( buff, 0, ( int ) f.Length ) ; string cmdstr = “Insert into bookinfo values ( @b, Book Name Label bookl @a, @l )” ; Author Label authorl SqlCommand com = new SqlCommand ( cmdstr, Picture Box img con ) ; Next Button next com.Parameters.Add ( “@b”, book.Text ) ; com.Parameters.Add ( “@a”, author.Text ) ; com.Parameters.Add ( “@l”, buff ) ; Khi người dùng nhấn nút ‘Next’, các thông tin về com.ExecuteNonQuery( ) ; sách trong cơ sở dữ liệu sẽ được hiển thị. con.Close( ) ; Bổ sung thêm các biến vào lớp Form1: } string constr; Đầu tiên, chúng ta tạo 1 đối tượng thuộc lớp SqlConnection con; FileStream với các đối số khởi tạo là tê ứa string cmdstr; à kiểu là FileMode.Open. Tiếp theo, SqlCommand com; chúng ta tạo 1 mảng buff kiểu byte có chiều dài bằng SqlDataReader r; với chiều dài của đối tượng f. Kế tiếp dùng hàm Read() để đọc nội dung của f vào mảng buff. Khởi tạo các biến trên trong contructor sau khi đã Tiếp theo tạo chuỗi truy vấn cmdstr để thêm thông gọi phương thức InitializeComponent() như bên dưới: tin vào cơ sở dữ liệu. Trong câu truy vấn trên, ta đã sử dụng các tham số hình thức @b, @a, @l chúng constr = “server=;database=bo lần lươt đại diện cho các trường dữ liệu book, author, oks;uid=sa;pwd = ”; logo trong bảng ‘bookinfo’. Điểm tiện lợi trong việc con = new SqlConnection ( constr ); sử dụng các tham số hình thức đó là khi cần thay cmdstr = “Select * from bookinfo”; đổi giá trị của một hay tất cả các trường ta không com = new SqlCommand ( cmdstr, con ); cần phải viết lại toàn bộ câu truy vấn mà chỉ cần dựa trên các tham số hình thức tương ứng vớ đó mà Bạn cũng nên bổ sung đoạn mã sau để mở cơ sở cập nhật lại dữ liệu. Thuộc tính Parameters của lớp dữ liệu và hiển thị thông tin về quyển sách đầu tiên: SqlCommand chứa tất cả các tham số được tham chiếu đến trong đối tượng SqlParameterCollection. Chúng con.Open( ); ta truyền giá trị cho những tham số này bằng cách gọi r = com.ExecuteReader( ); phương thức Add() của lớp SqlParameterCollection. if ( r.Read( ) ) Kế tiếp, chúng ta gọi phương thức ExecuteNonquery() { để thực thi câu truy vấn và gọi hàm Close() để đóng bookl.Text = r [ 0 ].ToString( ); 17
  16. authorl.Text = r [ 1 ].ToString( ); byte[ ] b = ( byte[ ] ) r [ 2 ]; private void next_Click ( object sender, MemoryStream st = new MemoryStream( ); EventArgs e ) st.Write ( b, 0, b.Length ); { Image i = Image.FromStream ( st ); if ( r.Read( ) ) img.Image = i ; { } bookl.Text = r [ 0 ].ToString( ) ; authorl.Text = r [ 1 ] .ToString( ) ; Sau khi mở được kết nối đến cơ sở dữ liệu, byte[ ] b = ( byte[ ] ) r [ 2 ] ; chúng ta lấy được một tham khảo của đối tượng MemoryStream st = new MemoryStream( ) ; SqlDataReader trong r bằng cách gọi phương thức st.Write ( b, 0, b.Length ) ; ExecuteReader(). Tiếp theo, ta gọi phương thức Image i = Image.FromStream ( st ) ; Read() để kiểm tra xem có tồn tại bản ghi (record) nào img.Image = i ; trong bảng ‘bookinfo’ không. Nếu có, chúng ta lấy } các thông tin về tên sách, tên tác giả hiển thị trong các } hộp textbox tương ứng. Bây giờ, chúng ta cần phải hiển thị hình trang bìa của sách. Đầu tiên chúng ta Đoạn mã xử lí bên trong hàm này cũng tương tự dùng 1 mảng b kiểu byte để lưu trữ hình cần hiển thị. như cách chúng ta lấy thông tin về quyển sách đầu Do không thể hiển thị nội dung của mảng b trong hộp tiên. Mỗi khi người dùng nhấn nút ‘Next’ thông tin Picture Box vì nó không có định dạng là về quyển sách tiếp theo trong cơ sở dữ liệu ‘book’ sẽ ình) nên ta cần chuyển nội dung mảng b sang được hiển thị. định dạng củ Để làm điều này,chúng ta tạo 1 đối tượng st của lớp MemoryStream. Lớp Tổng kết MemoryStream chỉ dùng để khởi tạo những đối tượng Hy vọng bài viết này sẽ giúp bạn hiểu được cách lưu trữ dữ liệu tạm thời trong bộ nhớ. Tiếp theo,ta thức ứng dụng tương tác với cơ sở dữ liệu cũng như dùng phương thức Write() của lớp MemoryStream để thủ thuật giúp bạn có thể lưu trữ trực tiếp hình ảnh vào ghi dữ liệu của mảng b vào luồng dữ liệu st. Sau đó, trong cơ sở dữ liệu. Tuy nhiên, cách làm này chỉ thích chúng ta tạ ằng cách dùng phương hợp để lưu trữ những hình ảnh nhỏ. Đối với những thức constructor của lớp Image có đối số tham khảo hình ảnh lớn thì phương pháp này trở nên không hiệu đến đối tượng của lớp MemoryStream. Kế đó chúng ta quả, bạn cần tìm hiểu những cách thức khác để lưu hiển thị hình ảnh trong hộp Picture Box. trữ; chẳng hạn như thay vì lưu nội dung hình ảnh, Ngay khi người dùng nhấn ‘Next’ hàm next_ chúng ta sẽ lưu trữ đường dẫn tương đối của nó. Chúc Click() được gọi để xử lí. Đoạn mã cho hàm next_ thành công. Click() như sau: ...tiếp theo trang 18 lý sự kiện WM_Help khi hộp thông báo gửi về, hoặc khi bạn nhấn nút help. Với cách thể hiện này, bạn có thể làm cho chương trình của mình thân thiện hơn, Tiếp tục vào nút Exit, bạn đưa lệnh: giúp đỡ người dùng tiện lợi hơn. Tuy nhiên công việc Private Sub Command2_Click() này không dễ lắm, đòi hỏi bạn phải có chút ít kiến End thức về SubclAs s, hook để xử lý công việc này. End Sub Đến đây bạn có thể lưu chương trình và bắt đầu Dĩ nhiên, bạn có thể thêm nút Help trong chương chạy thử. Hy vọng qua chương trình nhỏ này, các bạn trình, chỉ cần kết hợp giá trị dwStyle của biến mMsg sẽ có cái nhìn khác hơn về hàm API và hiểu được cách với giá trị MB_HELP Với câu lệnh như sau: ứng dụng nó. Trong bài tới tôi sẽ giới thiệu về các hàm mMsg.dwStyle=mMsg.dwStyle or MB_HELP API liên quan đến cửa sổ. Các bạn có thể liên hệ toàn soạn để chép mã nguồn của chương trình này. Chúc Và với tham số lpfnMsgBoxCallback bạn có thể các bạn thành công. cho nó trỏ tới địa chỉ của một hàm call back nhằm xử 18
  17. Lập trình ứng dụng với API Nguyễn Nhật Huân Chào các bạn, tôi nghĩ chắc các bạn đã từng nghe nhiên, hàm này mạnh hơn hàm MsgBox của Vb6 cung nói đến các hàm API (Application Programming cấp sẵn. Nhưng nó vẫn có nhược điểm là không hỗ Interface – Giao diện lập trình ứng dụng). Khi sử trợ nút Help, trong một số ứng dụng bạn vẫn thường dụng các hàm này, chúng ta có khả năng can thiệp hệ thấy có nút Help. Điều này có thể khắc phục một cách thống ở cấp cao hơn so với môi trường lập trình đang dễ dàng bằng cách dùng hàm MessageBoxIndirect. có, hoặc mở rộng khả năng một số chức năng của hệ Với hàm này, bạn có quyền thêm vào nút Help và thống. Trong bài này, để minh họa cho cách sử dụng thực hiện đoạn code để xử lý cho nút này đơn giản hàm API một cách đơn giản và dễ hiểu, tôi lấy ví dụ hơn hàm MessageBox. Mặc dù sự hơn thua không về hàm MessageBox. Hàm này có khai báo dạng API đáng kể nhưng nó thể hiện sức mạnh của hàm API. trong VB (bản Interprise vb6.0) như sau: Trong bài này tôi sẽ hướng dẫn cách dùng hàm Public Declare Function MessageBox Lib MessageBoxIndirect. “user32” AliAs “MessageBoxA” (ByVal hwnd As Để có thể bắt đầu, bạn khởi động VB 6.0, chạy Long, ByVal lpText As String, ByVal lpCaption As chương trình API Text Viewer. Khi khởi động chương String, ByVal wType As Long) As Long trình, vb sẽ tạo sẵn một form trống. Bạn chọn vào Với ý nghĩa các tham số như sau: form đó, nhấn chuột phải vào form, chọn view code. • hwnd : handle của cửa sổ gọi hàm này. Vào chương trình API Text Viewer. Rồi tìm khai báo • lpText: dòng chữ thông báo trên hộp thoại. và chèn vào form các khai báo sau: • lpCaption: dòng tiêu đề của hộp thông báo. Private Type MSGBOXPARAMS • wType: là kết hợp của các loại nút, icon hiện cbSize As Long trên hộp thông báo. hwndOwner As Long • WType: có thể là một trong các giá trị sau hInstance As Long (hoặc kết hợp): lpszText As String Các giá trị chỉ loại nút: lpszCaption As String Public Const MB_ABORTRETRYIGNORE dwStyle As Long = &H2& lpszIcon As String Public Const MB_OK = &H0& dwContextHelpId As Long Public Const MB_OKCANCEL = &H1& lpfnMsgBoxCallback As Long Public Const MB_RETRYCANCEL = &H5& dwLanguageId As Long Public Const MB_YESNO = &H4& End Type Public Const MB_YESNOCANCEL = &H3& Private Declare Function MessageBoxIndirect Lib “user32” AliAs “MessageBoxIndirectA” Các giá trị chỉ các loại Icon: (lpMsgBoxParams As MSGBOXPARAMS) As Public Const MB_ICONEXCLAMATION Long = &H30& Public Const MB_ICONAS TERISK = &H40& Private Const MB_ICONAS TERISK = &H40& Public Const MB_ICONHAND = &H10& Private Const MB_ICONEXCLAMATION Public Const MB_ICONINFORMATION = &H30& = MB_ICONAS TERISK Private Const MB_ICONHAND = &H10& Public Const MB_ICONMAS K = &HF0& Private Const MB_ICONINFORMATION Public Const MB_ICONMAS K = &HF0& = MB_ICONAS TERISK Public Const MB_ICONQUESTION = &H20& Private Const MB_ICONMAS K = &HF0& Public Const MB_ICONSTOP Private Const MB_ICONQUESTION = &H20& = MB_ICONHAND Private Const MB_ICONSTOP = MB_ICONHAND Bạn có thể kết hợp hai loại giá trị trên bằng toán tử Or rồi truyền giá trị này cho tham số wType. Tất Private Const MB_OK = &H0& 19
  18. Private Const MB_OKCANCEL = &H1& Nhấn đúp vào optBtn bạn sẽ được đưa vào thủ tục Private Const MB_YESNO = &H4& optBtn_click trong phần Coding: Private Const MB_YESNOCANCEL = &H3& Bạn đưa đoạn code sau đây vào: Private Const MB_RETRYCANCEL = &H5& Private Const MB_ABORTRETRYIGNORE Private Sub optBtn_Click(Index As Integer) = &H2& Select Case Index Private Const IDABORT = 3 Case 0 Private Const IDCANCEL = 2 BtnStl = MB_OK Private Const IDIGNORE = 5 Case 1 Private Const IDNO = 7 BtnStl = MB_YESNO Private Const IDOK = 1 Case 2 Private Const IDRETRY = 4 BtnStl = MB_OKCANCEL Private Const IDYES = 6 Case 3 BtnStl = MB_RETRYCANCEL Private Const MB_DEFBUTTON3 = &H200& Case 4 Private Const MB_DEFBUTTON1 = &H0& BtnStl = MB_YESNOCANCEL Private Const MB_DEFBUTTON2 = &H100& Case 5 Sau đó bạn thêm tiếp các biến sau: BtnStl = MB_ABORTRETRYIGNORE Dim mMsg As MSGBOXPARAMS End Select Dim IcoStl As Long End Sub Dim BtnStl As Long Trở về form chính, nhấn đúp vào phần chọn Icon, Trên form bạn thiết kế như sau: bạn sẽ lại được đưa vào phần thủ tục optIco_click: Bạn đưa đoạn code sau đây vào: Private Sub optIco_Click(Index As Integer) Select Case Index Case 0 IcoStl = MB_ICONEXCLAMATION Case 1 IcoStl = MB_ICONQUESTION Case 2 IcoStl = MB_ICONINFORMATION Case 3 IcoStl = MB_ICONSTOP Case 4 IcoStl = MB_ICONAS TERISK Case 5 IcoStl = MB_ICONMAS K End Select End Sub Nhấn đúp lên nút lệnh Generate bạn sẽ được đưa vào phần Command1_click: Bạn đưa đoạn code sau đây vào: Private Sub Command1_Click() With mMsg .cbSize = Len(mMsg) Phần lựa chọn cho các button bạn đặt tên cho .hwndOwner = Me.hWnd các Option là optBtn, tất cả 6 button đều cùng tên và .hInstance = App.hInstance bạn sẽ được một mảng đối tựợng, dĩ nhiên thuộc tính .dwStyle = BtnStl Or IcoStl Index sẽ chỉ số thứ tự phần tử bắt đầu từ 0. .lpszCaption = Text1.Text Tương tự cho phần Icon. Bạn đặt tên là optIcon, ở .lpszText = Text2.Text mảng này tương tự optBtn. Riêng hai nút lệnh bạn để End With nguyên. MessageBoxIndirect mMsg Trong phần Index của cả optBtn và optIco bạn End Sub thiết lập từ 0 đến 5 theo chiều từ trái qua, từ trên xuống. Xem tiếp trang 16 Ví dụ: Ok Only =0, Yes and No = 1. 20
  19. Nhập môn Java với JDBC và MySQL (Phần 1) Phạm Công Định (JavaVietnam.org) JDBC là gì? JDBC là viết tắt của “Java lớp JDBC, các giao diện và các lỗi DataBase Connectivity”. Nó là một Tại sao lại dùng JDBC? ngoại lệ quan trọng trong gói java. API (Application Programming JDBC tồn tại là để giúp các sql: Interface) có chứa một tập hợp các nhà phát triển Java tạo nên các ứng DriverManager - Nạp các lớp, các giao diện Java và các thông dụng truy xuất cơ sở dữ liệu mà JDBC driver vào trong bộ nhớ. Có báo lỗi ngoại lệ nằm trong cùng một không cần phải học và sử dụng các thể sử dụng nó để mở các kết nối tới đặc tả mà theo đó cả các công ty sản API độc quyền do các công ty sản một nguồn dữ liệu. xuất JDBC driver cũng như các nhà xuất phần mềm khác nhau bên thứ Connection - Biểu thị một kết nối phát triển JDBC đều phải tuân thủ ba cung cấp. Bạn chỉ cần học JDBC đến một nguồn dữ liệu. Được dùng chặt chẽ khi phát triển ứng dụng. và sau đó bạn sẽ được đảm bảo rằng để tạo ra các đối tượng Statement, JDBC là một chuẩn truy xuất cơ bạn sẽ có thể phát triển nên các ứng PreparedStatement và sở dữ liệu rất phổ biến. Các RDBMS dụng truy cập cơ sở dữ liệu có khả CallableStatement. (Relational Database Management năng truy cập đến các RDBMS khác Statement - Biểu diễn một lệnh Systems – Hệ quản trị cơ sở dữ nhau bằng cách sử dụng các JDBC SQL tĩnh. Có thể sử dụng nó để thu liệu quan hệ) hay các nhà sản xuất driver khác nhau. về đối tượng ResultSet. phần mềm bên thứ ba phát triển các PreparedStatement - Một giải driver cho Java đều cần tuân thủ Kiến trúc JDBC pháp thay thế hoạt động tốt hơn đối chặt chẽ đặc tả JDBC. Các nhà phát Trong Java có 2 lớp chủ yếu tượng Statement, thực thi một triển khác sử dụng các driver này để chịu trách nhiệm về thiết lập kết nối câu lệnh SQL đã được biên dịch phát triển nên các ứng dụng có truy đến một cơ sở dữ liệu. Lớp đầu tiên trước. cập cơ sở dữ liệu: ví dụ, bạn dùng là DriverManager. Đó là một trong CallableStatement – biểu diễn ConnectorJ JDBC driver để truy cập rất ít các lớp thực sự do JDBC API một thủ tục được lưu trữ. Có thể cơ sở dữ liệu MySQL. Vì các driver cung cấp. DriverManager chịu trách được sử dụng để thực thi các thủ tục này tuân thủ chặt chẽ đặc tả JDBC nhiệm quản lý một nhóm (pool) các được lưu trữ trong một RDBMS có nên các nhà phát triển ứng dụng driver đã đăng kí, mà thực chất là hỗ trợ chúng. JDBC có thể thay thế driver trong là trừu tượng hóa các chi tiết về ResultSet - biểu diễn một tập ứng dụng của họ bằng một cái tốt việc sử dụng một driver, cho nên kết quả trong cơ sở dữ liệu tạo ra hơn mà không cần phải viết lại ứng lập trình viên không cần phải làm bởi việc sử dụng một câu lệnh SQL dụng của họ. Nếu họ đã sử dụng một việc trực tiếp với driver đó. Lớp thứ là SELECT. số API độc quyền do một số nhà sản 2 là một lớp JDBC Driver thực sự. SQLException - một lớp xử lý xuất RDBMS nào đó cung cấp thì Nó được cung cấp bởi các nhà sản lỗi ngoại lệ chứa các lỗi truy cập cơ họ sẽ không thể nào thay đổi driver xuất phần mềm độc lập. Lớp JDBC sở dữ liệu. và/hoặc cơ sở dữ liệu mà không viết Driver chịu trách nhiệm thiết lập lại ứng dụng hoàn toàn. đường kết nối cơ sở dữ liệu và xử lý Gói thứ hai, javax.sql là một bộ tất cả các giao tiếp với cơ sở dữ liệu phận của J2SE 1.4 và J2EE 1.3. Nó Ai phát triển đặc tả JDBC? đó. Các JDBC driver chia thành 4 bổ sung các tính năng sau đây vào SUN chuẩn bị và duy trì đặc tả kiểu khác nhau. JDBC để hỗ trợ thêm cho các tính JDBC. Bởi JDBC chỉ là một đặc tả Chúng ta sẽ chia nó ra làm 2 năng đã có trong gói java.sql: (đề xuất cách viết và sử dụng các phần: DataSource - Trừu tượng JDBC driver), nên các công ty sản • JDBC API (các gói java.sql hóa một nguồn dữ liệu. Đối xuất phần mềm bên thứ ba sẽ phát & javax.sql ) tượng này có thể sử dụng thế cho triển các JDBC driver tuân thủ chặt • Các kiểu JDBC Driver DriverManager để tạo ra một chẽ đặc tả này. Các nhà phát triển cách có hiệu quả các kết nối cơ sở JDBC sau đó sẽ sử dụng các driver JDBC API dữ liệu (có khả năng sử dụng việc này để truy cập vào các nguồn dữ JDBC API có sẵn trong các gói chứa/phân chia các đường kết nối liệu. java.sql và javax.sql. Sau đây là các ngầm). 21
  20. Tạo sẵn cơ chế phân chia đường kết nối (built-in connection pooling). XADataSource, XAConnection – Cho phép/Hỗ trợ các giao dịch phân phối. RowSet – Nó mở rộng giao diện ResultSet để tăng thêm sự hỗ trợ đối với các tập kết nối bị ngắt. Các loại JDBC Driver Có 4 loại JDBC driver. Thông dụng nhất và cũng là hiệu quả nhất là loại 4. Sau đây là mô tả: JDBC Driver loại 1- Chúng là các trình điều khiển Hình 1. Hộp thoại điều chỉnh biến môi trường Trong cầu nối JDBC-ODBC. Chúng ủy nhiệm công việc truy mục System của Control Panel trong Windows 2k và cập dữ liệu cho ODBC API. Chúng là trình điều khiển XP. chậm nhất trong số còn lại. SUN cung cấp một phần mềm trình điều khiển JDBC/ODBC. JDBC Driver loại 2 – Chúng chủ yếu sử dụng API mã nền để truy cập dữ liệu và cung cấp các lớp bao Java để có thể được gọi ra bằng cách dùng các JDBC driver. JDBC Driver loại 3 – Chúng được viết thuần bằng Java và sử dụng giao thức Net độc lập nhà sản xuất để truy cập đến trình theo dõi từ xa độc lập nhà sản xuất. Trình theo dõi này đến lượt nó lại ánh xạ các lời gọi độc lập nhà sản xuất này vào các lời gọi phụ thuộc nhà sản xuất. Bước đặc biệt này đã làm tăng độ phức tạp và Hình 2. Điều chỉnh biến hệ thống trong Windows giảm tính hiệu quả trong truy cập cơ sở dữ liệu. JDBC Driver loại 4 – Chúng được viết thuần túy Sau khi bạn đã đặt đường dẫn đến Connector/J vào bằng Java và là loại hiệu quả nhất. Chúng cho phép kết biến môi trường MYSQL_DRIVER thì bạn đã có thể nối trực tiếp vào cơ sở dữ liệu, cung cấp kết quả tối ưu yên tâm là JDBC driver của MySQL đã được cài đặt và cho phép lập trình viên thực hiện các chức năng tùy xong. thuộc vào cơ sở dữ liệu cụ thể. Điều này đã tạo ra tính cơ động cao nhất là khi bạn cần thay đổi cơ sở dữ liệu Kiểm tra xem Connector/J đã hoạt động chưa? bên dưới một ứng dụng. Loại driver này thường được Chúng ta tạo ra một chương trình Java nhỏ để kiểm dùng cho các ứng dụng phân tán cao. tra xem chúng ta đã cài đặt đúng JDBC driver của SUN khuyến cáo sử dụng và phát triển các trình MySQL chưa. Nếu chương trình chạy thành công thì điều khiển loại 4 trong các ứng dụng. nghĩa là trình điều khiển JDBC đã sẵn sàng cho các tác vụ phức tạp hơn. Bạn hãy tạo ra mộ Cài đặt MySQL với đoạn mã sau: MySQL là hệ quản trị cơ sở dữ liệu mã nguồn mở phổ biến nhất thế giới và được các nhà phát triển rất ưa import java.sql.*; chuộng trong quá trình phát triển ứng dụng. MySQL public class Connect miễn phí hoàn toàn nên bạn có thể tải về MySQL từ { trang chủ www.mysql.com. MySQL có nhiều phiên bản public static void main (String[] args) cho các hệ điều hành khác nhau: phiên bản Win32 cho { các hệ điều hành dòng Windows, Linux, Mac OSX... Connection conn = null; try Cài đặt Connector/J - JDBC Driver của MySQL { JDBC Driver của MySQL có thể lấy về ở địa chỉ http:// String userName = “root”; www.mysql.com/downloads/api-jdbc.html . File bạn String password = “localhost”; tải về sẽ là mộ ặc .gz. Sau khi giải nén bạn sẽ String url = “jdbc:mysql://127.0.0.1:3306/mysql”; có mộ ó tên tương tự như sau: mysql-connector- Class.forName (“com.mysql.jdbc.Driver”) java-3.0.9-stable-bin.jar. Hãy ché ày vào thư mục .newInstance (); %JAVA_HOME%/jre/lib/ext trên hệ thống của bạn. Ví conn = DriverManager.getConnection (url, dụ C:\j2sdk1.4.2\jre\lib\ext. userName, password); Bạn cũng cần đưa đường dẫn đế ày vào System.out.println (“Da ket noi CSDL”); biến môi trường MYSQL_DRIVER của bạn. } catch (Exception e) 22
Đồng bộ tài khoản