Trong các bài trước, chúng ta làm quen với rollout và một vài thành phần giao diện cơ bản của rollout như nút bấm – button, hộp văn bản – edittext, hay bộ chọn giá trị – spinner. Các thành phần này giúp người dùng có thể tương tác với script một cách thuận tiện thông qua giao diện đồ họa, mà không cần phải thao tác với các dòng lệnh khô khan và dài dòng.
Trong bài viết này, chúng ta sẽ tìm hiểu thêm về các thành phần giao diện khác, giúp bạn có nhiều lựa chọn hơn khi xây dựng giao diện script. Tôi cũng sẽ hướng dẫn để bạn đọc có thể tự tra cứu những thuộc tính nâng cao trong sách hướng dẫn MAXScript của 3ds Max.
MỤC LỤC
Tổng quan
Có nhiều loại thành phần giao diện người dùng mà bạn có thể chọn để xây dựng một rollout trong MAXScript. Tất cả đều sử dụng cùng một cú pháp chung:
<item_type> <name> [ <label_string> ] [ <parameters> ]
Trong đó:
- <item_type>: loại thành phần giao diện. Ví dụ: button, edittext, slider, combobox… Lưu ý rằng <item_type> là thứ luôn được khai báo đầu tiên khi tạo một thành phần giao diện, và từ khóa này sẽ được in đậm nếu bạn viết đúng chính tả.
- <name>: là tên biến cục bộ (local) của thành phần giao diện. Ví dụ: ui_buttonTest. Đây là thứ không hiển thị trong giao diện người dùng, nó chỉ được sử dụng ngầm để code có thể tương tác với thành phần giao diện.
- <label_string> (tùy chọn): được sử dụng như một tiêu đề hoặc nội dung văn bản tùy thuộc vào loại điều khiển. Đây là thứ sẽ hiển thị ra giao diện người dùng. Lưu ý giá trị này là một string, tức là nó luôn được viết trong ngoặc kép. Ví dụ “Nút bấm”.
- <parameters> (tùy chọn): là các tham số để thiết lập tùy chọn hoặc ảnh hưởng đến bố cục của thành phần giao diện. Ví dụ: căn trái phải, trên dưới, bật tắt, số lượng items…
button ui_Test "Kiểm tra" align:center
Câu lệnh trên sẽ khai báo ra một nút bấm button, tên biến cục bộ là ui_Test, có tựa đề hiển thị là “Test”, và được căn giữa rollout.
Chú ý về cú pháp
Các thành phần trong cú pháp chỉ cần ngăn với nhau bởi một dấu cách, và quan trọng là phải được viết đúng thứ tự. Khi khai báo, với item_type, name, label_string, MAXScript sẽ chỉ nhận một giá trị duy nhất, tức là một thành phần giao diện chỉ có 1 kiểu – 1 tên biến – 1 tên hiển thị. Còn riêng parameters, MAXScript có thể nhận nhiều thông số khác nhau, và chúng không bắt buộc phải viết theo một thứ tự nào cả. Ví dụ:
button ui_Test "Kiểm tra" align:center enabled:false
sẽ tương đương với
button ui_Test "Kiểm tra" enabled:false align:center
Hầu hết các thuộc tính này có thể thay đổi trong quá trình sử dụng script. Một số thuộc tính liên quan đến giao diện thì không thể thay đổi, và phải khai báo chính xác từ đầu. Chúng ta sẽ tìm hiểu kỹ hơn ở mục tiếp theo.
Các loại thành phần giao diện
MAXScript có tổng cộng 26 loại thành phần giao diện. Trong đó có 2 thành phần là popUpMenu và timer không hiển thị trực tiếp trên rollout. Chúng là: angle, bitmap, button, checkbox, checkbutton, colorpicker, combobox, curvecontrol, dropdownlist, edittext, groupBox, hyperlink, imgTag, label, listbox, mapbutton, materialbutton, multilistbox, pickbutton, popUpMenu, progressbar, radiobuttons, slider, spinner, SubRollout, timer.
Tất cả được liệt kê và ghi chú chi tiết trong trang Rollout User-Interface Controls Types của Autodesk.
Hãy copy code dưới đây vào trong MAXScript Editor, và chạy thử (Evaluate) để tạo ra bảng trên. Hãy tương tác thử với các thành phần giao diện để hiểu hơn về cách hoạt động của nó.
try (destroyDialog allControls) catch() rollout allControls "User Interface Controls" ( angle theAngle "Angle" width:80 across:2 degrees:45 align:#left slider theSlider "Slider:" orient:#vertical spinner theSpinner "Spinner:" group "Group" ( button theButton "Button" across:2 width:80 align:#left checkbutton theCheckbutton "Checkbutton" width:80 align:#right mapbutton theMapButton "Map Button" width:80 across:2 align:#left materialbutton theMatButton "Material Button" width:80 align:#right pickbutton thePickbutton "Pickbutton:" width:80 ) checkbox theCheckbox "Checkbox" across:2 offset:[0,2] colorpicker theColorpicker "Colorpicker:" listbox theListbox "Listbox:" items:#("Item 1","Item 2") height:3 width:80 across:2 multilistbox theMLBox "Multilistbox:" items:#("Item 1","Item 2") height:3 width:80 dropdownlist theDDL "DropDownList:" items:#("Item 1","Item 2") width:80 across:2 combobox theCombobox "Combobox:" items:#("Item 1","Item 2") height:3 width:80 edittext theEdittext "Edittext:" hyperlink theHyperlink "Hyperlink" url:"http://www.autodesk.com" color:red across:2 offset:[10,20] label theLabel "Label" offset:[0,20] groupBox theGroupbox "Groupbox:" height:40 offset:[0,-40] width:174 progressbar theProgressbar "Progressbar:" value:50 radiobuttons theRadiobuttons labels:#("Option 1","Option 2") bitmap theBitmap "Bitmap" width:80 height:50 offset:[0,0] bitmap:(bitmap 80 50 color:red) align:#left across:2 imgTag theImgTag "Bitmap" width:80 height:50 offset:[0,0] bitmap:(bitmap 80 50 color:green) align:#right SubRollout theSubrollout "Subrollout" height:50 curvecontrol theCurvecontrol "Curvecontrol:" height:150 ) createDialog allControls 200 800
Các thuộc tính chung
Các thành phần giao diện này có chung một số thuộc tính <parameters>. Chúng được mô tả trong trang Rollout User-Interface Controls Common Properties và Rollout User-Interface Controls Common Layout Parameters của Autodesk.
Các thuộc tính này bao gồm:
- caption / text: ý nghĩa của thuộc tính này thay đổi tùy theo loại thành phần giao diện cụ thể. Thông thường, nó là phần ‘chữ’ của giao diện, ví dụ như tiêu đề nút bấm, hãy tiêu đề phía trên danh sách… Hai thuộc tính này thường có giá trị tương đương nhau, chỉ trừ trong edittext và combobox.
- enabled: kích hoạt (true) / vô hiệu hóa (false) thành phần giao diện người dùng.
- align: #left, #center, hoặc #right. Dùng để căn lề trái, phải hoặc giữa cho thành phần giao diện.
- offset: được biểu diễn dưới dạng [x,y]. Dùng để dịch chuyển giao diện người dùng một khoảng bằng x pixel chiều ngang, và y pixel theo chiều dọc. x và y có thể nhận giá trị âm. Đây là thứ bạn sẽ phải thường xuyên sử dụng nếu muốn tạo một giao diện gọn gàng và đẹp mắt.
- width / height: kích thước của thành phần giao diện theo chiều rộng và chiều cao, thường được tính bằng pixel. Lưu ý rằng với các giao diện dạng danh sách như listBox, dropdownlist, comboBox, height được tính bằng số dòng mà nó hiển thị. Bạn không thể đặt height cho spinner và slider, nó sẽ luôn có chiều cao mặc định.
- across: thông thường, giao diện của script sẽ được sắp xếp lần lượt từ trên xuống dưới, với 01 thành phần giao diện chiếm 01 dòng trong giao diện. Bạn có thể thay đổi điều này bằng thuộc tính across để xếp nhiều thuộc tính vào cùng một dòng. Thuộc tính across chỉ cần khai báo ở thành phần giao diện đầu tiên trong dòng đó.
- pos: được biểu diễn dưới dạng [x,y]. Dùng để chỉ định vị trí chính xác của thành phần giao diện, với góc [0,0] ở góc trên cùng bên trái. Về lý thuyết, bạn sẽ chỉ cần tham số này để sắp xếp tất cả các thành phần giao diện theo ý muốn, tuy nhiên điều ấy rất cực khổ và chậm chạp. Tôi khuyên bạn không bao giờ nên sử dụng thông số này.
Nhìn chung, MAXScript không hỗ trợ nhiều tham số về tùy biến giao diện, và bạn chỉ có thể dùng những gì sẵn có. Nếu muốn tạo các giao diện hấp dẫn hơn, bạn sẽ cần phải sử dụng dotNET trong MAXScript, một lĩnh vực khá phức tạp với người mới.
Các thuộc tính riêng
Như đã nói ở trên, mỗi thành phần giao diện sẽ có một số thuộc tính riêng dành cho nó. Và nó sẽ cực kỳ dài dòng nếu muốn liệt kê hết chúng ở đây. Cách nhanh nhất để biết được những thuộc tính này là tra cứu chúng trong tài liệu của Autodesk.
Trong bài viết này, tôi sẽ hướng dẫn bạn cách tra cứu và sử dụng chúng trong code của mình. Nhìn chung, tài liệu hướng dẫn về một thành phần giao diện sẽ gồm 4 phần:
- syntax: cú pháp để khởi tạo.
- parameters: các tham số trong cú pháp (xem lại phần tổng quan).
- properties: các thuộc tính của thành phần giao diện.
- events: các sự kiện khi tương tác với thành phần giao diện.
Ví dụ, với tài liệu hướng dẫn về nút bấm, chúng ta sẽ có syntax như sau:
button <name> [<caption>] [images:<image_spec_array>] [toolTip:<string>] [border:<boolean>] [iconName:<filename> iconSize:<point2>]
Những phần trong dấu ngoặc vuông ‘[ ]’ được hiểu là “tùy chọn”. Tức là nó có thể có hoặc không. Những phần nằm trong dấu ‘< >’ được hiểu là tham số, tức là bạn phải thay thế nó bằng từ khóa hoặc giá trị của bạn.
Ví dụ, một nút bấm có thể khai báo như sau:
button theBorderlessButton "I am a button, too!" border:false
<caption> tôi đã thay bằng “I am a button, too!”, và tham số <boolean> trong [border:<boolean>] tôi đã thay bằng false.
Về lý thuyết, parameters và properties có thể hiểu có ý nghĩa gần tương đương nhau. Nó khác nhau ở chỗ:
- parameters là các giá trị được thiết lập khi bạn khởi tạo một UI Control. Tham số được dùng khi bạn tạo một phần tử UI (giao diện người dùng) và định nghĩa hành vi hoặc giao diện ban đầu của nó.
- properties là các thuộc tính có thể được truy cập và thay đổi sau khi UI Control đã được tạo ra. Thuộc tính cho phép bạn truy xuất hoặc chỉnh sửa trạng thái hiện tại của phần tử giao diện. Việc truy xuất các giá trị properties có ý nghĩa quan trọng trong một vài trường hợp, ví dụ khi đọc giá trị người dùng nhập vào để tiếp tục xử lý code.
Về lý thuyết, parameters chỉ được khai báo một lần, và không thể thay đổi sau khi UI Control đã tạo ra. Tuy nhiên rất nhiều parameters và properties có chung một từ khóa. Ví dụ, với button, các parameters riêng của nó khi khai báo là: images, toolTip, border, iconName, iconSize, còn các properties của nó là images, tooltip, width, height (lưu ý button cũng có width, height trong parameters). Ta thấy tooltip vừa là parameters vừa là properties, tức là ta có thể dùng nó khi khai báo và cả trong code.
Events là phần cần chú ý nhất, bởi nó chứa các sự kiện khi người dùng tương tác với thành phần giao diện. Trong tài liệu, phần này sẽ được trình bày theo dạng:
on <thành phần giao diện> <hành động> do <code của bạn> hoặc on <thành phần giao diện> <hành động> <tham số> do <code của bạn>
Khi bạn xem tài liệu về một thành phần giao diện, chủ yếu bạn sẽ xem về từ khóa <hành động>. Ví dụ, với button, sẽ có 2 hành động là:
- on <button> pressed do <expr>
- on <button> rightclick do <expr>
Hai hành động này tương ứng với thao tác bấm chuột trái và chuột phải vào nút. Hãy xem xét code sau:
rollout test "TEST" ( button test_button "TEST" width:40 height:40 on test_button pressed do test_button.width += 15 on test_button rightClick do test_button.width -= 15 ) CreateDialog test
Khi tôi bấm chuột trái vào nút này, chiều rộng của nút sẽ tăng lên 15 pixel. Ngược lại khi tôi bấm chuột phải vào nút này, chiều rộng của nó sẽ giảm 15 pixel. Các giao diện người dùng khác nhau sẽ có các event khác nhau.
Một số thành phần giao diện sẽ có <tham số> trong event. Ví dụ, với checkbutton, nó sẽ có một event như sau:
- on <checkbutton> changed <arg> do <expr>
<arg> là tham số nhận giá trị trạng thái của checkbutton sau khi thay đổi. Tham số này sẽ có giá trị tùy thuộc vào loại UI Control. Như trường hợp của checkbutton, giá trị này sẽ là true hoặc false, thể hiện trạng thái của nút bấm sau khi người dùng nhấn vào nó:
checkbutton myCheck "Enable" on myCheck changed state do ( if state == true then print "Checkbutton is checked" else print "Checkbutton is unchecked" )
Trong ví dụ trên:
- state là tham số <arg>, nó sẽ nhận giá trị true hoặcfalse tùy thuộc vào trạng thái của myCheck sau khi thay đổi.
- Dựa vào giá trị của state, khối lệnh bên trong sẽ thực hiện hành động tương ứng.
Bài tập
Dựa vào kiến thức trong phần này, hãy chỉnh sửa và thiết kế lại giao diện của các script mà chúng ta đã viết trong phần 9 và phần 10 của seri bài viết. Bổ sung thêm các thành phần giao diện mới nếu có thể. Chúc các bạn thành công!