The last time we created a relatively simple Resource Manager, this time we talked about the above resource manager problems, and we should try to be close to the Windows Resource Manager.
This simple Resource Management tree is complete. Let's talk about its problems:
① There is a gap between pictures and appearance and windows
We can solve this problem by setting L & F and setting a new image like Renderer.
② When there are many files in the folder, the meeting is very slow and the interface will be suspended
In this case, we can write a slow loading treenode to inherit from defaultmutabletreenode, define the loading ID in it, and then use swingworker or multithreading to load the tree smoothly, though it is troublesome, but it can also be solved.
③ When a tree click is suspended, the user will think that there is a problem. Multiple events will be loaded when a random click occurs.
This problem is actually a problem of the swing event mechanism, but it cannot be solved because there will always be time-consuming operations and it is impossible not to wait. but we can do a better user experience to avoid this problem. The solution here is to draw a layer of glason the tree, block all events, and prompt users. After loading is complete, cancel the glasspane interface.
④ There are only basic files on my computer and no network neighbors.
This problem is very difficult to solve. The network problem exists when it comes to network neighbors, and network connection and scanning are also required. My idea is to use the commons-client of Apache, later, we found that some people have provided a better way to use Java's jfilechooser class. Java has implemented a lot of things we need to implement.
⑤ Sub-directories of the obtained Resource Management tree are out of order
This is a good solution, so that our treenode can implement the comparable interface.
To solve these five problems, we have made the release version:
First, let's solve problem 1 and look at our code:
We can set the Renderer for node image styles, and because these images can be obtained in the jfilechooser UI, we will first create a FileView class by referring to the jfilechooser UI:
//***********************
// * FileView operations *
//***********************
ProtectedClassBasicfileviewExtendsFileView {
Method to rewrite it:
@ Override
PublicString getname (file F ){
// Note: returns display name rather than file name
String filename =Null;
If(F! =Null){
Filename = chooser. getfilesystemview (). getsystemdisplayname (f );
}
ReturnFilename;
}
This is the display name.
@ Override
PublicString getdescription (file F ){
ReturnF. getname ();
}
This is the description
@ Override
PublicString gettypedescription (file F ){
String type = chooser. getfilesystemview (). getsystemtypedescription (
F );
If(Type =Null){
If(F. isdirectory ()){
Type = directorydescriptiontext;
}Else{
Type = filedescriptiontext;
}
}
ReturnType;
}
This is the file type.
@ Override
PublicIcon getIcon (file F ){
This is an image representation.
In this way, the image and name we need after building this FileView can be obtained.
Then there is our Renderer:
PrivateClassFilesystemtreerendererExtendsDefaulttreecellrenderer {
Rewrite its method, set the image and name we get from FileView:
@ Override
PublicComponent gettreecellrenderercomponent (jtree tree, object value,BooleanSel,BooleanExpanded,BooleanLeaf,IntRow,
BooleanHasfocus ){
Settext (getfileview (chooser). getname (node. GetFile ()));
Seticon (getfileview (chooser). getIcon (node. GetFile ()));
Then set it to the tree:
Tree. setcellrenderer (NewFilesystemtreerenderer ());
See the results:
Is it very close to Windows? Set L & F, for example:
Uimanager.Setlookandfeel(Uimanager.Getsystemlookandfeelclassname());
Then solve problem 2. We cannot use the original node of the tree. We construct it ourselves and inherit from it:
PublicAbstractClassLazymutabletreenodeExtendsDefaultmutabletreenode {
Add an attribute:
/** Is node load .*/
PrivateBooleanLoaded =False;
Provide a virtual method for subclass implementation:
ProtectedAbstractVoidLoadchildren ();
Then our implementation:
PrivateClassFiletreenodeExtendsLazymutabletreenode {
Rewrite its method. loading is not allowed for non-load:
@ Override
PublicBooleanIsleaf (){
If(! Isloaded ()){
ReturnFalse;
}Else{
ReturnSuper. Isleaf ();
}
}
And its real name:
@ Override
PublicString tostring (){
ReturnChooser. getfilesystemview (). getsystemdisplayname (
(File) getuserobject ());
}
Implementation of Virtual Methods:
@ Override
ProtectedVoidLoadchildren (){
Filetreenode [] nodes = getchildren ();
For(IntI = 0, c = nodes. length; I <C; I ++ ){
Add (nodes [I]);
}
}
In this way, problem 2 is solved, and problem 5 can also be solved here, so that our treenode implements the comparable interface:
PrivateClassFiletreenodeExtendsLazymutabletreenodeImplements
Comparable <Object> {
Then the implementation method is as follows:
@ Override
PublicIntCompareto (Object O ){
If(! (OInstanceofFiletreenode )){
Return1;
}
ReturnGetFile (). compareto (filetreenode) O). GetFile ());
}
Finally, in our use:
// Sort directories, filetreenode implements comparable
Filetreenode [] result = (filetreenode []) nodes
. Toarray (NewFiletreenode [0]);
Arrays.Sort(Result );
Nodes. Add (NewFiletreenode (result [I]);
In this way, all the node folders we add are sorted.
Then, let's solve problem 4. Three is more difficult to stay at the end:
When building this component, we first build jfilechooser
Jfilechooser chooser =NewJfilechooser ();
Add listeners:
ProtectedVoidInstalllisteners (){
Tree. addtreeselectionlistener (NewSelectionlistener ());
Chooser. getactionmap (). Put ("refreshtree ",NewUpdateaction ());
Chooser. getinputmap (jcomponent.When_ancestor_of_focused_component). Put (
Keystroke.Getkeystroke("F5"), "refreshtree ");
Chooser. addpropertychangelistener (NewChangelistener ());
}
When expanding the tree in the listener, use the jfilechooser method:
/**
* Tree node select change.
*/
PrivateClassSelectionlistenerImplementsTreeselectionlistener {
@ Override
PublicVoidValuechanged (treeselectionevent e ){
Getapproveselectionaction ()
. Setenabled (tree. getselectioncount ()> 0 );
Setselectedfiles ();
// The current directory is the one currently selected
Treepath currentdirectorypath = tree. getselectionpath ();
If(Currentdirectorypath! =Null){
File currentdirectory = (filetreenode) currentdirectorypath
. Getlastpathcomponent (). GetFile ();
Chooser. setcurrentdirectory (currentdirectory );
}
}
}
In this way, we do not need to construct all our directory structures cyclically. We can use jfilechooser to provide us with a good solution. For example, there are network neighbors. Problem 4 is completed:
Finally, let's solve problem 3. Why is it suspended? It is caused by many folders or slow network speeds. The solution is of course multithreading, but multithreading is prone to thread insecurity in swing, because it is not on the ADT, here we use swingworker to listen to the expand event of the tree:
Tree. addtreeexpansionlistener (NewTreeexpansion ());
Process it:
PrivateClassTreeexpansionImplementsTreeexpansionlistener {
@ Override
PublicVoidTreecollapsed (treeexpansionevent event ){
}
@ Override
PublicVoidTreeexpanded (treeexpansionevent event ){
// Ensure children gets expanded later
If(Event. getpath ()! =Null){
Object lastelement = event. getpath (). getlastpathcomponent ();
If(LastelementInstanceofFiletreenode & usenodequeue)
If(Filetreenode) lastelement). isloaded ()){
Slow processing is mainly here. We put it in swingworker:
NewWorkerqueue (node, tree, glasspane0000.exe cute ();
Then let's look at this class:
PrivateStaticFinalClassWorkerqueueExtends
Swingworker <void, filetreenode> {
Rewrite its method to handle the event added to our treenode:
@ Override
ProtectedVoid doinbackground ()ThrowsException {
Glasspanel. setvisible (True);
For(Enumeration <?> E = node. Children (); E. hasmoreelements ();){
Publish (filetreenode) E. nextelement ());
}
ReturnNull;
}
@ Override
ProtectedVoidProcess (list <filetreenode> chunks ){
For(Filetreenode: chunks ){
Filetreenode. getchildcount ();
}
}
@ Override
ProtectedVoidDone (){
Glasspanel. setvisible (False);
Tree. repaint ();
}
Then we will block all mouse clicks and give the user a prompt when expanding the node. Here we will draw a component and set it to glasspane to block all events:
/**
*/
PublicClassGlasspaneExtendsJcomponent {
All events are blocked and only focus is obtained:
// Blocks all user input
Addmouselistener (NewMouseadapter (){
});
Addmousemotionlistener (NewMousemotionadapter (){
});
Addkeylistener (NewKeyadapter (){
});
Setfocustraversalkeysenabled (False);
Addcomponentlistener (NewComponentadapter (){
PublicVoidComponentshown (componentevent EVT ){
Requestfocusinwindow ();
}
});
Then draw:
@ Override
ProtectedVoidPaintcomponent (Graphics g ){
First, draw the overall background:
// Gets the current clipping Area
Rectangle clip = G. getclipbounds ();
// Sets a 65% translucent Composite
Alphacomposite alpha = alphacomposite.Srcover. Derive (0.65f );
Composite composite = g2.getcomposite ();
G2.setcomposite (alpha );
// Fills the background
G2.setcolor (getbackground ());
G2.fillrect (clip. X, Clip. Y, Clip. Width, Clip. Height );
G2.setcomposite (composite );
Then I drew a prompt image. I wanted to draw a scroll wait icon, but I was not in the mood to write it. I put a picture on Google.
If(Image =Null){
Try{
Image = ImageIO.Read(Getclass (). getresource ("wait2.jpg "));
}Catch(Ioexception ex ){
Ex. printstacktrace ();
}
}
G. drawimage (image, getwidth ()/2-40, getheight ()/2
-80,120,120,Null);
Set the glasspane of the screen.
Component glasspane =NewGlasspane ();
Frame. getrootpane (). setglasspane (glasspane );
------ Not completed. It will be available later. Leave a tail
Jtree (node rendering + Resource Manager) (2)