2009-01-23 15 views
8

Cách ngây thơ viết xây dựng một thực đơn trong một ứng dụng Java Swing là để làm một cái gì đó như:cách chính xác để sử dụng hành động để tạo các menu, thanh công cụ, và các thành phần khác trong Java

JMenu fileMenu = new JMenu("File"); 
JMenuItem openItem = new JMenuItem("Open..."); 
openItem.addActionListener(new ActionListener() { /* action listener stuff */ }) 
fileMenu.addMenuItem(openItem); 

Một nhà phát triển có kinh nghiệm hơn sẽ nhận ra rằng các hành động có thể được truy cập thông qua nhiều cơ chế khác nhau - các menu, các nút trên thanh công cụ, thậm chí có thể là các luồng công việc khác trong hệ thống. người đó có nhiều khả năng để viết:

Action openAction = new AbstractAction(); 
openAction.setName("Open..."); 
openAction.addActionListener(new ActionListener() { /* action listener stuff */ }) 
... 
JMenuItem openItem = new JMenuItem(openAction); 

Câu hỏi của tôi là, cách tốt nhất để quản lý các hành động đối tượng để họ có thể được sử dụng trên các menu, thanh công cụ, vv là những gì?

  • Tạo lớp nhà máy trả về các hành động cụ thể?
  • Khai báo tất cả các hành động là private static final Action trong một số lớp tiện ích?
  • Tận dụng lợi thế của khung ứng dụng Java?
  • Cái gì khác?
+0

Bản sao của http://stackoverflow.com/questions/448179/organizing-actions-in-a-swing-application#448195, như được chỉ ra bởi Dave Ray. –

Trả lời

4

Các ứng dụng mà tôi đã phát triển cần sử dụng các hành động tương tự trên các menu, thanh công cụ và các nút khác đã được thực hiện bằng cách sử dụng Khung ứng dụng Swing.

Swing Application Framework

khuôn khổ này sẽ cho phép bạn có một tập tin tài nguyên, nơi bạn có thể xác định tất cả văn bản trình đơn, tooltips, và các biểu tượng. Tôi nghĩ rằng các biểu tượng là chìa khóa, bạn không phải tự tải chúng. Ngoài ra, nếu bạn có bất kỳ hành động nào mà bạn cần bật/tắt, bạn có thể ghi đè phương thức để kiểm soát trạng thái của nó.

Trang web đáng để đọc.

0

Action là sự trừu tượng xấu - ActionListener được hàn với người nghèo Map.

Chắc chắn không gán chúng cho static vì chúng có thể thay đổi và cũng cần một số ngữ cảnh để hoạt động hữu ích.

Lời khuyên chung của tôi về lập trình GUI là cần lưu ý rằng nó thực sự giống với bất kỳ lĩnh vực lập trình nào khác. Thực hiện theo các thực hành tốt thông thường. Đáng chú ý là việc phân lớp, tách mối quan tâm, sử dụng (thực hiện) thừa kế hiếm khi và không viết một quả bóng bùn lớn.

1

Bạn có thể nhóm tất cả AbstractAction của mình bằng cách sử dụng Bản đồ chuyên dụng javax.swing.actionmap. Xem http://java.sun.com/javase/6/docs/api/javax/swing/ActionMap.html

Hơn nữa, mỗi JComponent có một hành động nội bộMap (getActionMap()).

class MyComponent 
extends JPanel 
{ 
public static final String ACTION_NAME1="my.action.1"; 

public MyComponent() 
{ 
AbstractAction action= new AbstractAction() { ... } 
getActionMap().put(ACTION_NAME1,action); 
... 

menu.add(getActionMap().get(ACTION_NAME1)); 
} 

} 

Hy vọng nó giúp

0

Xem thêm this question, đó là khá nhiều giống như những gì bạn đang yêu cầu.

0

Chỉnh sửa: Tôi có cảm giác mọi người không tin điều này là có thể hoặc dễ dàng, vì vậy tôi đã làm - mất khoảng một giờ từ đầu - có thể mất 40 phút nếu tôi chỉ sử dụng một phương pháp một mục tiêu thay vì phản ánh nó ra để tách các phương thức cho từng mục menu.

Đây là số Tested source code. Nó hoạt động, nhưng là một phương pháp lớn và xấu xí - refactor nó nếu bạn sử dụng nó. Tôi có thể sửa chữa nó một chút trong vài ngày tới, tôi luôn muốn có một bản sao này để tiếp tục sử dụng lại.

--- bài đăng gốc

Trước hết, hãy nhớ tách mã của bạn khỏi dữ liệu. Điều đó có nghĩa là bạn KHÔNG BAO GIỜ nên nhập:

new Menu("File..."); 

Chuỗi "Tệp ..." là dữ liệu. Nếu bạn bắt đầu suy nghĩ theo cách này, bạn sẽ thấy rằng câu hỏi của bạn tự trả lời.

Trước tiên, bạn cần tạo một số dữ liệu. Bạn cần nhận "Tệp ..." và "Lưu" vào các menu. Tôi thường bắt đầu với một mảng chuỗi (mà bạn có thể dễ dàng di chuyển đến một tệp)

new String[]{"File...","+Save","Load"...} 

Đây là một trong những mẫu đơn giản mà tôi đã bắt đầu. Sau đó, bạn có thể phân tích dấu + và sử dụng nó để có nghĩa là "Thả xuống một cấp trong menu khi bạn thêm một cấp độ này"

Đây chỉ là quy ước ngớ ngẩn, tự sáng chế nếu bạn không thích.

Bước tiếp theo là ràng buộc để mã chạy. Bạn có thể có tất cả họ gọi cùng một phương pháp, nhưng những gì một nỗi đau trong ass (Giant chuyển tuyên bố). Một khả năng là sử dụng sự phản chiếu để ràng buộc tên phương thức trong khi bạn đang đọc dữ liệu. Dưới đây là một giải pháp (một lần nữa nó có thể không phù hợp với thị hiếu của bạn)

new String[]{"File...[fileMenu]","+Save[saveMenu]","Load[loadMenu]"...} 

Sau đó, bạn phân tích ra các điều trong dấu ngoặc vuông, phản tư móc nó lên đến một phương pháp trong lớp hiện tại của bạn và bạn đang thiết lập.

Có một sự cám dỗ mà tôi luôn luôn có vào thời điểm này và tôi đã học cách chiến đấu vì nó KHÔNG BAO GIỜ làm việc. Sự cám dỗ là sử dụng tập dữ liệu đầu tiên ("File ...") và thao tác nó để phù hợp với một số mẫu và tự động liên kết với mã của bạn (trong trường hợp này, xóa tất cả các ký tự không phải alpha, làm cho chữ cái đầu tiên thấp hơn và thêm "Menu" để lấy tên phương thức chính xác). Hãy thử điều này, nó rất hấp dẫn và có vẻ bóng bẩy, nhưng sẵn sàng từ bỏ nó khi nó không đáp ứng một số nhu cầu (chẳng hạn như hai mục menu có cùng tên chính xác trong các menu phụ khác nhau).

Một cách khác là nếu ngôn ngữ của bạn hỗ trợ đóng cửa, sau đó bạn có thể thực sự tạo tên tập tin và đóng cửa ở cùng một chỗ ..

Dù sao, một khi bạn bắt đầu viết mã như thế này, bạn sẽ thấy rằng TẤT CẢ của bạn xây dựng menu là trong một phương pháp 10 dòng duy nhất và bạn có thể thay đổi nó cho phù hợp với nhu cầu của bạn. Tôi đã có một trường hợp mà tôi đã phải thay đổi một bộ các menu để phân cấp nút và tôi đã làm nó trong 2 phút.

Cuối cùng, bạn có thể sử dụng mẫu này để thiết lập các đối tượng hành động dễ dàng và thay đổi cách dễ dàng sử dụng chúng (ở một vị trí, một dòng mã), vì vậy bạn thử nghiệm chúng. Có nhiều cách để sử dụng chúng, nhưng nếu bạn không làm những gì tôi đề xuất ở đây, bạn sẽ phải thực hiện lại trên mọi mục menu cho mọi thay đổi, điều này thực sự gây phiền nhiễu - sau một thay đổi duy nhất bạn sẽ lãng phí nhiều thời gian hơn nếu bạn vừa mới triển khai giải pháp dựa trên dữ liệu ngay từ đầu.

Điều này thực sự không phải là mã khó, nên mất khoảng một hoặc hai giờ thì bạn không bao giờ phải viết Menu mới ("... một lần nữa. Hãy tin tôi đi, loại dụng cụ này chỉ là luôn luôn đáng giá trị.

chỉnh sửa:

Tôi chỉ là luôn luôn mã dữ liệu điều khiển những ngày này.Thông thường tôi sẽ thử nghiệm một vài cách bình thường, nhận ra mẫu và refactor - và nếu bạn tái cấu trúc đúng cách, dữ liệu luôn luôn về các yếu tố và những gì bạn còn lại là đẹp, chặt chẽ và có thể duy trì.

Tôi có thể làm những gì tôi đề xuất ở trên trong vòng chưa đầy 1/2 phút (có thể là một giờ để làm phiên bản phản chiếu). Điều này gần như luôn luôn chỉ miễn là nó sẽ làm gì để sử dụng phiên bản chưa được kích hoạt, và từ đó trở đi, số tiền tiết kiệm của bạn nhân lên cho mọi thay đổi.

Điều này rất giống với những gì mọi người thích về ruby, ngoại trừ ruby ​​dường như chèn nhiều dữ liệu hơn vào mã của họ (điều này làm cho dữ liệu của bạn trở nên khó khăn hơn rất nhiều). quốc tế hóa).

Hmm, tôi có đề cập rằng nếu bạn giỏi trích xuất dữ liệu của mình như thế này thì i18n hầu như miễn phí?

Tôi khuyên bạn nên thử một lần nào đó và xem suy nghĩ của bạn. Việc nhúng điều khiển trong các chuỗi là không cần thiết nếu nó làm bạn khó chịu. Tôi có xu hướng sử dụng mảng chuỗi/đối tượng chỉ vì chúng thực sự dễ nhập, vẫn còn trong tệp khi bạn đang mã hóa và không quan trọng để ngoại tác hóa sau này, nhưng nếu bạn thích tệp YML hoặc XML hoặc thuộc tính, hãy sử dụng bất cứ điều gì bạn thấy thoải mái với - chỉ cần trừu tượng dữ liệu của bạn từ mã của bạn!

+0

Bạn thực sự mã GUI của bạn như thế này? : | –

+0

GUI của bạn có thể được tính toán đầy đủ như thế nào mà không bị dữ liệu điều khiển? Có quá nhiều sự lặp lại. –

+0

Bằng cách này, String.split (được sử dụng để StringTokenizer) có thể giúp rất nhiều với phân tích cú pháp các mục này. Một chuỗi như "File ... | * | fileMethod" có thể được phân tích cú pháp trong một giây (* có nghĩa là "cấp cao nhất" trong trường hợp này - bạn có thể tạo "ngôn ngữ" của bạn khi đang di chuyển - rất giống với Ruby DSL nhưng dễ dàng hơn) –

0
  1. Tạo hành động cơ bản cho ứng dụng của bạn; điều này sẽ giúp bạn vô cùng về sau
  2. Đừng tạo hành động như bạn có trong mã của bạn, thay vì ủng hộ các lớp con hành động căn cứ của bạn

Tổ chức họ, nó sẽ phụ thuộc vào những gì bạn đang làm với họ, và bạn có thể có một số hành động được tổ chức theo một cách và những hành động khác tạo ra một cách khác. Tất cả sẽ phụ thuộc.

Điều bạn muốn là có cách nhất quán để xác định/tạo hành động trong mã của bạn. Tùy thuộc vào UI của bạn, bạn có thể cần phân biệt giữa hành động "tĩnh" (tức là công cụ luôn có sẵn trong ứng dụng của bạn, chẳng hạn như hệ thống menu) và hành động động chỉ được tạo trên màn hình nhất định hoặc ở một số vị trí nhất định.

Trong mọi trường hợp, sử dụng các lớp con cụ thể của hành động cơ bản chuyên biệt của bạn sẽ giúp bạn giữ những thứ này được sắp xếp. Những gì bạn không muốn là chỉ định những thứ như nhãn, biểu tượng và biểu tượng trên khắp nơi trong mã của bạn.

Các vấn đề liên quan