简介
GenericDialog类是ImageJ的一部分,可用于为脚本和插件制作简单的图形用户界面。它比SciJava的script parameters功能需要更多的工作,但提供了更多的可能性。
Fiji 提供了额外的 PrefService 子类,其中包括额外的 GUI 项目,例如带浏览按钮的文件输入。
与脚本参数一样,使用GenericDialog(其余子类之一)的插件是可录制宏的。
在 Jython(或类似的脚本语言)中
这是 Jython 中的示例。
from ij.gui import GenericDialog
# Create an instance of GenericDialog
gui = GenericDialog("My first GUI")
# Add some gui elements (Ok and Cancel button are present by default)
# Elements are stacked on top of each others by default (unless specified)
gui.addMessage("Some information to display at the top of the gui")
gui.addStringField("Type some input text :", "initial text")
gui.addCheckbox("This is a tickbox->Activate some option", True)
# We can add elements next to each other using the addToSameRow method
gui.addToSameRow() # The next item is appended next to the tick box
gui.addChoice("Choose one option among a list", ["Choice1", "Choice2"], "Choice1") # Choice1 is default here
gui.addNumericField("Some integer", 10, 0) # 0 for no decimal part
# Add a Help button in addition to the default OK/Cancel
gui.addHelp(r"https://imagej.net/scripting/generic-dialog") # clicking the help button will open the provided URL in the default browser
# Show dialog, the rest of the code is not executed before OK or Cancel is clicked
gui.showDialog() # dont forget to actually display the dialog at some point
# If the GUI is closed by clicking OK, then recover the inputs in order of "appearance"
if gui.wasOKed():
inString = gui.getNextString()
inBool = gui.getNextBoolean()
inChoice = gui.getNextChoice() # one could alternatively call the getNextChoiceIndex too
inNum = gui.getNextNumber() # This always return a double (ie might need to cast to int)
###在宏语言中
有2个选项可以用ImageJ宏语言生成GUI。
如果只需要一个或几个参数,第一个选项很方便。
它将为每个请求的参数打开一个专用的输入窗口,即如果有多个参数,则依次显示多个窗口。
someNumber = getNumber("Some number", 0); // 0 is the default here
someString = getString("Some string", "DefaultValue");
可能的输入列表与对话框的第二个选项相同。
使用对话框(第二个选项),将显示一个包含所有参数的输入窗口。这比第一个选项需要更多的编码,但更优雅。
Dialog.create("My inputs");
Dialog.addMessage("Some message to display");
var min = 0;
var max = 10;
var default = 5;
Dialog.addSlider("Some slider", min, max, default);
Dialog.addNumber("Some number", 0);
Dialog.addString("Some string", "DefaultString");
Dialog.addChoice("Type:", newArray("8-bit", "16-bit", "32-bit", "RGB"));
Dialog.addCheckbox("Ramp", true);
// One can add a Help button that opens a webpage
Dialog.addHelp("https://imagej.net/ij/macros/DialogDemo.txt");
// Finally show the GUI, once all parameters have been added
Dialog.show();
// Once the Dialog is OKed the rest of the code is executed
// ie one can recover the values in order of appearance
inNumber1 = Dialog.getNumber(); // Sliders are number too
inNumber2 = Dialog.getNumber();
inString = Dialog.getString();
inChoice = Dialog.getChoice();
inBoolean = Dialog.getCheckbox();
print("Number1:", inNumber1);
print("Number2:", inNumber2);
print(inString);
print("Choice:", inChoice);
print("Do something (1=True, 0=False):", inBoolean);
有关详细信息,请参阅第 Macro functions reference 的“/scripting/generic-dialog”部分。
图片和文件输入
默认情况下,脚本和插件处理最后选择的图像。
然而有时需要指定不同的图像或文件作为输入。
子类GenericDialogPlus这种情况提供了一些方法,而上面显示的所有方法都是从 GenericDialog 类继承的。
from fiji.util.gui import GenericDialogPlus
# Create an instance of GenericDialogPlus
gui = GenericDialogPlus("an enhanced GenericDialog")
# Add possibility to choose some images already opened in Fiji
gui.addImageChoice("Image1","Some description for image1")
gui.addImageChoice("Image2","Some description for image2")
# The GenericDialogPlus also allows to select files, folder or both using a browse button
gui.addFileField("Some_file path", "DefaultFilePath")
gui.addDirectoryField("Some_folder path", "DefaultFolderPath")
gui.addDirectoryOrFileField("Some_Path", "DefaultPath")
gui.showDialog()
# Recover the inputs in order of "appearance"
if gui.wasOKed():
image1 = gui.getNextImage() # This method directly returns the ImagePlus object
image2 = gui.getNextImage()
# Path are recovered as string
filePath = gui.getNextString()
folderPath = gui.getNextString()
somePath = gui.getNextString()
宏录制
就像脚本参数一样,使用 GenericDialog 类的插件是可宏记录的。
需要注意的每一件重要的事情是记录命令中变量的名称。该名称实际上是使用项目标签的字符串的第一个单词,仅包含小写字母。
大多数情况下,用一个词来理解一个参数不太容易理解。要在录制的命令中包含标签的下一个单词,补足空格替换为下划线,如上面的some_file所示。
例如,之前在 Fiji.app/scripts/Plugins/Test 中保存为 GUI_.py 的代码会生成以下记录命令:
run("GUI ", "image1=MyImage1.tif image2=MyImage2.tif some_file=DefaultFilePath some_folder=DefaultFolderPath some_path=DefaultPath");
使用 PrefService 调用以前的边境
在接下来运行给定插件时调用前面输入的参数很方便。对于脚本参数(不用以不同方式指定),这种情况会自动发生,但对于 GenericDialog 类则不会。
幸运的是,仍然可以使用 PrefService 进行工作。
服务是一些ImageJ2/SciJava功能,可以将其视为运行时的某种包导入。它们在原始ImageJ中不可用,因此在ImageJ中调用参数的另一种方法是使用临时文件来存储先前输入的参数。
这是GenericDialogPlus的链接。
下面是如何使用它的 Jython 示例。
#@ PrefService prefs
from fiji.util.gui import GenericDialogPlus
# Create GUI
gui = GenericDialogPlus("Some GUI")
gui.addImageChoice("Image", prefs.get(None, "Image", "DefaultImage") )
gui.addCheckbox("Activate some option", prefs.getInt(None, "doOption", False) ) # in theory we should use the getBoolean method but it does not work for Jython, the wrong method signature is matched
gui.addStringField("Some_string", prefs.get(None, "someString", "initial"))
gui.addChoice("Some_choice", ["Choice1","Choice2"], prefs.get(None, "someChoice", "DefaultChoice"))
gui.addNumericField("Some_integer", prefs.getInt(None, "n", 1), 0)
gui.addNumericField("Some_float", prefs.getFloat(None, "number", 0.5), 2)
gui.showDialog()
if gui.wasOKed():
image = gui.getNextImage()
doOption = gui.getNextBoolean()
someString = gui.getNextString()
someChoice = gui.getNextChoice()
n = int(gui.getNextNumber()) # cast to int : getNextNumber always return a double
number = gui.getNextNumber()
# Save in memory using PrefService
prefs.put(None, "image", image.getTitle())
prefs.put(None, "doOption", doOption)
prefs.put(None, "someString", someString)
prefs.put(None, "someChoice", someChoice )
prefs.put(None, "n", n)
prefs.put(None, "number", number)
第一步是“导入”PrefService并指定一个名称,此处为prefs。
现在有两种方法分别从 PrefService 中恢复和存储一些参数值,即get和put。
让我们从get开始。该方法是针对不同的数据类型getInt、getFloat、getBoolean定义的。字符串例外,没有getString,只有get。
另外,在 Jython 中,getBoolean 方法未映射正确的 Java 签名,因此请使用 getInt 代替,如上所示。
get方法有3个参数:
- 要关联参数持久性的插件类。将其保留为“无”(或在其他语言中为“空”)并使用默认值。
2.从内存/首选项中调用的参数名称,它应该与
put该参数使用的名称的方法相同。 3.如果内存中不存在具有该运行名称的参数(即第一个脚本或重置首选项),则使用默认值。
方法put甚至更简单,因为只有一个方法也接受3个参数:
1.就像get一样,一个可选的Plugin类
- 用于在内存/首选项中存储参数值的名称,与
get用于恢复先前输入的值的名称相同。 - 要使用参数 2 中的名称存储在内存中的值。如果该参数已存在于内存中,则该值将更新为新提供的值。
因此,在上面的脚本中,GenericDialog 字段的默认值被初始化为内存中可用的值,或者如果内存中缺少某些默认值。
GUI确定后,内存中的值将使用put方法用新输入的值进行更新。
自定义按钮
使用斐济提供的GenericDialogPlus,可以向添加GUI自定义按钮和相关操作。
为此,我们必须从 java.awt.event 导入 ActionListener 接口。
然后,我们创建一个实现这个接口的类,其中包含一个名为 actionPerformed 的方法,只要用户链接到这个事件监听类的项目(如按钮),就会交互调用该方法。
在下面的 jython 示例中,我们定义了 2 个按钮 A 和 B,它们都与名为 ButtonClic 的同一事件处理类关联。
如果单击任意按钮,则调用 ButtonClic 的 actionPerformed 方法。但是事件的来源不同(按钮 A 或 B),因此我们可以为端点情况定义不同的命令来执行。
对于更复杂的情况,还可以创建不同的事件处理类来分配给不同的GUI项目集。
from fiji.util.gui import GenericDialogPlus
from java.awt.event import ActionListener
class ButtonClic(ActionListener):
"""Class which unique function is to handle the button clics"""
def actionPerformed(self, event): # self (or this in Java) to state that the method will be associated to the class instances
# Check from where comes the event
source = event.getSource() # returns the Button object
print source
# Do an action depending on the button clicked
if source.label == "A":
print "You clicked A\n"
elif source.label == "B":
print "You clicked B\n"
gui = GenericDialogPlus("GUI with custom buttons")
clicRecorder = ButtonClic() # Create an instance of the ButtonClic class
gui.addButton("A", clicRecorder) # Associate the buttons to an instance of the ButtonClic class
gui.addButton("B", clicRecorder)
gui.showDialog()