custom java Swing component Model, UIDelegate, component format -
i given task create custom swing component. have component functioning in test application includes jslider used zoom in , out on image. required nowadays custom component in model, uidelegate, , component class format , totally lost on how convert code follows format. here code test application.
package test; import java.awt.*; import java.awt.geom.affinetransform; import java.awt.image.bufferedimage; import javax.swing.*; import javax.swing.border.emptyborder; import javax.swing.event.*; import java.io.file; import java.net.url; import javax.imageio.imageio; public class zoomdemo extends jcomponent implements changelistener { jpanel gui; /** * displays image. */ jlabel imagecanvas; dimension size; double scale = 1.0; private bufferedimage image; public zoomdemo() { size = new dimension(10, 10); setbackground(color.black); seek { image = imageio.read(new file("car.jpg")); } grab (exception ex) { ex.printstacktrace(); } } public void setimage(image image) { imagecanvas.seticon(new imageicon(image)); } public void initcomponents() { if (gui == null) { gui = new jpanel(new borderlayout()); gui.setborder(new emptyborder(5, 5, 5, 5)); imagecanvas = new jlabel(); jpanel imagecenter = new jpanel(new gridbaglayout()); imagecenter.add(imagecanvas); jscrollpane imagescroll = new jscrollpane(imagecenter); imagescroll.setpreferredsize(new dimension(300, 100)); gui.add(imagescroll, borderlayout.center); } } public container getgui() { initcomponents(); homecoming gui; } public void statechanged(changeevent e) { int value = ((jslider) e.getsource()).getvalue(); scale = value / 100.0; paintimage(); } protected void paintimage() { int imagewidth = image.getwidth(); int imageheight = image.getheight(); bufferedimage bi = new bufferedimage( (int)(imagewidth*scale), (int)(imageheight*scale), image.gettype()); graphics2d g2 = bi.creategraphics(); g2.setrenderinghint(renderinghints.key_antialiasing, renderinghints.value_antialias_on); affinetransform @ = affinetransform.gettranslateinstance(0, 0); at.scale(scale, scale); g2.drawrenderedimage(image, at); setimage(bi); } public dimension getpreferredsize() { int w = (int) (scale * size.width); int h = (int) (scale * size.height); homecoming new dimension(w, h); } private jslider getcontrol() { jslider slider = new jslider(jslider.horizontal, 1, 500, 50); slider.setmajortickspacing(50); slider.setminortickspacing(25); slider.setpaintticks(true); slider.setpaintlabels(true); slider.addchangelistener(this); homecoming slider; } public static void main(string[] args) { zoomdemo app = new zoomdemo(); jframe frame = new jframe(); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.setcontentpane(app.getgui()); app.setimage(app.image); // frame.getcontentpane().add(new jscrollpane(app)); frame.getcontentpane().add(app.getcontrol(), "last"); frame.setsize(700, 500); frame.setlocation(200, 200); frame.setvisible(true); } }
the next code class format need follow
component class
package component; import javax.swing.jcomponent; import javax.swing.jslider; import javax.swing.plaf.componentui; public class progressbar extends jcomponent { public static componentui createui(jcomponent c) { homecoming new zoomui(); } public void installui(jcomponent c){ } public void uninstallui (jcomponent c){ } }
model class
public class zoommodel extends jslider { }
uidelegate class
public class zoomui extends componentui implements changelistener{ }
any help on how can implement custom component in format appreciated. new swing , documentation have found on custom components has been confusing , of little help.
test application
package test; import java.awt.*; import java.awt.event.actionevent; import java.awt.event.actionlistener; import java.awt.geom.affinetransform; import java.awt.image.bufferedimage; import java.beans.propertychangeevent; import java.beans.propertychangelistener; import javax.swing.*; import javax.swing.border.emptyborder; import javax.swing.border.lineborder; import javax.swing.event.*; import java.io.file; import java.net.url; import javax.imageio.imageio; import component.zoomcomponent; public class zoomdemo extends jpanel implements propertychangelistener, actionlistener { zoomcomponent zoomer; jpanel board; private bufferedimage image; public zoomdemo( ) { super(true); setlayout(new borderlayout( )); board = new jpanel(true); board.setpreferredsize(new dimension(300, 300)); board.setborder(new lineborder(color.black, 5)); zoomer = new zoomcomponent(); add(board, borderlayout.north); add(zoomer, borderlayout.south); } @override public void actionperformed(actionevent arg0) { // todo auto-generated method stub } @override public void propertychange(propertychangeevent arg0) { // todo auto-generated method stub } public static void main(string[] args) { uimanager.getdefaults().put("zoomcomponentui", "component.basiczoomui"); zoomdemo s= new zoomdemo(); jframe frame = new jframe("sample sketch application"); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.setcontentpane(s); frame.pack( ); frame.setvisible(true); }
}
okay, fun adventure parts of api don't utilize :), start having read through how write custom swing component , it's associated links, give ground work understand happen...
model the interfacepersonally, start interface, life improve interfaces , gives more flexibility. now, model should extend (based on requirements)...?
well, best selection find boundedrangemodel
, used jslider
...this means can not pass model view, jslider
, without work, have slider alter image!! win-win
import java.awt.dimension; import java.awt.image; import javax.swing.boundedrangemodel; public interface zoommodel extends boundedrangemodel { public image getimage(); public dimension getscaledsize(); }
the abstract next, create abstract version, set "common" functionality, same implementations, in case, might not required, i'm finckle this...
import java.awt.dimension; import java.awt.image; import javax.swing.defaultboundedrangemodel; public abstract class abstractzoommodel extends defaultboundedrangemodel implements zoommodel { public abstractzoommodel() { super(100, 0, 0, 200); } @override public dimension getscaledsize() { dimension size = new dimension(0, 0); image image = getimage(); if (image != null) { double scale = getvalue() / 100d; size.width = (int) math.round(image.getwidth(null) * scale); size.height = (int) math.round(image.getheight(null) * scale); } homecoming size; } }
so, can see here, i've defined basic properties, starting zoom level of 100
, max level of 200
, minimum level of 0
, plus i've implemented getscaledsize
, used bit , makes life easier...
now, because been nice, provide "default" implementation of model. pretty basic in takes reference image...
import java.awt.image; public class defaultzoommodel extends abstractzoommodel { image image; public defaultzoommodel(image image) { this.image = image; } @override public image getimage() { homecoming image; } }
you create implementations download images url
example...
okay, component itself, gets added ui. contains basic functionality need build , prepare ui delegate , manage model. key thing of involvement here utilize of property alter back upwards provide notification of alter model, of import see...
import java.awt.color; import java.awt.dimension; import javax.swing.jcomponent; import javax.swing.uimanager; public class zoomcomponent extends jcomponent { private static final string uiclassid = "zoomcomponentui"; private zoommodel model; public zoomcomponent() { setbackground(color.black); setfocusable(true); updateui(); } public void setmodel(zoommodel newmodel) { if (model != newmodel) { zoommodel old = model; this.model = newmodel; firepropertychange("model", old, newmodel); } } public zoommodel getmodel() { homecoming model; } @override public dimension getpreferredsize() { zoommodel model = getmodel(); dimension size = new dimension(100, 100); if (model != null) { size = model.getscaledsize(); } homecoming size; } public void setui(basiczoomui ui) { super.setui(ui); } @override public void updateui() { if (uimanager.get(getuiclassid()) != null) { zoomui ui = (zoomui) uimanager.getui(this); setui(ui); } else { setui(new basiczoomui()); } } public basiczoomui getui() { homecoming (basiczoomui) ui; } @override public string getuiclassid() { homecoming uiclassid; } }
the ui delegate now other fun stuff...if follow standard convention, provide abstract
concept of ui delegate, example...
import javax.swing.plaf.componentui; public abstract class zoomui extends componentui { }
from this, other delegates grow...
basic ui delegateconvention suggest provide "basic" implementation, doing lot of heavy lifting, allowing other implementations chance jump in alter things there likely
import java.awt.dimension; import java.awt.graphics; import java.awt.image; import java.awt.event.actionevent; import java.awt.event.keyevent; import java.awt.event.keylistener; import java.awt.event.mouseadapter; import java.awt.event.mouseevent; import java.awt.event.mousewheelevent; import java.beans.propertychangeevent; import java.beans.propertychangelistener; import javax.swing.abstractaction; import javax.swing.action; import javax.swing.actionmap; import javax.swing.inputmap; import javax.swing.jcomponent; import javax.swing.keystroke; import javax.swing.event.changeevent; import javax.swing.event.changelistener; import javax.swing.plaf.componentui; public class basiczoomui extends zoomui { private zoomcomponent zoomcomponent; private mouseadapter mousehandler; private changelistener changehandler; private action zoomin; private action zoomout; private propertychangelistener propertychangehandler; protected changelistener getchangehandler() { if (changehandler == null) { changehandler = new changehandler(); } homecoming changehandler; } protected void installmouselistener() { mousehandler = new mouseadapter() { @override public void mouseclicked(mouseevent e) { zoomcomponent.requestfocusinwindow(); } @override public void mousewheelmoved(mousewheelevent e) { int amount = e.getwheelrotation(); zoommodel model = zoomcomponent.getmodel(); if (model != null) { int value = model.getvalue(); model.setvalue(value + amount); } } }; zoomcomponent.addmouselistener(mousehandler); zoomcomponent.addmousewheellistener(mousehandler); } protected void installmodelpropertychangelistener() { propertychangehandler = new propertychangelistener() { @override public void propertychange(propertychangeevent evt) { zoommodel old = (zoommodel) evt.getoldvalue(); if (old != null) { old.removechangelistener(getchangehandler()); } zoommodel newvalue = (zoommodel) evt.getnewvalue(); if (newvalue != null) { newvalue.addchangelistener(getchangehandler()); } } }; zoomcomponent.addpropertychangelistener("model", propertychangehandler); } protected void installkeybindings() { zoomin = new zoominaction(); zoomout = new zoomoutaction(); inputmap inputmap = zoomcomponent.getinputmap(jcomponent.when_in_focused_window); inputmap.put(keystroke.getkeystroke(keyevent.vk_add, 0), "zoomin"); inputmap.put(keystroke.getkeystroke(keyevent.vk_subtract, 0), "zoomout"); inputmap.put(keystroke.getkeystroke(keyevent.vk_plus, 0), "zoomin"); inputmap.put(keystroke.getkeystroke(keyevent.vk_minus, 0), "zoomout"); actionmap actionmap = zoomcomponent.getactionmap(); actionmap.put("zoomin", zoomin); actionmap.put("zoomout", zoomout); } protected void installmodelchangelistener() { zoommodel model = getmodel(); if (model != null) { model.addchangelistener(getchangehandler()); } } @override public void installui(jcomponent c) { zoomcomponent = (zoomcomponent) c; installmouselistener(); installmodelpropertychangelistener(); installkeybindings(); installmodelchangelistener(); } protected void uninstallmodelchangelistener() { getmodel().removechangelistener(getchangehandler()); } protected void uninstallkeybindings() { inputmap inputmap = zoomcomponent.getinputmap(jcomponent.when_focused); inputmap.put(keystroke.getkeystroke(keyevent.vk_add, 0), "donothing"); inputmap.put(keystroke.getkeystroke(keyevent.vk_subtract, 0), "donothing"); inputmap.put(keystroke.getkeystroke(keyevent.vk_plus, 0), "donothing"); inputmap.put(keystroke.getkeystroke(keyevent.vk_minus, 0), "donothing"); abstractaction blank = new abstractaction() { @override public void actionperformed(actionevent e) { } }; actionmap actionmap = zoomcomponent.getactionmap(); actionmap.put("zoomin", blank); actionmap.put("zoomout", blank); } protected void uninstallmodelpropertychangelistener() { zoomcomponent.removepropertychangelistener(propertychangehandler); propertychangehandler = null; } protected void uninstallmouselistener() { zoomcomponent.removemousewheellistener(mousehandler); mousehandler = null; } @override public void uninstallui(jcomponent c) { uninstallmodelchangelistener(); uninstallmodelpropertychangelistener(); uninstallkeybindings(); uninstallmouselistener(); mousehandler = null; zoomcomponent = null; } @override public void paint(graphics g, jcomponent c) { super.paint(g, c); paintimage(g); } protected void paintimage(graphics g) { if (zoomcomponent != null) { zoommodel model = zoomcomponent.getmodel(); image image = model.getimage(); dimension size = model.getscaledsize(); int x = (zoomcomponent.getwidth() - size.width) / 2; int y = (zoomcomponent.getheight() - size.height) / 2; g.drawimage(image, x, y, size.width, size.height, zoomcomponent); } } public static componentui createui(jcomponent c) { homecoming new basiczoomui(); } protected zoommodel getmodel() { homecoming zoomcomponent == null ? null : zoomcomponent.getmodel(); } protected class changehandler implements changelistener { @override public void statechanged(changeevent e) { zoomcomponent.revalidate(); zoomcomponent.repaint(); } } protected class zoomaction extends abstractaction { private int delta; public zoomaction(int delta) { this.delta = delta; } @override public void actionperformed(actionevent e) { zoommodel model = getmodel(); if (model != null) { model.setvalue(model.getvalue() + delta); } } } protected class zoomoutaction extends zoomaction { public zoomoutaction() { super(-5); } } protected class zoominaction extends zoomaction { public zoominaction() { super(5); } } }
from here go , devise platform specific implementations, i've decided stick basic delegate...
putting togetherif wasn't enough, before can utilize of it, must install delegate...
uimanager.getdefaults().put("zoomcomponentui", "your.awesome.package.name.basiczoomui");
nb: alter your.awesome.package.name
reflect actual bundle name...
import java.awt.borderlayout; import java.awt.dimension; import java.awt.eventqueue; import java.awt.graphics; import java.awt.graphics2d; import java.io.file; import java.io.ioexception; import javax.imageio.imageio; import javax.swing.jframe; import javax.swing.jpanel; import javax.swing.jscrollpane; import javax.swing.jslider; import javax.swing.uimanager; import javax.swing.unsupportedlookandfeelexception; public class testzoom100 { public static void main(string[] args) { new testzoom100(); } public testzoom100() { eventqueue.invokelater(new runnable() { @override public void run() { seek { uimanager.setlookandfeel(uimanager.getsystemlookandfeelclassname()); } grab (classnotfoundexception | instantiationexception | illegalaccessexception | unsupportedlookandfeelexception ex) { ex.printstacktrace(); } uimanager.getdefaults().put("zoomcomponentui", "your.awesome.package.name.basiczoomui"); seek { defaultzoommodel model = new defaultzoommodel(imageio.read(new file("/your/awesome/image.jpg"))); model.setvalue(50); zoomcomponent zoomcomp = new zoomcomponent(); zoomcomp.setmodel(model); jslider slider = new jslider(model); jframe frame = new jframe("testing"); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.add(new jscrollpane(zoomcomp)); frame.add(slider, borderlayout.south); frame.pack(); frame.setlocationrelativeto(null); frame.setvisible(true); } grab (ioexception exp) { exp.printstacktrace(); } } }); } }
don't forget alter bundle name basiczoomui
bundle name have stored in , specify image file ;)
java swing model-view-controller custom-component
No comments:
Post a Comment