java - How can I fix this code bug? -
i trying make image editing application in java using mvc design pattern. so, event handling in controller, state , operations relevant state stored in models, , user sees stored in views.
when open image, there zoom box displays zoom level of image being displayed. zoom automatically calculated when first rendered in paintcomponent()
(see step #3). when open image, want zoom level set calculated be. the problem zoom level shows 0, , know why. let me explain:
1. the actionlistener
for open menu item fired
in jpscontroller:
class menubarfileopenlistener implements actionlistener { public void actionperformed(actionevent event) { file filechooserreturnvalue = view.showandgetvalueoffilechooser(); if (filechooserreturnvalue != null) { try { // irrelevant code omitted view.adddocument(newdocument); } catch(ioexception ex) { ex.printstacktrace(); } } } }
2. view.adddocument()
is called
note: root of problem
in jpsview:
public void adddocument(documentmodel document) { // irrelevant code omitted // canvaspanelview extends jpanel documentstabbedpane.add(newdocumentview.getcanvaspanelview()); // root of problem double currentzoomfactor = getcurrentcanvaspanelview().getzoomfactor(); // formatting text string zoomleveltext = statusbar_zoomleveltextfield_formatter.format(currentzoomfactor); // setting text of text field statusbar_zoomleveltextfield.settext(zoomleveltext); }
3. time later, paintcomponent()
is run
in canvaspanelview extends jpanel:
public void paintcomponent(graphics g) { super.paintcomponent(g); if (initialrender) { initialrender = false; // calculates zoom level setzoomfit(); } // irrelevant code omitted g.drawimage(image, destinationx1, destinationy1, destinationx2, destinationy2, sourcex1, sourcey1, sourcex2, sourcey2, null); }
in part 2, have line of code:
double currentzoomfactor = getcurrentcanvaspanelview().getzoomfactor();
when getzoomfactor()
called, current canvaspanelview
must not have size, because returns 0
. had problem before, , solution these lines of code in #3:
if (initialrender) { initialrender = false; setzoomfit(); }
when paintcomponent() called, canvaspanelview
must have been given size then, not when getzoomfactor() called. paintcomponent(), , therefore setzoomfit(), come after getzoomfactor().
how can correctly show zoom level of image when opened?
basically, have kind of race condition (as can in single thread).
what's happening adding new view, expecting laid out immediately. not how works in swing. when add new component container, request made update layouts of components in hierarchy, , layout containers have been marked invalid. won't happen until current call cycle has completed , event dispatching thread has had time process requests.
instead, can schedule @ later time adding request end of event dispatching thread. ensures request executed after current tasks on edt have been executed before (there may others follow, you've squeezed in).
the following example demonstrates point.
it adds new panel jtabbedpane
, dumps it's current size, use swingutilities.invokelater
request callback @ time in future , dumps panels size again. should find first request 0x0
, second valid value (depending on size of frame , , feel)
import java.awt.borderlayout; import java.awt.eventqueue; import java.awt.gridbaglayout; import java.awt.event.actionevent; import java.awt.event.actionlistener; import javax.swing.jbutton; import javax.swing.jframe; import javax.swing.jlabel; import javax.swing.jpanel; import javax.swing.jtabbedpane; import javax.swing.swingutilities; import javax.swing.uimanager; import javax.swing.unsupportedlookandfeelexception; public class testtabbedpane01 { public static void main(string[] args) { new testtabbedpane01(); } private jtabbedpane tabbedpane; public testtabbedpane01() { eventqueue.invokelater(new runnable() { @override public void run() { try { uimanager.setlookandfeel(uimanager.getsystemlookandfeelclassname()); } catch (classnotfoundexception ex) { } catch (instantiationexception ex) { } catch (illegalaccessexception ex) { } catch (unsupportedlookandfeelexception ex) { } tabbedpane = new jtabbedpane(); jbutton btnadd = new jbutton("add"); btnadd.addactionlistener(new actionlistener() { @override public void actionperformed(actionevent e) { final jpanel panel = new jpanel(new gridbaglayout()); panel.add(new jlabel(string.valueof(tabbedpane.getcomponentcount()))); tabbedpane.add(string.valueof(tabbedpane.getcomponentcount()), panel); system.out.println("new panel size = " + panel.getsize()); swingutilities.invokelater(new runnable() { @override public void run() { system.out.println("new panel size (later) = " + panel.getsize()); } }); } }); jframe frame = new jframe("test"); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.setlayout(new borderlayout()); frame.add(tabbedpane); frame.add(btnadd, borderlayout.south); frame.setsize(200, 200); frame.setlocationrelativeto(null); frame.setvisible(true); } }); } }
Comments
Post a Comment