📄 menus.java
字号:
if (System.getProperty("mrj.version") != null) commandKey = "meta "; } catch (SecurityException e) { } } return KeyStroke.getKeyStroke(commandKey + description); } /** * A convenience method that breaks up a string into tokens, where * the tokens are substrings seprated by specified delimiters. * For example, explode("ab,cde,f,ghij", ",") produces an array * of the four substrings "ab" "cde" "f" "ghi". */ private String[] explode(String str, String separators) { StringTokenizer tokenizer = new StringTokenizer(str, separators); int ct = tokenizer.countTokens(); String[] tokens = new String[ct]; for (int i = 0; i < ct; i++) tokens[i] = tokenizer.nextToken(); return tokens; } /** * Enables/Disables some menu items, based on the status of the MandelbrotDisplay. * This method is called by a listener that listens for property change events * from the display. * @param status is probably either "working" or "ready". Working means that * a computation is in progress in the display. The save commands, the * entire MaxIterations menu,and the Set Limits and Set Image Size commands * are disabled during computations. There is a small posility that the * program will not have enough memory to create the image; Set Image Size * would be enabled in this case because changing the image size might fix * the problem. */ private void newDisplayStatus(Object status) { boolean ready = status.equals(MandelbrotDisplay.STATUS_READY); boolean outofmem = status.equals(MandelbrotDisplay.STATUS_OUT_OF_MEMORY); saveImage.setEnabled(ready); saveParams.setEnabled(ready); openParams.setEnabled(ready); setLimits.setEnabled(ready); setImageSize.setEnabled(ready || outofmem); maxIterationsManager.setEnabled(ready || outofmem); } /** * A little utility method that makes strings out of the xy-limits on the display, * where the lengths of the strings is adjusted depending on the distance between * xmax and xmin. The idea is to try to avoid more digits after the decimal * points than makes sense. If it succeeds the coordinates that are shown for xmin * and xmax should differ only in their last four or five digits and the same should * also be true for ymin and ymax. * @return An array of 4 strings representing the values of xmin, xmax, ymin, ymax. */ private String[] makeScaledLimitStrings() { double xmin = owner.getDisplay().getXmin(); double xmax = owner.getDisplay().getXmax(); double ymin = owner.getDisplay().getYmin(); double ymax = owner.getDisplay().getYmax(); double diff = xmax - xmin; if (diff == 0) return new String[] { ""+xmin, ""+xmax, ""+ymin, ""+ymax }; int scale = 4; if (diff > 0) { while (diff < 1) { scale++; diff *= 10; } } String fmt = "%1." + scale + "f"; String[] str = new String[4]; str[0] = String.format(fmt,xmin); str[1] = String.format(fmt,xmax); str[2] = String.format(fmt,ymin); str[3] = String.format(fmt,ymax); return str; } // ------ The rest of the file defines Actions and nested classes that implement commands ------- private Action saveParams = new AbstractAction(I18n.tr("command.save")) { // Saves current setting in an XML format file. public void actionPerformed(ActionEvent evt) { if (fileDialog == null) fileDialog = new JFileChooser(); File selectedFile = new File(I18n.tr("files.saveparams.defaultFileName")); fileDialog.setSelectedFile(selectedFile); fileDialog.setDialogTitle(I18n.tr("files.saveparams.title")); int option = fileDialog.showSaveDialog(owner); if (option != JFileChooser.APPROVE_OPTION) return; // User canceled or clicked the dialog's close box. selectedFile = fileDialog.getSelectedFile(); if (selectedFile.exists()) { // Ask the user whether to replace the file. int response = JOptionPane.showConfirmDialog( owner, I18n.tr("files.fileexists",selectedFile.getName()), I18n.tr("files.confirmsave.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE ); if (response == JOptionPane.NO_OPTION) return; // User does not want to replace the file. } PrintWriter out; try { FileOutputStream stream = new FileOutputStream(selectedFile); out = new PrintWriter( stream ); } catch (Exception e) { JOptionPane.showMessageDialog(owner, I18n.tr("files.saveparams.error.cannotOpen", selectedFile.getName(), e.toString())); return; } try { out.print(currentSettingsAsXML()); out.close(); } catch (Exception e) { JOptionPane.showMessageDialog(owner, I18n.tr("files.saveparams.error.cannotWrite", selectedFile.getName(), e.toString())); } } }; private Action openParams = new AbstractAction(I18n.tr("command.open")) { // Loads settings from an XML file of the form that is saved by the Save Params command. public void actionPerformed(ActionEvent evt) { if (fileDialog == null) fileDialog = new JFileChooser(); fileDialog.setDialogTitle(I18n.tr("files.openparams.title")); fileDialog.setSelectedFile(null); // No file is initially selected. int option = fileDialog.showOpenDialog(owner); if (option != JFileChooser.APPROVE_OPTION) return; // User canceled or clicked the dialog's close box. File selectedFile = fileDialog.getSelectedFile(); Document xmldoc; try { DocumentBuilder docReader = DocumentBuilderFactory.newInstance().newDocumentBuilder(); xmldoc = docReader.parse(selectedFile); } catch (Exception e) { JOptionPane.showMessageDialog(owner, I18n.tr("files.openparams.error.notXML", selectedFile.getName(), e.toString())); return; } try { retrieveSettingsFromXML(xmldoc); } catch (Exception e) { JOptionPane.showMessageDialog(owner, I18n.tr("files.openparams.error.notParamsFile", selectedFile.getName(), e.getMessage())); } } }; private Action saveImage = new AbstractAction(I18n.tr("command.saveImage")) { // Saves the current image as a file in PNG format. public void actionPerformed(ActionEvent evt) { if (fileDialog == null) fileDialog = new JFileChooser(); BufferedImage image; // A copy of the sketch will be drawn here. image = owner.getDisplay().getImage(); if (image == null) { JOptionPane.showMessageDialog(owner,I18n.tr("files.saveimage.noImage")); return; } fileDialog.setSelectedFile(new File(I18n.tr("files.saveimage.defaultFileName"))); fileDialog.setDialogTitle(I18n.tr("files.saveimage.title")); int option = fileDialog.showSaveDialog(owner); if (option != JFileChooser.APPROVE_OPTION) return; // User canceled or clicked the dialog's close box. File selectedFile = fileDialog.getSelectedFile(); if (selectedFile.exists()) { // Ask the user whether to replace the file. int response = JOptionPane.showConfirmDialog( owner, I18n.tr("files.fileexists",selectedFile.getName()), I18n.tr("files.confirmsave.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE ); if (response == JOptionPane.NO_OPTION) return; // User does not want to replace the file. } try { boolean hasPNG = ImageIO.write(image,"PNG",selectedFile); if ( ! hasPNG ) throw new Exception(I18n.tr("files.saveimage.noPNG")); } catch (Exception e) { JOptionPane.showMessageDialog(owner, I18n.tr("files.saveimage.cantwrite", selectedFile.getName(), e.toString())); } } }; private Action close = new AbstractAction(I18n.tr("command.close")) { // Implement the Close or Quit command by disposing the frame. public void actionPerformed(ActionEvent evt) { frame.dispose(); } }; private Action defaultLimits = new AbstractAction(I18n.tr("command.defaultLimits")) { // Restores the default xy-limits on the MandelbrotDisplay. public void actionPerformed(ActionEvent evt) { owner.getDisplay().setLimits(-2.5,1.1,-1.35,1.35); } }; private Action allDefaults = new AbstractAction(I18n.tr("command.restoreAllDefaults")) { // Restores default settings for limtis, palette type, palette lenght, and maxIterations. public void actionPerformed(ActionEvent evt) { owner.getDisplay().setLimits(-2.5,1.1,-1.35,1.35); paletteManager.setDefault(); paletteLengthManager.setDefault(); maxIterationsManager.setDefault(); } }; private Action undoChangeOfLimits = new AbstractAction(I18n.tr("command.undoChangeOfLimits")) { // Restores previous xy-limits on MandelbrotPanel. The previous limits are // obtained from a property change event that is emitted by the display whenever // the limits change. The listener stores the old limits in the previousLimits // instance variable. public void actionPerformed(ActionEvent evt) { if (previousLimits != null) owner.getDisplay().setLimits(previousLimits[0],previousLimits[1], previousLimits[2],previousLimits[3]); } }; private Action showLimits = new AbstractAction(I18n.tr("command.showLimits")) { // Puts up a message dialog that contains the current range of xy-values // that is shown in the MandelbrotDisplay. public void actionPerformed(ActionEvent evt) { String[] limits = makeScaledLimitStrings(); JOptionPane.showMessageDialog(owner, I18n.tr("dialog.showLimits",limits[0],limits[1],limits[2],limits[3])); } }; private Action setImageSize = new AbstractAction(I18n.tr("command.enterImageSize")) { // Puts up a dialog box of type SetImageSizeDialog (another class defined in // this package). The dialog box lets the user enter new values for the // width and height of the image. If the user does not cancel, then the // new width and height are applied to the image. The frame changes size // to match the new size. However, the size is not allowed to grow bigger // than will fit on the screen. public void actionPerformed(ActionEvent evt) { Dimension oldSize = owner.getDisplay().getSize(); Dimension newSize = SetImageSizeDialog.showDialog(frame, oldSize); if (newSize == null) return; owner.getDisplay().setPreferredSize(newSize); // Change the size that the display wants to be. frame.pack(); // Sizes the window to accomodate the preferred size. frame.adjustToScreenIfNecessary(); // Make sure frame fits on the screen. } }; private Action setLimits= new AbstractAction(I18n.tr("command.enterLimits")) { // Puts up a dialog box of type SetLimitsDialog (another class defined in // this package. The dialog box lets the user enter new values for xmin, // xmax, ymin, and ymax (the limits of the range of xy-values shown in the // MandelbrotDisplay). If the user does not cancel, the new limits are // applied to the display. public void actionPerformed(ActionEvent evt) { String[] limits = makeScaledLimitStrings(); double[] newLimits = SetLimitsDialog.showDialog(frame, limits); if (newLimits != null) owner.getDisplay().setLimits(newLimits[0],newLimits[1],newLimits[2],newLimits[3]); } }; /** * Defines the object that manages the Palette menu. */ private class PaletteManager implements ActionListener{ JRadioButtonMenuItem[] items; // Array ontains all the items that are in the Palette menu. int selectedItem = 0; // Index in the items array of the item that is currently selected. private String[] valueStrings = {"Spectrum","PaleSpectrum","Grayscale","ReverseGrayscale", "BlackToRed","RedToCyan","OrangeToBlue"}; // Names for commands in XML settings file. PaletteManager() { // Constructor creates the items and adds them to a ButtonGroup. Also this // object adds itself as an ActionListener to each item so it can carry out // the command when the user selects one of the items. items = new JRadioButtonMenuItem[8]; items[0] = new JRadioButtonMenuItem(I18n.tr("command.palette.spectrum")); items[1] = new JRadioButtonMenuItem(I18n.tr("command.palette.paleSpectrum")); items[2] = new JRadioButtonMenuItem(I18n.tr("command.palette.grayscale")); items[3] = new JRadioButtonMenuItem(I18n.tr("command.palette.reverseGrayscale")); items[4] = new JRadioButtonMenuItem(I18n.tr("command.palette.gradientBlackToRed")); items[5] = new JRadioButtonMenuItem(I18n.tr("command.palette.gradientRedToCyan")); items[6] = new JRadioButtonMenuItem(I18n.tr("command.palette.gradientOrangeToBlue"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -