Cell editor requirements
Recently, I need to develop a small application by myself and use SWT to design the interface. In this case, I need to use JFace TableViewer. After using TableViewer, I found that it is easier to use than Swing JTable, in addition, it is more convenient and easy to add an editor to the cells in the table (it may also be the illusion that I have not studied the cell editor in Swing's JTable ......)
I need to add the edit date editor to the cell of the object generated by TableViewer (1)
Figure 1 Date editor in Cell
Using the combination of the keyword "JFace CellEditor" and so on the Internet, you can easily find many override methods for the CellEditor class in the JFace interface component. However, I have searched for several days, I just found some articles that are useless to me.
From October 1 to October 1, it took four days to finally solve the problem of this editor, so now we can use the code to summarize the results:
Code of the custom date cell Editor
The code for implementing the cell editor is as follows:
Note: Please read the code quickly and learn more about the code later.
/**
* Updated at 04:31:44
* <P>
*
*@ AuthorGuo Kai
*
*/
Public class DatepickerCellEditor extends CellEditor {
Public static Logger log = Logger. getLogger (DatepickerCellEditor. class );
Private DatePickerCombo datepickerWidget;
Protected Date selectedDate;
Public DatepickerCellEditor (){
}
Public DatepickerCellEditor (Composite parent, int style ){
Super (parent, style );
}
Protected Control createControl (Composite parent ){
DatepickerWidget = new DatePickerCombo (parent, getStyle ());
DatepickerWidget. getDp (). addSelectionListener (new SelectionAdapter (){
Public void widgetdefaselecselected (SelectionEvent event ){
ApplyEditorValueAndDeactivate ();
}
Public void widgetSelected (SelectionEvent event ){
SelectedDate = datepickerWidget. getDate ();
}
});
DatepickerWidget. addTraverseListener (new TraverseListener (){
Public void keyTraversed (TraverseEvent e ){
If (e. detail = SWT. TRAVERSE_ESCAPE
| E. detail = SWT. TRAVERSE_RETURN ){
E. doit = false;
}
}
});
Return datepickerWidget;
}
Protected void applyEditorValueAndDeactivate (){
SelectedDate = datepickerWidget. getDate ();
MarkDirty ();
FireApplyEditorValue ();
Deactivate ();
}
Protected Object doGetValue (){
FocusLost (); // when getting the value of the cell editor, the cell editor should also lose focus.
Return Constants. format (selectedDate );
}
Protected void doSetFocus (){
DatepickerWidget. getDp (). setFocus ();
}
Protected void doSetValue (Object value ){
Assert. isTrue (datepickerWidget! = Null & (value instanceof String ));
SelectedDate = Constants. parse (String) value );
DatepickerWidget. setDate (selectedDate );
}
Protected void focusLost (){
System. out. println ("focusLost ");
If (isActivated ()){
ApplyEditorValueAndDeactivate ();
}
}
Public Date getSelectedDate (){
Return datepickerWidget. getDate ();
}
Public void setSelectedDate (Date date ){
DatepickerWidget. setDate (date );
}
}
First, you must pay attention to a few differences from other CellEditor implementations.
1. In the createControl () method, we did not add a focus listener to the property dp in datepickerCombo or datepickerCombo (the addFocusListener part in the code was commented out ).
2. In the doGetValue () method, we make the current CellEditor lose the focus (here we can refer to the code of ComboBoxCellEditor, it is not hard to find that its doGetValue () method does not process the focus)
This code is still not perfect, because if the focus of CellEditor is lost in the doGetValue () method, there will be a problem -- Because doGetValue () the call time is when the value of CellEditor changes, that is, each time we open the date CellEditor and modify the date, the focus of the cell editor will be lost, in this way, the user has to click another cell, then click back to this cell, and then select another date (assuming that he did not select a correct one for the first time ). This means that the implementation here is very uugly!
What should I do? Analysis again ~~
Our initial problem was:
From Region.
The widget 2 is divided into three parts: an editing box, a button, and a panel with a calendar
Figure 2 SWT-Datepicker Control
Based on the source code, we know that their respective event control systems are in textEvent (), arrowEvent (), dpEvent (), and auxiliary events are controlled in popupEvent () and comboEvent ().
When you directly use DatepickerCombo that has not been modified to our DatepickerCellEditor, the issue of focusing cannot be captured. In the constructor of the DatepickerCombo class, we can find a piece of code that defines the Listener interface object.
Listener listener = new Listener (){
Public void handleEvent (Event event ){
Log.info (event );
If (popup = event. widget ){
PopupEvent (event );
Return;
}
......
}
};
We add the log in the first line of the handleEVent () method, and then look at the event information.
When the unmodified code is used, we can see that when the calendar panel is popped up by the arrow button, the focus is lost immediately after it gets the focus.
.................................... (Here we omit the process of thinking about a problem)
Finally, we noticed the code of an existing implementation class ComboBoxCellEditor. We found that CCombo is used in this class, and the code of CCombo is surprisingly similar to that of DatepickerCombo. However, when using ComboBoxCellEditor, there will be no focus issues.
After carefully checking the code, we found that the biggest difference between CCombo and DatepickerCombo lies in the code of focus processing:
The DatepickerCombo class puts the code of FocusIn and FocusOut into several event processing methods, such as textEvent (), dpEvent (), and arrowEvent, CCombo then focuses on the handleFocus () method. The Code is as follows:
Void handleFocus (int type ){
If (isDisposed () return;
Switch (type ){
Case SWT. FocusIn :{
If (hasFocus) return;
If (getEditable () text. selectAll ();
HasFocus = true;
Shell shell = getShell ();
Shell. removeListener (SWT. Deactivate, listener );
Shell. addListener (SWT. Deactivate, listener );
Display display = getDisplay ();
Display. removeFilter (SWT. FocusIn, filter );
Display. addFilter (SWT. FocusIn, filter );
Event e = new Event ();
Policylisteners (SWT. FocusIn, e );
Break;
}
Case SWT. FocusOut :{
If (! HasFocus) return;
Control focusControl = getDisplay (). getFocusControl ();
If (focusControl = arrow | focusControl = list | focusControl = text) return;
HasFocus = false;
Shell shell = getShell ();
Shell. removeListener (SWT. Deactivate, listener );
Display display = getDisplay ();
Display. removeFilter (SWT. FocusIn, filter );
Event e = new Event ();
NotifyListeners (SWT. FocusOut, e );
Break;
}
}
}
The key code is displayed in blue and white. The filter declaration code of an important attribute object in the CCombo class is put in the CCombo constructor. The Code is as follows:
Filter = new Listener (){
Public void handleEvent (Event event ){
Shell shell = (Control) event. widget). getShell ();
If (shell = CCombo. this. getShell ()){
HandleFocus (SWT. FocusOut );
}
}
};
This listener object means that any response event of shell will lead to the execution of the FocusOut event processing code, which also enables the filter listener to be promptly cleared in both the FocusIn and FocusOut event processing code, otherwise, the GUI may be directly in the endless loop of Event Response. (In addition, we can see the impact of the filter on the performance in the SWT document. Therefore, when using this tool that may affect the performance, you should refer to the source code included in Eclipse)
The final source code of the DatepickerCellEditor class is:
/**
* Updated at 04:31:44
* <P>
*
* @ Author Guo Kai
*
*/
Public class DatepickerCellEditor extends CellEditor {
Public static Logger log = Logger. getLogger (DatepickerCellEditor. class );
Private DatePickerCombo datepickerWidget;
Protected Date selectedDate;
Public DatepickerCellEditor (){
}
Public DatepickerCellEditor (Composite parent, int style ){
Super (parent, style );
}
Protected Control createControl (Composite parent ){
DatepickerWidget = new DatePickerCombo (parent, getStyle ());
DatepickerWidget. getDp (). addSelectionListener (new SelectionAdapter (){
Public void widgetdefaselecselected (SelectionEvent event ){
ApplyEditorValueAndDeactivate ();
}
Public void widgetSelected (SelectionEvent event ){
SelectedDate = datepickerWidget. getDate ();
}
});
DatepickerWidget. addTraverseListener (new TraverseListener (){
Public void keyTraversed (TraverseEvent e ){
If (e. detail = SWT. TRAVERSE_ESCAPE
| E. detail = SWT. TRAVERSE_RETURN ){
E. doit = false;
}
}
});
DatepickerWidget. addFocusListener (new FocusAdapter (){
Public void focusLost (FocusEvent e ){
Log.info ("datepickerWidget focus lost caused by: \ n" + e );
DatepickerCellEditor. this. focusLost ();
}
});
Return datepickerWidget;
}
Protected void applyEditorValueAndDeactivate (){
SelectedDate = datepickerWidget. getDate ();
MarkDirty ();
FireApplyEditorValue ();
Deactivate ();
}
Protected Object doGetValue (){
Return Constants. format (selectedDate );
}
Protected void doSetFocus (){
DatepickerWidget. setFocus ();
}
Protected void doSetValue (Object value ){
Assert. isTrue (datepickerWidget! = Null & (value instanceof String ));
SelectedDate = Constants. parse (String) value );
DatepickerWidget. setDate (selectedDate );
}
......
}
Summary: referring to the official Eclipse source code, it is still an important means of learning. With the help of the sample code, the two methods can greatly reduce repetitive work.