简体   繁体   中英

How to refresh a textbox in zk when input gets updated programmatically?

got a textbox I want to use as a form of console in ZK on my apache tomcat 7 server. Right now, it doesn't update when its content gets changed programmatically but I'd like to do just this. Whenever my java changes the String, it's supposed to show it just in time but how?

(modified an existing code for the ZK)

My index.zul:

<zk>
  <window id="PDFmodifier" border="normal" height="98%"
     apply="org.zkoss.bind.BindComposer"
     viewModel="@id('vm') @init('toolbox.pdfconverter.FileUploadVM')"> 
    <label value="PDFmodifier"/>
      <separator></separator>
      <separator></separator>
     <hbox>

             <label value="Console log: " />
     <textbox width="500px" height="400px" id="txt" readonly="true" multiline ="true" value="Press the Upload Button to upload any PDF file. PDFmodifier will cover the unwanted area. After processing, the showPDF button will be active and you can save the modified PDF"/>
         <button label="Upload" upload="true"
             onUpload="@command('onUploadPDF',upEvent=event)"> </button>

         <button label="Show PDF" visible="@load(vm.fileuploaded)"
                onClick="@command('showPDF')">
           </button>
     </hbox>

       <iframe height="100%" width="100%" id="reportframe"
          content="@bind(vm.fileContent)">
     </iframe>
 </window>

Viewmodel:

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar;

import org.zkoss.bind.BindContext;
import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.io.Files;
import org.zkoss.util.media.AMedia;
import org.zkoss.util.media.Media;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.UploadEvent;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;

public class FileUploadVM {

    private String filePath;
    private boolean fileuploaded = false;
    AMedia fileContent;

    @Wire("#test")
    private Window win;
    @Wire("#txt")
    Textbox txt;


    public AMedia getFileContent() {
        return fileContent;
    }

    public void setFileContent(AMedia fileContent) {
        this.fileContent = fileContent;
    }

    public boolean isFileuploaded() {
        return fileuploaded;
    }

    public void setFileuploaded(boolean fileuploaded) {
        this.fileuploaded = fileuploaded;
    }

    @AfterCompose
    public void initSetup(@ContextParam(ContextType.VIEW) Component view) {
        Selectors.wireComponents(view, this, false);
        Executions.getCurrent().getDesktop().getWebApp().getConfiguration().setMaxUploadSize(10 * 1024);//for larger files

    }

    @Command
    @NotifyChange("fileuploaded")
    public void onUploadPDF(
            @ContextParam(ContextType.BIND_CONTEXT) BindContext ctx)
            throws IOException {

        UploadEvent upEvent = null;
        Object objUploadEvent = ctx.getTriggerEvent();
        if (objUploadEvent != null && (objUploadEvent instanceof UploadEvent)) {
            upEvent = (UploadEvent) objUploadEvent;
        }
        if (upEvent != null) {
            Media media = upEvent.getMedia();
            Calendar now = Calendar.getInstance();
            int year = now.get(Calendar.YEAR);
            int month = now.get(Calendar.MONTH);
            int day = now.get(Calendar.DAY_OF_MONTH);
            int min = now.get(Calendar.MINUTE);
            String fileName = year+"_"+month+"_"+day+"_"+min+".pdf";
            filePath = Executions.getCurrent().getDesktop().getWebApp().getRealPath("/");
            filePath = filePath + fileName;
            System.out.println("filePath='"+filePath+"'");
            Files.copy(new File(filePath), media.getStreamData());

            PDFmodifier mod = new PDFmodifier(txt);//txt
            filePath = mod.start(filePath);
            System.out.println("Ergbnis-pfad='"+filePath+"'");
            Messagebox.show("File Sucessfully altered. Press \"Show PDF\" to download file.");
            fileuploaded = true;

        }
    }

    @Command
    @NotifyChange("fileContent")
    public void showPDF() throws IOException {
        File f = new File(filePath);
        byte[] buffer = new byte[(int) f.length()];
        FileInputStream fs = new FileInputStream(f);
        fs.read(buffer);
        fs.close();
        ByteArrayInputStream is = new ByteArrayInputStream(buffer);
        fileContent = new AMedia("report", "pdf", "application/pdf", is);

    }
}

Extemely reduced java code (it's a lot more but not needed for this question):

import org.zkoss.zul.Textbox;
public class PDFmodifier {

     String logText ="";
     Textbox text;


    public PDFmodifier(Textbox t)
    {
        text = t;
    }

    protected void printToTextbox(String txt)
    {
        logText += "\n"+txt;
        text.setValue(logText);
    }
}

It all works but I'd like to improve it. Thanks for reading in advance.

EDITS:

Index.zul

<zk xmlns:n="native" xmlns:c="client">
<?page title="RemoveKlausNote" ?>
  <window id="RemoveKlausNote" 
     apply="org.zkoss.bind.BindComposer"
     viewModel="@id('vm') @init('toolbox.pdfconverter.FileUploadVM')"
     title="Bioinfo Teaching Toolbox" border="normal" width="1000px" position="center,top" mode="embedded"> 
<hbox>
    <label value="Console log: " />
     <textbox width="500px" height="200px" readonly="true" value="@bind(vm.getLogText())" multiline ="true"/>
         <button label="Upload" upload="true"
             onUpload="@command('onUploadPDF',upEvent=event)"> </button>

         <button label="Show PDF" visible="@load(vm.fileuploaded)"
                onClick="@command('showPDF')">
           </button>
     </hbox>

     <iframe height="100%" width="100%" id="reportframe"
          content="@bind(vm.fileContent)">
     </iframe>

 </window>

Viewmodel:

public class FileUploadVM {

    private String filePath;
    private boolean fileuploaded = false;
    AMedia fileContent;

    @Wire("#test")
    private Window win;

    LogText logText = new LogText();

    public AMedia getFileContent() {
        return fileContent;
    }

    public void setFileContent(AMedia fileContent) {
        this.fileContent = fileContent;
    }

    public boolean isFileuploaded() {
        return fileuploaded;
    }

    public void setFileuploaded(boolean fileuploaded) {
        this.fileuploaded = fileuploaded;
    }

    @AfterCompose
    public void initSetup(@ContextParam(ContextType.VIEW) Component view) {
        Selectors.wireComponents(view, this, false);
        Executions.getCurrent().getDesktop().getWebApp().getConfiguration().setMaxUploadSize(10 * 1024);//for larger files
    }


    @NotifyChange("logText.log")
    public void setLogText(String text) {
        logText.setLog(text);
    }

    @NotifyChange("logText.log")
    public String getLogText()
    {
        return logText.getLog();
    }

    @Command
    @NotifyChange("fileuploaded")
    public void onUploadPDF(
            @ContextParam(ContextType.BIND_CONTEXT) BindContext ctx)
            throws IOException {

        UploadEvent upEvent = null;
        Object objUploadEvent = ctx.getTriggerEvent();
        if (objUploadEvent != null && (objUploadEvent instanceof UploadEvent)) {
            upEvent = (UploadEvent) objUploadEvent;
        }
        if (upEvent != null) {
            Media media = upEvent.getMedia();


            String webAppPath = Executions.getCurrent().getDesktop().getWebApp().getRealPath("/");
            System.out.println("webAppPath='"+webAppPath+"'");


            Calendar now = Calendar.getInstance();
            int year = now.get(Calendar.YEAR);
            int month = now.get(Calendar.MONTH);
            int day = now.get(Calendar.DAY_OF_MONTH);
            int min = now.get(Calendar.MINUTE);
            String originalName = media.getName();

            String fileName = originalName +year+"_"+month+"_"+day+"_"+min+".pdf";
            String tmpPath = PDFmodifier.getTemp();
            if (!tmpPath.endsWith(File.separatorChar+"")) tmpPath = tmpPath + File.separator;
            filePath = tmpPath + fileName;
            System.out.println("filePath='"+filePath+"'");

            Files.copy(new File(filePath), media.getStreamData());

            filePath = new PDFmodifier(logText).start(filePath);
            System.out.println("Ergbnis-pfad='"+filePath+"'");
            Messagebox.show("File Sucessfully altered. Press \"Show PDF\" to download file.");
            fileuploaded = true;
    }
}

LogText object:

public class LogText {

    public String log;

    public LogText()
    {
        log ="Press the Upload Button to upload any PDF file. PDFmodifier will cover the unwanted area. After processing, the showPDF button will be active and you can save the modified PDF";
    }

    public void setLog(String txt)
    {
        log += "\n"+txt;
    }

    public String getLog()
    {
        return log;
    }       
}

PDFmodifier (I might as well show my core method start()):

protected void printToTextbox(String txt)
    {
        log.setLog("\n"+txt);

    }

public String start(String uploadFile) throws IOException
       {
        setStringVariables(uploadFile);

        System.out.println("Processing inputFile='"+inputFile+"'");
        File f = new File(inputFile);
        if (!f.exists()) {
            System.err.println("inputFile not found)");
            return null;
        }
        long startTime = System.currentTimeMillis();
        //file can be opened and normally processed
        if(accessChecker(inputFile)){  
            coverWithRectangle(inputFile, outputFile) ;
            return outputFile;
        }
        //file needs further work
        else
        {
            printToTextbox("Accessing PDFsam for split...");
            if (createDirectory(outputDir)) {
                long startTimeSplit = System.currentTimeMillis();
                boolean splitOk = splitPDF(inputFile, outputDir);
                long endTimeSplit = System.currentTimeMillis();
                printToTextbox("Time for splitting [ms]: "+(endTimeSplit-startTimeSplit));

                if (!splitOk) {
                    printToTextbox("PDF couldn't be split. Exiting.");
                    return null;
                } 
                else 
                {
                    long startTimeMerge = System.currentTimeMillis();
                    boolean mergeOk = mergePDF(getAllFiles(),tempPDF,tempCSV);
                    long endTimeMerge = System.currentTimeMillis();
                    printToTextbox("Time for merging [ms]: "+(endTimeMerge-startTimeMerge));

                    if (mergeOk) {  
                        coverWithRectangle(tempPDF, outputFile);
                        deleteTrash();
                    } else {
                        printToTextbox("ERROR: merge failed!");
                    }


                }
            }
            writeLog(outputFile);
            long endTime = System.currentTimeMillis();
            printToTextbox("Total time needed [ms]: "+(endTime-startTime));
            printToTextbox("outputFile='"+outputFile+"'");
            return outputFile;
        }

EDIT 2:

Zul:

<textbox width="500px" height="200px"  readonly="true" value="@bind(vm.logText)" multiline ="true"/>
        <timer id="timer" delay="50" repeats="true" onTimer="@command('refreshTextbox')" />

Viewmodel:

String logText;
    LogText log = new LogText();

    @NotifyChange("logText")
    public void setLogText(String txt)
    {
        log.log ="\n"+txt;
        logText = log.log;

    }

    @NotifyChange("logText")
    public String getLogText()
    {
        logText = log.log;
        return logText;
    }

    @Command
    public void refreshTextbox()
    {
        logText = log.log;
        BindUtils.postNotifyChange(null,null,this,"logText");

    }

And the viewmodel passes the Textlog object to a new instance of Pdfmodifier. One deserate attempt at solving this.

You are mixing 2 types, MVVM and MVC. The window and the textbox are used in the MVC way.

You can do this easier :

Create in your VM :

private String textField = "Press the Upload Button to upload any PDF file. PDFmodifier will cover the unwanted area. After processing, the showPDF button will be active and you can save the modified PDF";

and provide getters and setter.

In the viewmodel change to :

<textbox width="500px" height="400px" id="txt" readonly="true" multiline ="true" value=@bind(vm.textField)"/>

Now when want to persist the change to the GUI you can work with

@NotifyChange("textField")

But this only works on setters and commands.

You can do it in other methods in the viewmodel like :

BindUtils.postNotifyChange(null,null,this,"textField");

Edit:

If your textbox need to be updated more then once while the fileupload is busy you need separate thread.

If not, your almost there :

public void setLogText(String text) {
    logText.setLog(text);
}

public String getLogText() {
    return logText.getLog();
}

Removed the notifychanged here, not needed and perfect solution for showing text.

@Command
@NotifyChange({"fileuploaded","logText"})
public void onUploadPDF(
        @ContextParam(ContextType.BIND_CONTEXT) BindContext ctx)
        throws IOException {

    UploadEvent upEvent = null;
    Object objUploadEvent = ctx.getTriggerEvent();
    if (objUploadEvent != null && (objUploadEvent instanceof UploadEvent)) {
        upEvent = (UploadEvent) objUploadEvent;
    }
    if (upEvent != null) {
        Media media = upEvent.getMedia();


        String webAppPath = Executions.getCurrent().getDesktop().getWebApp().getRealPath("/");
        System.out.println("webAppPath='"+webAppPath+"'");


        Calendar now = Calendar.getInstance();
        int year = now.get(Calendar.YEAR);
        int month = now.get(Calendar.MONTH);
        int day = now.get(Calendar.DAY_OF_MONTH);
        int min = now.get(Calendar.MINUTE);
        String originalName = media.getName();

        String fileName = originalName +year+"_"+month+"_"+day+"_"+min+".pdf";
        String tmpPath = PDFmodifier.getTemp();
        if (!tmpPath.endsWith(File.separatorChar+"")) tmpPath = tmpPath + File.separator;
        filePath = tmpPath + fileName;
        System.out.println("filePath='"+filePath+"'");

        Files.copy(new File(filePath), media.getStreamData());

        filePath = new PDFmodifier(logText).start(filePath);
        System.out.println("Ergbnis-pfad='"+filePath+"'");
        Messagebox.show("File Sucessfully altered. Press \"Show PDF\" to download file.");
        fileuploaded = true;
}

Added the notifychange of the logText to this command.

Now also some other improvements :

<button label="Upload" upload="true"
         onUpload="@command('onUploadPDF',upEvent=event)"> </button>

You don't ask the upEvent in the VM so just remove it.

public void onUploadPDF(
        @ContextParam(ContextType.BIND_CONTEXT) BindContext ctx)
        throws IOException {

Could be this :

 public void onUploadPDF(
        @ContextParam(ContextType.TRIGGER_EVENT) UploadEvent evt)
        throws IOException {

Because the only thing you do is getting the trigger event from your bindContext so no need to fetch that object and it removes a lot of boilerplate code in your method.

Edit 2:

Looks like you need a separate thread for the handling. I created a fiddle so you can see how I did it.

But if link ever dies :

@Command
@NotifyChange("timer")
public void longOperation() {
    timer = true;
    Thread r = new Thread(new Runnable() {

        @Override
        public void run() {

            log = "button pressed, initializing now";
            sleep(5000); // this is a private method for calling Thread.sleep
            log = "initialized done, processing now";
            sleep(5000);
            log = "finished";
            timer = false;
        }
    });
    r.start();
}

@Command
@NotifyChange({"log","timer"})
public void refreshTextbox(){
  if (!timer) {
      Clients.showNotification("timer stopped"); 
  }
}

and the zul :

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM