如何在向导页点击Next后取消进度条时停留在当前页?
解决Eclipse向导中取消进度条后停留在原页面的问题
要实现点击Next时显示进度条,取消后停留在当前页面,核心是在向导切换页面的前置逻辑中处理进度任务,并根据取消结果决定是否切换页面。你之前在setVisible里处理进度的方式有问题——因为当setVisible(true)被调用时,页面已经开始切换了,此时取消无法阻止页面跳转。而你尝试的getNextPage方法是正确的方向,只是需要修正细节。
问题分析
- 在
WizardPage.setVisible中执行进度任务:页面已经处于切换流程中,取消后无法回退到原页面。 - 原
getNextPage代码中,进度任务没有正确处理取消后的中断抛出,导致框架无法感知取消操作。
正确实现方案
我们需要在主向导类的getNextPage方法中执行进度任务,利用该方法的返回值控制页面切换:如果任务被取消,返回null(停留在当前页);否则返回下一页。
1. 主向导类修改(核心逻辑)
public class TemplateCreationWizard extends Wizard implements INewWizard, IExecutableExtension { private InterfacePage interfacePage; private InterfaceDetailsPage interfaceDetailsPage; private ErrorPage error; private IConfigurationElement _configurationElement; private SelectedServerNode iServer; public TemplateCreationWizard() { setWindowTitle("Auto Development"); setNeedsProgressMonitor(true); // 必须设置这个,让向导支持进度条 } @Override public void addPages() { super.addPages(); if (iServer.isConnected()) { interfacePage = new InterfacePage(iServer); interfaceDetailsPage = new InterfaceDetailsPage(iServer); addPage(interfacePage); addPage(interfaceDetailsPage); } else { error = new ErrorPage(iServer); addPage(error); } } @Override public boolean performFinish() { return true; } @Override public void init(IWorkbench workbench, IStructuredSelection selection) { // 保留原有初始化逻辑 try { TreeSelection treeSelection = (TreeSelection) selection; TreePath[] treePaths = treeSelection.getPaths(); if (null != treePaths && treePaths.length > 0) { TreePath treePath = treePaths[0]; ISServerNode serverNode = (ISServerNode) treePath.getFirstSegment(); ServerConnection iData = serverNode.getServerConnection(); if (null != iData) { iServer = createSelectedServerNode(iData); } } else { System.out.println("<empty selection>"); } } catch (Exception exception) { exception.printStackTrace(); } } @Override public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { _configurationElement = config; } @Override public IWizardPage getNextPage(final IWizardPage page) { // 只在从InterfacePage切换到下一页时处理进度 if (!(page instanceof InterfacePage)) { return super.getNextPage(page); } try { // 运行进度任务,允许用户取消 getContainer().run(true, true, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask("Fetching details from External System...", 10); try { for (int i = 0; i < 10; i++) { if (monitor.isCanceled()) { // 抛出InterruptedException,让外层捕获取消事件 throw new InterruptedException("Task cancelled by user"); } monitor.worked(1); Thread.sleep(2000); } } finally { monitor.done(); } } }); } catch (InvocationTargetException ex) { // 处理任务执行中的异常,比如外部系统调用失败 ex.printStackTrace(); // 可弹出错误提示,返回null停留在当前页 return null; } catch (InterruptedException ex) { // 用户取消了进度任务,返回null停留在原页面 return null; } // 任务正常完成,返回下一页 return super.getNextPage(page); } }
2. InterfacePage修改(确保canFlipToNextPage不触发进度)
public class InterfacePage extends WizardPage { private SelectedServerNode iServer = null; private Text interfaceId; protected InterfacePage(SelectedServerNode iServer) { super("InterfacePage"); this.iServer = iServer; setTitle("Some title"); setMessage("Some message"); } @Override public void createControl(Composite parent) { // 保留原有UI创建逻辑 Composite page = new Composite(parent, SWT.NONE); setControl(page); setPageComplete(false); GridLayout gridLayout = new GridLayout(2, false); page.setLayout(gridLayout); page.setLayoutData(new GridData(GridData.FILL_BOTH)); Label label = new Label(page, SWT.NONE); label.setText("Interface ID:"); interfaceId = new Text(page, SWT.BORDER); interfaceId.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); interfaceId.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) { boolean hasInterfaceID = !interfaceId.getText().trim().isEmpty(); setMessage(hasInterfaceID ? null : "Please enter an Interface ID", IMessageProvider.ERROR); setPageComplete(hasInterfaceID); } }); } @Override public boolean canFlipToNextPage() { // 只检查页面是否完成,不要调用getNextPage(避免提前触发进度) return isPageComplete(); } public String getInterfaceID() { return interfaceId == null || interfaceId.isDisposed() ? null : interfaceId.getText().trim(); } }
3. InterfaceDetailsPage修改(移除setVisible中的进度逻辑)
因为进度任务已经在切换前完成,这里只需要在页面显示时获取数据即可:
public class InterfaceDetailsPage extends WizardPage { private SelectedServerNode iServer; protected InterfaceDetailsPage(SelectedServerNode iServer) { super("InterfaceDetailsPage"); this.iServer = iServer; setTitle("Interface ID details"); setMessage("Provided Interface ID details is shown below"); } @Override public void createControl(Composite parent) { Composite page = new Composite(parent, SWT.NONE); setControl(page); page.setLayout(new FillLayout()); } @Override public void setVisible(boolean visible) { if (visible) { InterfacePage interfacePage = (InterfacePage) getWizard().getPage("InterfacePage"); String interfaceId = interfacePage.getInterfaceID(); // 这里可以使用进度任务中获取并存储的数据(可在向导类中添加字段存储) } super.setVisible(visible); } }
关键要点说明
setNeedsProgressMonitor(true):必须在向导构造方法中设置,启用进度条支持。getContainer().run(true, true, ...):第一个true表示允许用户取消任务,第二个true表示在UI线程外执行任务,避免阻塞界面。- 取消时抛出
InterruptedException:当用户点击取消按钮,monitor.isCanceled()返回true,此时抛出中断异常,外层捕获后返回null,向导框架就会停留在当前页面。 canFlipToNextPage的实现:只检查页面是否完成,不要调用getNextPage,否则会提前触发进度任务。
内容的提问来源于stack exchange,提问作者Farhan stands with Palestine
相关产品推荐
相关产品推荐

